==  Example with Scala
This article shows how to use Infinispan with link:$$http://www.scala-lang.org/$$[Scala language] . It uses the same commands and configurations used in the <<_example_with_groovy, Example with Groovy>>. For more details about the scenarios and steps please visit about page since here will will only focus on Scala compatibility. 

=== Environment
Running the shell

----
 $ scala -cp infinispan-embedded-{infinispanversion}.0.Final.jar:lib/jboss-transaction-api_1.1_spec-1.0.1.Final.jar:sample-configurations.xml
----

where infinispan-embedded-{infinispanversion}.0.Final.jar, jboss-transaction-api_1.1_spec-1.0.1.Final.jar are shipped with the infinispan zip.

.sample-configurations.xml
[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>

<infinispan
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="urn:infinispan:config:{infinispanversion} http://infinispan.org/schemas/infinispan-config-{infinispanversion}.xsd"
        xmlns="urn:infinispan:config:{infinispanversion}">

   <jgroups>
      <stack-file name="tcpStack" path="default-configs/default-jgroups-tcp.xml"/>
   </jgroups>

   <cache-container default-cache="default">
      <transport stack="tcpStack" cluster="sampleCluster"/>
      <local-cache name="LocalTX">
         <transaction transaction-manager-lookup="org.infinispan.transaction.lookup.DummyTransactionManagerLookup" />
      </local-cache>
      <local-cache name="CacheStore">
         <persistence>
            <file-store path="${java.io.tmpdir}" shared="false" preload="false" />
         </persistence>
      </local-cache>
      <local-cache name="Eviction">
         <eviction max-entries="2" strategy="FIFO" />
         <expiration interval="500" />
      </local-cache>
      <local-cache name="CacheStoreEviction">
         <eviction max-entries="2" strategy="FIFO" />
         <expiration interval="500" />
         <persistence>
            <file-store path="${java.io.tmpdir}" shared="false" preload="false" purge="false" fetch-state="true" />
         </persistence>
      </local-cache>
      <replicated-cache name="ReplicatedTX" mode="SYNC" remote-timeout="20000">
         <state-transfer timeout="20000" />
      </replicated-cache>
   </cache-container>

</infinispan>
----


=== Testing Setup
The following code shows how to start an Scala console that will allow commands to be entered interactively. To verify that the Infinispan classes have been imported correctly, an import for all Infinispan classes will be attempted and then a request will be made to print the version of Infinispan:


----
 $ scala -cp infinispan-embedded-{infinispanversion}.0.Final.jar:lib/jboss-transaction-api_1.1_spec-1.0.1.Final.jar:sample-configuration.xml
Welcome to Scala version 2.11.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_60).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import org.infinispan._
import org.infinispan._

scala> println(Version.VERSION)
{infinispanversion}.0.Final


----

=== Loading the Configuration file

In this next example, a new cache manager will be created using the configuration file downloaded earlier:


----
scala> import org.infinispan.manager._                                   
import org.infinispan.manager._

scala> val manager = new DefaultCacheManager("sample-configurations.xml")
manager: org.infinispan.manager.DefaultCacheManager = org.infinispan.manager.DefaultCacheManager@38b58e73@Address:null

----

Retrieving cache instances from cache manager

In this example, the default cache is retrieved expecting keys and values to be of String type:


----
scala> val defaultCache = manager.getCache[String, String]()
defaultCache: org.infinispan.Cache[String,String] = Cache '___defaultcache'@1326840752

----

In this next example, a named cache is retrieved, again with keys and values expected to be String:


----
scala> val namedCache = manager.getCache[String, String]("NameOfCache")
namedCache: org.infinispan.Cache[String,String] = Cache 'NameOfCache'@394890130
----

[[sid-68355111_InfinispanwithScala-Basiccacheoperations]]


=== Basic cache operations

In this section, several basic operations will be executed against the cache that show how it can be populated with data, how data can be retrieved and size can be checked, and finally how after removing the data entered, the cache is empty:


----
scala> val localCache = manager.getCache[String, String]("Local")
localCache: org.infinispan.Cache[String,String] = Cache 'Local'@420875876

scala> localCache.size
res0: Int = 0

scala> localCache.put("aKey", "aValue")
res1: String = null
// This null was returned by put() indicating that 
// the key was not associated with any previous value.

scala> localCache.size
res2: Int = 1

scala> localCache.containsKey("aKey")
res3: Boolean = true

scala> localCache.get("aKey")
res4: String = aValue

scala> localCache.size
res5: Int = 1

scala> localCache.remove("aKey")
res6: String = aValue

scala> localCache.isEmpty
res7: Boolean = true
----

=== Basic cache operations with TTL

When a cache entry is stored, a maximum lifespan for the entry can be provided. So, when that time is exceeded, the entry will dissapear from the cache:


----
scala> localCache.put("bKey", "bValue")
res8: String = null

scala> import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeUnit

scala> localCache.put("timedKey", "timedValue", 1000, TimeUnit.MILLISECONDS)
res9: String = null

scala> localCache.size
res10: Int = 2

scala> localCache.get("timedKey")
res11: String = null

scala> localCache.size
res12: Int = 1
----

=== Cache restarts

When caches are local and not configured with a persistent store, restarting them means that the data is gone. To avoid this issue you can either configure caches to be clustered so that if one cache dissapears, the data is not completely gone, or configure the cache with a persistent cache store. The latter option will be explained later on.


----
scala> localCache.size
res13: Int = 1

scala> localCache.stop

scala> localCache.start

scala> localCache.size
res16: Int = 0
----

=== Transactional cache operations

Infinispan caches can be operated within a transaction, in such way that operations can be grouped in order to be executed atomically. The key thing to understand about transactions is that within the transactions changes are visible, but to other non-transactional operations, or other transactions, these are not visible until the transaction is committed. The following example shows how within a transaction an entry can be stored but outside the transaction, this modification is not yet visible, and that once the transaction is committed, the modification is visible to all:


----
scala> import javax.transaction.TransactionManager
import javax.transaction.TransactionManager

scala> val localTxCache = manager.getCache[String, String]("LocalTX")
localTxCache: org.infinispan.Cache[String,String] = Cache 'LocalTX'@955386212

scala> val tm = localTxCache.getAdvancedCache().getTransactionManager()
tm: javax.transaction.TransactionManager = org.infinispan.transaction.tm.DummyTransactionManager@81ee8c1

scala> tm.begin

scala> localTxCache.put("key1", "value1")
res1: String = null

scala> localTxCache.size
res2: Int = 1

scala> val tx = tm.suspend
res3: javax.transaction.Transaction = DummyTransaction{xid=DummyXid{id=1}, status=0}

scala> localTxCache.size
res4: Int = 0

scala> localTxCache.get("key1")
res5: String = null

scala> tm.resume(tx)

scala> localTxCache.size()
res7: Int = 1

scala> localTxCache get "key1"
res8: String = value1

scala> tm.commit

scala> localTxCache.size
res10: Int = 1

scala> localTxCache get "key1"
res11: String = value1

----

Note how this example shows a very interesting characteristic of the Scala console. Every operation's return value is stored in a temporary variable which can be referenced at a later stage, even if the user forgets to assign the result of a operation when the code was executed.

=== Persistent stored backed Cache operations

When a cache is backed by a persistent store, restarting the cache does not lead to data being lost. Upon restart, the cache can retrieve in lazy or prefetched fashion cache entries stored in the backend persistent store:


----
scala> val cacheWithStore = manager.getCache[String, String]("CacheStore")
cacheWithStore: org.infinispan.Cache[String,String] = Cache 'CacheStore'@2054925789

scala> cacheWithStore.put("storedKey", "storedValue")
res21: String = null

scala> localCache.put("storedKey", "storedValue")
res22: String = null

scala> cacheWithStore.stop

scala> localCache.stop

scala> cacheWithStore.start

scala> localCache.start

scala> localCache.get("storedKey")
res27: String = null

scala> cacheWithStore.size
res28: Int = 1

scala> cacheWithStore.get("storedKey")
res29: String = storedValue

----

=== Operating against a size bounded cache

Infinispan caches can be configured with a max number of entries, so if this is exceeded certain cache entries are evicted from in-memory cache. Which cache entries get evicted is dependant on the eviction algorithm chosen. In this particular example, FIFO algorithm has been configured, so when a cache entry needs to be evicted, those stored first will go first:


----
scala> val evictionCache = manager.getCache[String, String]("Eviction")
evictionCache: org.infinispan.Cache[String,String] = Cache 'Eviction'@882725548

scala> evictionCache.put("key1", "value1")
res30: String = null

scala> evictionCache.put("key2", "value2")
res31: String = null

scala> evictionCache.put("key3", "value3")
res32: String = null

scala> evictionCache.size()
res33: Int = 2

scala> evictionCache.get("key3")
res34: String = value3

scala> evictionCache.get("key2")
res35: String = value2

scala> evictionCache.get("key1")
res36: String = null
----

=== Size bounded caches with persistent store

When caches configured with eviction are configured with a persistent store as well, when the cache exceeds certain size, apart from removing the corresponding cache entries from memory, these entries are stored in the persistent store. So, if they're requested by cache operations, these are retrieved from the cache store:


----
scala> val cacheStoreEvictionCache = manager.getCache[String, String]("CacheStoreEviction")
cacheStoreEvictionCache: org.infinispan.Cache[String,String] = Cache 'CacheStoreEviction'@367917752

scala> cacheStoreEvictionCache.put("cs1", "value1")
res37: String = null

scala> cacheStoreEvictionCache.put("cs2", "value2")
res38: String = null

scala> cacheStoreEvictionCache.put("cs3", "value3")
res39: String = null

scala> cacheStoreEvictionCache.size()
res40: Int = 2

scala> cacheStoreEvictionCache.get("cs3")
res41: String = value3

scala> cacheStoreEvictionCache.get("cs2")
res42: String = value2

scala> cacheStoreEvictionCache.get("cs1")
res43: String = value1

----

