Spring, Infinispan and JBoss 7 integration - spring

I'm trying to use JBoss 7 Infinispan cache as a communication form (something more later) of two war-deployed spring-based apps. I'm having a problem with accessing the JBoss managed cache managers.
When I use
DefaultCacheManager cacheManager = new DefaultCacheManager();
cache = cacheManager.getCache();
on each of two applications, I get two separate caches. Is there any way to access the cache created by JBoss server without using the #ManagedBean annotation and Java EE standard at all ?
It's done. Thanks to Kazaag, I used JNDI.
JndiTemplate jndiTemplate = new JndiTemplate();
jndiTemplate.lookup("java:jboss/infinispan/container/cluster");
I had the well known problem with a DefaultEmbeddedCacheManager Class Cast Exception. I used reflections.
Map<Object, Object> cache;
JndiTemplate jndiTemplate = new JndiTemplate();
Object cacheManager;
try {
cacheManager = (Object) jndiTemplate.lookup("java:jboss/infinispan/container/cluster");
Method method = cacheManager.getClass().getMethod("getCache");
cache = (Map) method.invoke(cacheManager);
} catch (Exception e) {
e.printStackTrace();
return;
}
Moreover I had to mark container as started eagerly.
<cache-container name="cluster" aliases="ha-partition" default-cache="default">
<transport lock-timeout="60000"/>
<replicated-cache name="default" mode="SYNC" start="EAGER" batching="true">
<locking isolation="REPEATABLE_READ"/>
</replicated-cache>
</cache-container>
The cache is replicated although different class loaders.

If each application are using there own cache manager, they will have separated cached.
You can retrieve the cache container managed by the application server via JNDI support of Spring (The JNDI name is java:jboss/infinispan/my-container-name). So Spring will be responsible to make sure every part are using the same container.
I am not 100% sure you will get the same cache, it may return you a application specific cache (the 2 applications data object are in fact coming from different class loader).
Embedded cache is probably not mean for inter application communication. You probably need to use the client/server paradigm.

A bit late in the day but the information on accessing the infinispance cache store via JNDI can be found here
With that a JNDI lookup I get the CacheContainer
<jee:jndi-lookup id="cache1"
jndi-name="java:jboss/infinispan/container/jbossas7-quickstart"
cache="true" resource-ref="false" lookup-on-startup="true" />
which I inject via a setter
public void setContainer(CacheContainer container) {
this.container = container;
}
and now I have access to the cachestore. Note the suggestions here
#Resource(lookup="java:jboss/infinispan/container/my-container-name")
#Resource(lookup="java:jboss/infinispan/cache/my-container-name/my-cache-name")
do not work within my Spring Bean

Related

Redis cache metrics with Prometheus(Spring boot)

I am using RedisTemplate for caching purpose in my spring boot service. Now I want to check cache hit/cache miss through end point actuator/prometheus. But can not see cache hit/cache miss for the cache.
The code I have written is something like below
#EnableCaching
#Configuration
public class CachingConfiguration {
#Bean
public RedisTemplate<String, SomeData> redisTemplate(LettuceConnectionFactory connectionFactory, ObjectMapper objectMapper)
{
RedisTemplate<String, SomeData> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
var valueSerializer = new Jackson2JsonRedisSerializer<SomeData>(SomeData.class);
valueSerializer.setObjectMapper(objectMapper);
template.setValueSerializer(valueSerializer);
return template;
}
}
Now am doing like below to get and save into cache
to get:-
redisTemplate.opsForValue().get(key);
And to save:-
redisTemplate.opsForValue().set(key, obj, some_time_limit);
My cache is working properly, am getting able to save into cache and getting proper data.
But I don't see cache hit/miss related data inside actuator/prometheus.
In my application.yml file I have added below
cache:
redis:
enable-statistics: 'true'
I would assume that in order for Springboot Cache Monitoring to apply (Including Hits/Misses), you would need to depend on AutoConfiguration.
In your case you are creating the RedisTemplate yourself, and probably enable-statistics is not actually applied.
Can you remove the redistemplate creation and use #Cacheable annotation abstraction? That way any supported Cache library will work out of the box, without you having to create #Bean and manually configuring it.
Otherwise, generally if you wanted to enable statistics on a cache manager manually, you will need to call RedisCacheManager.RedisCacheManagerBuilder enableStatistics():
https://docs.spring.io/spring-data/redis/docs/current/api/org/springframework/data/redis/cache/RedisCacheManager.RedisCacheManagerBuilder.html
For Reference:
Auto-configuration enables the instrumentation of all available Cache
instances on startup, with metrics prefixed with cache. Cache
instrumentation is standardized for a basic set of metrics.
Additional, cache-specific metrics are also available.
Metrics are tagged by the name of the cache and by the name of the
CacheManager, which is derived from the bean name.
Only caches that are configured on startup are bound to the registry. For caches not
defined in the cache’s configuration, such as caches created on the
fly or programmatically after the startup phase, an explicit
registration is required. A CacheMetricsRegistrar bean is made
available to make that process easier.
I had exactly the same question and spent a good number of hours trying to figure out how to enable cache metrics for my manually created RedisTemplate instance.
What I eventually realised is that it's only RedisCache class which collects and exposes CacheStatistics through getStatistics() method. As far as I can see there is nothing like that for RedisTemplate, which means you either need to switch to using RedisCache through RedisCacheManager and #Cacheable annotation or implement your custom metrics collection.

Can I use the JCache API for distributed caches in Apache Ignite?

I would like to configure a distributed cache with Apache Ignite using the JCache API (JSR107, javax.cache). Is this possible?
The examples I have found either create a local cache with the JCache API or create a distributed cache (or datagrid) using the Apache Ignite API.
JCache allows to provide provider-specific configuration when creating a cache. I.e., you can do this:
// Get or create a cache manager.
CacheManager cacheMgr = Caching.getCachingProvider().getCacheManager();
// This is an Ignite configuration object (org.apache.ignite.configuration.CacheConfiguration).
CacheConfiguration<Integer, String> cfg = new CacheConfiguration<>();
// Specify cache mode and/or any other Ignite-specific configuration properties.
cfg.setCacheMode(CacheMode.PARTITIONED);
// Create a cache based on configuration create above.
Cache<Integer, String> cache = cacheMgr.createCache("a", cfg);
Also note that partitioned mode is actually the default one in Ignite, so you are not required to specify it explicitly.
UPD. In addition, CachingProvider.getCacheManager(..) method accepts a provider-specific URI that in case of Ignite should point to XML configuration file. Discovery, communication and other parameters can be provided there.
Please note that JCache specification does not specify all the configurations that apply to individual cache providers in terms of configuring via CacheManager for creating a Grid. The requirement for creating a CacheManager is standard but not everything relevant to how the manager itself is configured.
Following code will demonstrate how to create a grid using Apache Ignite in SpringBoot
#Bean
#SuppressWarnings("unchecked")
public org.apache.ignite.cache.spring.SpringCacheManager cacheManager() {
IgniteConfiguration igniteConfiguration = new IgniteConfiguration();
igniteConfiguration.setGridName("petclinic-ignite-grid");
//igniteConfiguration.setClassLoader(dynamicClassLoaderWrapper());
igniteConfiguration.setCacheConfiguration(this.createDefaultCache("petclinic"),
this.createDefaultCache("org.hibernate.cache.spi.UpdateTimestampsCache"),
this.createDefaultCache("org.hibernate.cache.internal.StandardQueryCache"));
SpringCacheManager springCacheManager = new SpringCacheManager();
springCacheManager.setConfiguration(igniteConfiguration);
springCacheManager.setDynamicCacheConfiguration(this.createDefaultCache(null));
return springCacheManager;
}
private org.apache.ignite.configuration.CacheConfiguration createDefaultCache(String name) {
org.apache.ignite.configuration.CacheConfiguration cacheConfiguration = new org.apache.ignite.configuration.CacheConfiguration();
cacheConfiguration.setName(name);
cacheConfiguration.setCacheMode(CacheMode.PARTITIONED);
cacheConfiguration.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL);
cacheConfiguration.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC);
cacheConfiguration.setStatisticsEnabled(true);
cacheConfiguration.setEvictSynchronized(true);
return cacheConfiguration;
}
}
If we were to create another instance of this service and have it register to the same grid as igniteConfiguration.setGridName("petclinic-ignite-grid"), an IMDG will be created. Please note that the 2 service instances with this version of partitioned, embedded distributed cache should be able to talk to each other via required PORTS. Please refer to Apache Ignite - Data Grid for more details.
Hope this helps.

Need inputs for Database Tuning using Spring and Dbcp Connection pool

I am using Spring in my project and instantiating dataSource as below.
#Bean(destroyMethod="close")
public DataSource restDataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getProperty("hibernate.connection.driver_class"));
dataSource.setUrl(env.getProperty("hibernate.connection.url"));
dataSource.setUsername(env.getProperty("hibernate.connection.username"));
dataSource.setPassword(env.getProperty("hibernate.connection.password"));
dataSource.setInitialSize(env.getRequiredProperty("hibernate.dbcp.initialSize", Integer.class));
dataSource.setMaxActive(env.getRequiredProperty("hibernate.dbcp.maxActive", Integer.class));
dataSource.setMaxIdle(env.getRequiredProperty("hibernate.dbcp.maxIdle", Integer.class));
dataSource.setMinIdle(env.getRequiredProperty("hibernate.dbcp.minIdle", Integer.class));
return dataSource;
}
Below is my properties file.
hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
hibernate.connection.driver_class=oracle.jdbc.driver.OracleDriver
hibernate.connection.username=<>
hibernate.connection.password=<>
hibernate.connection.url=jdbc:oracle:thin:#<Host>:1521:<SID>
hibernate.show_sql=true
hibernate.cache.use_query_cache=true
cache.provider_class=org.hibernate.cache.EhCacheProvider
hibernate.cache.use_second_level_cache=true
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
net.sf.ehcache.configurationResourceName=ehcache.xml
**hibernate.dbcp.initialSize=10
hibernate.dbcp.maxActive=100
hibernate.dbcp.maxIdle=30
hibernate.dbcp.minIdle=10**
Please suggest :-
Any changes in the properties marked in Bold(initialSize,maxActive,maxidle,minIdle). My application will be concurrently used by around 100 users and total users are around 3000.
I am using Tomcat Server to deploy my application.Should I be using JNDI for connections instead of directly specify connection properties? Is above way of using connections good for a production System?
Instead of Commons DBCP I would suggest using HikariCP (I'm having very good experiences with that lately or if you are already on tomcat use Tomcat JDBC instead.
There is a lot written on poolsizing (see here for a nice explanation and here for a short video from Oracle). In short large poolsizes don't work and probably will make performance worse.
A rule of thumb/formula (also in the article mentioned) is to use
connections = ((core_count * 2) + effective_spindle_count)
Where core_count is the number of (actual) cores in your server and effective_spindle_count the number of disks you have. If you have server with a large disk and 4 cores it would lead to a connection pool of size 9. This should be able to handle what you need, adding more will only add overhead of monitoring, thread switching etc.

Axis2(aar) + spring, without a servletContext

Greetings dear Stackoverflow users, I have been lately in lots of pain with one specific problem with axis2 web services with Spring framework. I have read lots of different guides and read different forums but found people with the same problems but with no solutions. Basically ended up holding the monitor with both of my hands and yelling "What did you find out BudapestHacker938?". Anyway my axis2 web service class needs Spring beans and therefore they are autowired inside the web service class. Everything works so well inside the jetty server where I have servletContext. Just define needed listeners in web.xml and it works. Such a bliss. But unfortunately all good things come to the end in some point, for me, the devil is CICS environment inside of mainframe. There is no servletcontext like in Jetty/Tomcat, luckily it still has axis2 support. So according to the different user-guides I decided to archive my web-service into .aar and added it under the services folder. Axis2 folder structure is the following:
repository/
modules
services
When I am building this .aar archive then I am also generating my own wsdl, not using axis2 inbuilt wsdl generator which according to services.xml generates the services out of the given class (when I am running the axis2server, not using because doesn't like JAX-WS annotations as far as I know). To initialize Spring framework, I needed to write little SpringInit class which initializes Spring beans. Unfortunately it also for some reason initializes my web-service class according to its annotations and then occupies the main port(suspect that SpringInit intializes by its own the web service class since it is also defined as a Spring bean and SpringInit extends Axis2 class ServiceLifeCycle) and I get JVM BIND exception where it is stating that address is already in use. I would like to have the service built up according to the wsdl which is stored inside of the WSDL rather than generate new one, because I have various environments: 1) local machine - Jetty 2) mainframe. Anyway I give an insight to my services.xml:
<service name="Absence" class="org.services.SpringInit">
<description>
random description
</description>
<parameter name="ServiceTCCL">composite</parameter>
<parameter name="useOriginalwsdl" locked="false">true</parameter>
<parameter name="ServiceObjectSupplier">org.apache.axis2.extensions.spring.receivers.SpringAppContextAwareObjectSupplier</parameter>
<parameter name="ServiceClass">org.services.Absence</parameter>
<parameter name="SpringBeanName">absence</parameter>
<parameter name="SpringContextLocation">META-INF/applicationContextAar.xml</parameter>
</service>
Spring applicationContextAar.xml, little bit refactored it for dear Stack community:
<beans>
<bean id="applicationContext" class="org.apache.axis2.extensions.spring.receivers.ApplicationContextHolder" />
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:tcp://localhost/~/devDb" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="absence" class="org.services.Absence"></bean>
<bean id="jtemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="ds"></constructor-arg>
</bean>
<bean id="datasetFactory" class="org.vsam.DataSetFactory"></bean>
<bean id="dataManagerFactory" class="org.datamanager.DataManagerFactory"></bean>
<bean id="absenceFactory" class="org.services.AbsenceFactory"></bean>
<bean id="h2Database" class="org.dataset.H2Database"><constructor-arg ref="jtemplate"></constructor-arg>
</bean>
<bean class="org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter"></bean>
</beans>
My SpringInit class looks something like that:
public class SpringInit implements ServiceLifeCycle {
public void startUp(ConfigurationContext ignore, AxisService service) {
try {
ClassLoader classLoader = service.getClassLoader();
ClassPathXmlApplicationContext appCtx = new
ClassPathXmlApplicationContext(new String[] {"applicationContextAar.xml"}, false);
appCtx.setClassLoader(classLoader);
appCtx.refresh();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void shutDown(ConfigurationContext ctxIgnore, AxisService ignore) {}
}
Now we are moving to org.services.Absence.class, it is an ordinary JAX-WS web-service class with following header (contains JAX-WS annotations):
#WebService(name = "AbsenceService", serviceName = "Absence", portName = "Absence",
targetNamespace = "http://www.something.org/Absence")
public class Absence extends ServiceHandlerBase {
#Autowired
private AbsenceFactory absenceFactory;
#Autowired
private DataManagerFactory dataManagerFactory;
#Autowired
private DataSetFactory dataSetFactory;
...
}
Containing methods like that:
#WebMethod
#WebResult(name = "AbsenceResponse")
public SearchAbsenceRecordsResponse invokeSearchAbsenceRecords(
#WebParam ServiceRequest request,
#WebParam SearchAbsenceRecordsRequest absenceRequest) {...}
One alternative is to add "servicejars" folder into "repository" folder and populate it with absence.jar which has all its dependencies in the sub-folder "lib". Axis2 then automatically runs absense.jar since it has JAX-WS annotation. But in there when I call out the web-service for example with SOAP-UI, it doesn't have Spring initialized since I don't know how to initialize Spring in that solution. Maybe someone has any expertise about that.
TL;DR
How do I get my Spring beans initialized in manner that it doesn't start the services in the web service class according to the annotation and would rather build up services according to the wsdl?
You are welcome to ask questions.
How I initialized Spring inside of CICS without servletcontext?
Basically until today the SOAP web services have been published through servicejars which means into the repository folder has been created "servicejars" folder which cointains jars which have been built from the web service classes. "servicejars" subfolder "lib" contains all the dependencies which web service jars need.
At first I learnt from the web(Axis2 homepage, there was an instruction about axis2 and spring integration) for initializing Spring in Axis2 web service I need .aar archive and SpringInit service defined in services.xml. But this brought lots of problems since having old architecture built on jaxws and jaxb there was a huge need for refactoring the web services layer. Axis2 tolerated jaxws annotations only with "servicejars" solution. Initing Spring with SpringInit class meant that it initializes Spring beans according to the application context. This now runs web service bean(absence bean in previous post) as a separate web service and occupied 8080 port, when time came for the web service creation according to WSDL I got an error "JVM bind address already in use". So after that I figured I should create the service according to the absence Spring bean and let axis2server generate the WSDL, but axis2server didn't like jaxws annotation and even without them it didn't like my jaxb DTOs.
Therefore, I decided to drop .aar architecture and went back to the "servicejars" architecture. Unfortunately in there I didn't have services.xml support, to define the potential SpringInit service.
Since jaxws web services are the only entrypoints then I decided do the following (initialize Spring beans in the web service layer):
#WebService(name = "AbsenceService", serviceName = "Absence", portName = "Absence",
targetNamespace = "http://www.something.org/Absence")
public class Absence extends ServiceHandlerBase {
private static AbsenceFactory absenceFactory;
private static DataManagerFactory dataManagerFactory;
private static DataSetFactory dataSetFactory;
static {
try {
ClassPathXmlApplicationContext appCtx = new
ClassPathXmlApplicationContext(new String[] {"applicationContext.xml"}, false);
appCtx.refresh();
absenceFactory = (AbsenceFactory) appCtx.getBean("absenceFactory", AbsenceFactory.class);
dataManagerFactory = (DataManagerFactory) appCtx.getBean("dataManagerFactory", DataManagerFactory.class);
dataSetFactory = (DataSetFactory) appCtx.getBean("datasetFactory", DataSetFactory.class);
} catch (Exception ex) {
ex.printStackTrace();
}
}
...
}
As you can see when this class is being called out, it will initialize applicationcontext and since it is static, all the spring beans will stay in the memory until the end(when service is closed). In other classes autowiring works perfectly, no need to get these beans wired manually.
In the end, I didn't find the possiblity to initialize Spring in the matter as I hoped through .aar architecture, but I found a work around with the guidance of a senior programmer. Huge thanks to him! And now the possible solution is visible for all StackOverFlow users.
EDIT:
In applicationContext.xml I had:
<bean class="org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter"/>
Tries to create web services with Absence.class(absence bean). Removed it since I can in local machine as well use pre-generated WSDL with Jetty (originally was used for creating web service in the local machine, like I said before, I have local development environment and it should be also compatible with CICS, now it is solved).

Using Spring to Access an EJB Across Clusters in WebSphere using Grails

I have spent the last few days attempting to integrate a Grails (version 1.3.2) application with an EJB 2.1 application that is deployed on WebSphere 6.1. Once our grails apps are in production, they will be deployed to WebSphere as well. The EJB 2.1 application is widely used across our company and, in anything except a local development environment, is deployed to its own cluster. The way we handle this in our existing Java EE applications (all of which are non-Spring, non-Grails) is to bind a CORBA CosNaming Naming Context within each of our other clusters that can then be used to obtain references to our shared EJB 2.1 application. So, up to this point, if one of our application needed to interact with this application, they would do so using an approach like this:
String cosNameBinding = "ejbApp.HighAvail.cluster";
InitialContext initial = new InitialContext();
Context fedContext = (javax.naming.Context) initialCtx.lookup(cosNameBinding);
Then do the normal EJB-style lookup/narrow/invoke using the federated/CosNaming context:
Object ejbHomeAsObject = fedContext.lookup(jndiNameOfService);
EJBHome home = (EJBHome) PortableRemoteObject.narrow(ejbHomeAsObject, homeClass);
Object service = invokeMethod(homeClass, home, "create");
As you can see, there is a level of indirection that occurs here in order to go from the InitialContext to the federated naming Context that can be used to interact with the shared EJB application.
Running locally, I have both the Grails application and the EJB application deployed to the same server (non network deployment WAS, same profile&node). I have Spring configured like so:
beans = {
ejbJndi(org.springframework.jndi.JndiTemplate) {
environment = ["java.naming.factory.initial" :
"com.ibm.websphere.naming.WsnInitialContextFactory"]
}
crewMemberService(org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean) {
jndiName="hotelService/ejb/HotelService"
businessInterface="com.company.appName.hotel.HotelService"
lookupHomeOnStartup="false"
cacheHome="false"
refreshHomeOnConnectFailure="true"
jndiTemplate = ref("ejbJndi")
}
}
And I can successfully inject ejb references into my Grails controllers and invoke them. However, WebSphere can only resolve the JNDI lookup because they are both deployed on the same server. When we move it to one of our development environments, we'll need jndi lookups for these services to go against the federated naming context.
So my questions are:
Is there a way to do this with the classes that are provided within Spring and if so could you give me an idea of how I would need up modify my Spring config to do so?
Given that there is no flexibility around how we deploy the other app or gain references to its services (we must use the federated context), should I consider extending JndiTemplate and do the necessary wiring myself?
If anyone has faced this situation I would be most appreciative for any insights you may be able to offer.
In case anyone has this same question down the road, I ended up implementing an extension to Spring's JndiTemplate and using that. Here is the code:
public class FederatedJndiTemplate extends org.springframework.jndi.JndiTemplate
{
protected static final String JNDI_CONTEXT_BINDING_NAME = "fed.context.jndiName";
/**
* Obtain a JNDI naming context for the specified federated naming context.
*
* #throws NamingException if no "fed.context.jndiName" has been specified in
* the environment properties for the jndiTemplate or the container throws a naming
* exception.
*/
#Override
protected Context createInitialContext() throws NamingException {
Properties props = super.getEnvironment();
if(!props.containsKey(JNDI_CONTEXT_BINDING_NAME)) {
throw new NamingException("You must specify the federated naming context JNDI binding name");
}
String jndiBinding = props.getProperty(JNDI_CONTEXT_BINDING_NAME);
InitialContext initCtx = new InitialContext();
Context fedCtx = (Context) initCtx.lookup(jndiBinding);
return fedCtx;
}
}
Then inside my resources.groovy, I just used this JndiTemplate:
ejbJndi(com.myCompany.spring.jndi.FederatedJndiTemplate) {
environment = [
"fed.context.jndiName":"myServices.HighAvail.Cluster"]
}
hotelService(org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean) {
jndiName="hotelService/ejb/HotelService"
businessInterface="com.mycompany.appName.hotel.HotelService"
homeInterface="com.mycompany.appName.hotel.HotelServiceHome"
lookupHomeOnStartup="false"
jndiTemplate = ref("ejbJndi")
}

Resources