If you have completed the basic Maven and Eclipse tutorial we will now learn how to enhance the simple Project by adding a dependency to a JBoss framework: Infinispan.
Infinispan currently has already some Maven archetypes you can use to create a skeleton project and get started using Infinispan. This is an easy way to get started using Infinispan as the archetype generates sample code, a sample Maven pom.xml with necessary depedencies.
So the quick way to generate this project is by running maven archetype generator using the org.infinispan.archetypes groupId:
mvn archetype:generate -DarchetypeGroupId=org.infinispan.archetypes -DarchetypeArtifactId=newproject-archetype -DarchetypeVersion=1.0.10 -DarchetypeRepository=http://repository.jboss.org/nexus/content/groups/public
If you want to learn how to get started with Maven and JBoss projects, we suggest to build the project from an quickstart project (see this tutorial how to create a quickstart project). This can be useful if you will familiarize with basic Maven concepts.
So provided that you have created a quick start project, add the following classes under the src\main\java folder
package com.sample; import org.infinispan.Cache; import org.infinispan.notifications.Listener; import org.infinispan.notifications.cachelistener.annotation.*; import org.infinispan.notifications.cachelistener.event.*; import org.infinispan.notifications.cachemanagerlistener.event.Event; import org.infinispan.util.concurrent.NotifyingFuture; import java.util.Arrays; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; /** * Sample application code. For more examples visit http://community.jboss.org/wiki/5minutetutorialonInfinispan */ public class Application { public void basicUse() { System.out.println("\n\n1. Demonstrating basic usage of Infinispan. This cache stores arbitrary Strings."); Cache<String, String> cache = SampleCacheContainer.getCache(); System.out.println(" Storing value 'World' under key 'Hello'"); String oldValue = cache.put("Hello", "World"); System.out.printf(" Done. Saw old value as '%s'\n", oldValue); System.out.println(" Replacing 'World' with 'Mars'."); boolean worked = cache.replace("Hello", "World", "Mars"); System.out.printf(" Successful? %s\n", worked); assert oldValue == null; assert worked == true; } public void lifespans() throws InterruptedException { System.out.println("\n\n2. Demonstrating usage of Infinispan with expirable entries."); Cache<String, Float> stocksCache = SampleCacheContainer.getCache("stock tickers"); System.out.println(" Storing key 'RHT' for 10 seconds."); stocksCache.put("RHT", 45.0f, 10, TimeUnit.SECONDS); System.out.printf(" Checking for existence of key. Is it there? %s\n", stocksCache.containsKey("RHT")); System.out.println(" Sleeping for 10 seconds..."); Thread.sleep(10000); System.out.printf(" Checking for existence of key. Is it there? %s\n", stocksCache.containsKey("RHT")); assert stocksCache.get("RHT") == null; } public void asyncOperations() { System.out.println("\n\n3. Demonstrating asynchronous operations - where writes can be done in a non-blocking fashion."); Cache<String, Integer> wineCache = SampleCacheContainer.getCache("wine cache"); System.out.println(" Put #1"); NotifyingFuture<Integer> f1 = wineCache.putAsync("Pinot Noir", 300); System.out.println(" Put #1"); NotifyingFuture<Integer> f2 = wineCache.putAsync("Merlot", 120); System.out.println(" Put #1"); NotifyingFuture<Integer> f3 = wineCache.putAsync("Chardonnay", 180); // now poll the futures to make sure any remote calls have completed! for (NotifyingFuture<Integer> f: Arrays.asList(f1, f2, f3)) { try { System.out.println(" Checking future... "); f.get(); } catch (Exception e) { throw new RuntimeException("Operation failed!", e); } } System.out.println(" Everything stored!"); // TIP: For more examples on using the asynchronous API, visit http://community.jboss.org/wiki/AsynchronousAPI } public void registeringListeners() { System.out.println("\n\n4. Demonstrating use of listeners."); Cache<Integer, String> anotherCache = SampleCacheContainer.getCache("another"); System.out.println(" Attaching listener"); MyListener l = new MyListener(); anotherCache.addListener(l); System.out.println(" Put #1"); anotherCache.put(1, "One"); System.out.println(" Put #2"); anotherCache.put(2, "Two"); System.out.println(" Put #3"); anotherCache.put(3, "Three"); // TIP: For more examples on using listeners visit http://community.jboss.org/wiki/ListenersandNotifications } public static void main(String[] args) throws Exception { System.out.println("\n\n\n ******************************** \n\n\n"); System.out.println("Hello. This is a sample application making use of Infinispan."); Application a = new Application(); a.basicUse(); a.lifespans(); a.asyncOperations(); a.registeringListeners(); System.out.println("Sample complete."); System.out.println("\n\n\n ******************************** \n\n\n"); } @Listener public class MyListener { @CacheEntryCreated @CacheEntryModified @CacheEntryRemoved public void printDetailsOnChange(CacheEntryEvent e) { System.out.printf("Thread %s has modified an entry in the cache named %s under key %s!\n", Thread.currentThread().getName(), e.getCache().getName(), e.getKey()); } @CacheEntryVisited public void pribtDetailsOnVisit(CacheEntryVisitedEvent e) { System.out.printf("Thread %s has visited an entry in the cache named %s under key %s!\n", Thread.currentThread().getName(), e.getCache().getName(), e.getKey()); } } }
This class is part of the 5 minutes quickstart tutorial to Infinispan and provides a simple and effective way to demonstrate some basic cache functionalities, the cache lifespan of entries, recording asynchronous operations in the cache, and registering listener to cache, which will notify your application when an entry has been created/moded/removed/visited.
Additionally, we will enrich the project with the SampleCacheContainer class which will be used to retrieves the embedded cache manager and the single named caches contained in the configuration file.
package com.sample; import org.infinispan.Cache; import org.infinispan.manager.DefaultCacheManager; import org.infinispan.manager.EmbeddedCacheManager; import java.io.IOException; /** * This sample cache container acts as a factory and a mechanism with which to create and configure an embedded cache * manager, and to hold this cache manager such that other code can access it. */ public class SampleCacheContainer { private static final String INFINISPAN_CONFIGURATION = "infinispan-local.xml"; private static final EmbeddedCacheManager CACHE_MANAGER; static { try { CACHE_MANAGER = new DefaultCacheManager(INFINISPAN_CONFIGURATION); } catch (IOException e) { throw new RuntimeException("Unable to configure Infinispan", e); } } /** * Retrieves the default cache. * @param <K> type used as keys in this cache * @param <V> type used as values in this cache * @return a cache */ public static <K, V> Cache<K, V> getCache() { return CACHE_MANAGER.getCache(); } /** * Retrieves a named cache. * @param cacheName name of cache to retrieve * @param <K> type used as keys in this cache * @param <V> type used as values in this cache * @return a cache */ public static <K, V> Cache<K, V> getCache(String cacheName) { if (cacheName == null) throw new NullPointerException("Cache name cannot be null!"); return CACHE_MANAGER.getCache(cacheName); } /** * Retrieves the embedded cache manager. * @return a cache manager */ public static EmbeddedCacheManager getCacheContainer() { return CACHE_MANAGER; } }
The configuration file, “infinispan-local.xml” used by the SampleCacheContainer, will be added into the resources folder of your application
<?xml version="1.0" encoding="UTF-8"?> <infinispan xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:infinispan:config:5.0 http://www.infinispan.org/schemas/infinispan-config-5.0.xsd" xmlns="urn:infinispan:config:5.0"> <global> <globalJmxStatistics enabled="true" jmxDomain="Infinispan" /> </global> <default> <locking concurrencyLevel="5000" /> </default> <namedCache name="stock tickers"> <locking isolationLevel="REPEATABLE_READ" useLockStriping="false" lockAcquisitionTimeout="10000" /> </namedCache> <namedCache name="wine cache"> <locking lockAcquisitionTimeout="500" /> <eviction maxEntries="500" wakeUpInterval="100" /> <lazyDeserialization enabled="true" /> </namedCache> <namedCache name="another"> <expiration lifespan="1000" maxIdle="500" /> </namedCache> </infinispan>
Here’s how the project should look like in your Eclipse editor:
Now what we need is adding a dependency into the pom.xml so that the project will be able to use Infinispan libraries:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.sample</groupId> <artifactId>com.mastertheboss</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>A sample project using Infinispan</name> <url>http://www.myorganization.org</url> <properties> <version.infinispan>5.1.5.FINAL</version.infinispan> </properties> <dependencies> <dependency> <groupId>org.infinispan</groupId> <artifactId>infinispan-core</artifactId> <version>${version.infinispan}</version> </dependency> </dependencies> <!-- Just in case you have not configured a Repository for JBoss projects in settings.xml --> <repositories> <repository> <id>JBoss.org Public Repository</id> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> <url>http://repository.jboss.org/nexus/content/groups/public/</url> </repository> </repositories> </project>
The repositories section has been added just in case that your Maven’s settings.xml file does not contain a repository for JBoss libraries (you can skip this section if you have already configured it in settings.xml)
Now you can run your application by right-clicking on your pom.xml and specifying the main class which will execute.
We will show here some tips to enrich your pom.xml configuration.
Setting the release version
One of the first thing we have coded in pom.xml is the release version. This has been injected into a property
<properties>
<version.infinispan>5.1.5.FINAL</version.infinispan>
</properties>
And then used, when declaring the dependency
<version>${version.infinispan}</version>
In general, it is not always a best practice to design software which depends on a non-specific version of an artifact. If you are developing software, you might want to use the latest (LATEST) or latest stable release (RELEASE) as a convenience so that you don’t have to update version numbers when a new release of a third-party library is released.
Let’s see some alternatives you can choose to specify the release:
Declare an exact version (will always resolve to 5.1.5.FINAL):
<version>[5.1.5.FINAL]</version>
Declare an explicit version (will always resolve to 5.1.5.FINAL unless a collision occurs, when Maven will select a matching version):
<version>5.1.5.FINAL</version>
Declare a version range:(will currently resolve to the version defined as RELEASE, in your case 5.1.5.FINAL):
<version>[5.1.5.FINAL,5.2.0.Beta2)</version>
Declare an open-ended version range (will resolve to 5.2.0.Beta2, if that is the latest version):
<version>[5.1.5.FINAL,)</version>
Declare the version as LATEST (will resolve to 5.2.0.Beta2):
<version>LATEST</version>
Delcare the version as RELEASE (will resolve to the latest stable RELEASE 5.1.5.FINAL)
<version>RELEASE</version>
Enforcing the JDK and Maven release
If you want to use a specific JDK and Maven release you can use a Maven plugin. Maven is – at its heart – a plugin execution framework; all work is done by plugins. You can find a list of available plugins here. In our case we will use the maven-enforcer-plugin which is a Environmental constraint checking (Maven Version, JDK etc) and user custom Rule Execution.
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>1.0-beta-1</version> <executions> <execution> <id>enforce-java</id> <goals> <goal>enforce</goal> </goals> <configuration> <rules> <requireJavaVersion> <version>[1.6,)</version> </requireJavaVersion> <requireMavenVersion> <version>[2.1.0,)</version> </requireMavenVersion> </rules> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.1</version> <configuration> <source>1.6</source> <target>1.6</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build>
You can add this plugin section, just after the dependency section of your pom.xml
Adding profiles to your pom.xml
By using profiles you can adapt the execution of your project to specific environments. For example you can create a “run” profile which will be used to trigger a Java main class, in our example the com.sample.Application class.
<profiles> <profile> <id>run</id> <activation> <activeByDefault>false</activeByDefault> </activation> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.1</version> <executions> <execution> <phase>process-classes</phase> <goals> <goal>java</goal> </goals> </execution> </executions> <configuration> <mainClass>com.sample.Application</mainClass> </configuration> </plugin> </plugins> </build> </profile> </profiles>
This can be useful if the user does not know which class to be launched at startup, so instead of running the project with:
mvn compile exec:java -Dexec.mainClass=com.sample.Application
Just use:
mvn install -Prun
Notice the -P option which is used to reference the “run” profile.