==  Using {brandname} as an embedded data grid in Java SE
Clustering {brandname} is simple.
Under the covers, {brandname} uses link:http://www.jgroups.org[JGroups] as a network transport, and JGroups handles all
the hard work of forming a cluster.

.clustered-cache quickstart
TIP: All the code discussed in this tutorial is available in the
link:https://github.com/infinispan/infinispan-quickstart/tree/master/clustered-cache[clustered-cache quickstart].

=== Sharing JGroups channels
By default all caches created from a single CacheManager share the same JGroups channel and multiplex RPC messages over it.
In this example caches 1, 2 and 3 all use the same JGroups channel.

[source,java]
----
EmbeddedCacheManager cm = new DefaultCacheManager("infinispan.xml");
Cache<Object, Object> replSyncCache = cm.getCache("replSyncCache");
Cache<Object, Object> replAsyncCache = cm.getCache("replAsyncCache");
Cache<Object, Object> invalidationSyncCache = cm.getCache("invalidationSyncCache");
----

=== Running {brandname} in a cluster
It is easy set up a clustered cache. This tutorial will show you how to create two nodes in different processes on the
same local machine.
The quickstart follows the same structure as the embedded-cache quickstart, using Maven to compile the project, and a
main method to launch the node.

If you are following along with the quickstarts, you can try the examples out.

The quickstart defines two clustered caches, one in _replication mode_ and one _distribution mode_.

==== Replicated mode
To run the example in replication mode, we need to launch two nodes from different consoles.
For the first node:

 $ mvn exec:java -Djava.net.preferIPv4Stack=true -Djgroups.bind_addr=127.0.0.1 -Dexec.mainClass="org.infinispan.quickstart.clusteredcache.Node" -Dexec.args="A"

And for the second node:

 $ mvn exec:java -Djava.net.preferIPv4Stack=true -Djgroups.bind_addr=127.0.0.1 -Dexec.mainClass="org.infinispan.quickstart.clusteredcache.Node" -Dexec.args="B"

Note: You need to set `-Djava.net.preferIPv4Stack=true` because the JGroups configuration uses IPv4 multicast address.
Normally you should not need `-Djgroups.bind_addr=127.0.0.1`, but many wireless routers do not relay IP multicast by default.

Each node will insert or update an entry every second, and it will log any changes.

==== Distributed mode
To run the example in distribution mode and see how entries are replicated to only two nodes, we need to launch three
nodes from different consoles.
For the first node:

 $ mvn compile exec:java -Djava.net.preferIPv4Stack=true  -Dexec.mainClass="org.infinispan.quickstart.clusteredcache.Node" -Dexec.args="-d A"

For the second node:

 $ mvn compile exec:java -Djava.net.preferIPv4Stack=true  -Dexec.mainClass="org.infinispan.quickstart.clusteredcache.Node" -Dexec.args="-d B"

And for the third node:

 $ mvn compile exec:java -Djava.net.preferIPv4Stack=true  -Dexec.mainClass="org.infinispan.quickstart.clusteredcache.Node" -Dexec.args="-d C"

The same as in replication mode, each node will insert or update an entry every second, and it will log any changes.
But unlike in replication mode, not every node will see every modification.

You can also see that each node holds a different set of entries by pressing Enter.

=== clustered-cache quickstart architecture

====  Logging changes to the cache
An easy way to see what is going on with your cache is to log mutated entries. An {brandname} listener is notified of any mutations:

[source,java]
----
import org.infinispan.notifications.Listener;
import org.infinispan.notifications.cachelistener.annotation.*;
import org.infinispan.notifications.cachelistener.event.*;
import org.jboss.logging.Logger;

@Listener
public class LoggingListener {

   private BasicLogger log = BasicLogFactory.getLog(LoggingListener.class);

   @CacheEntryCreated
   public void observeAdd(CacheEntryCreatedEvent<String, String> event) {
      if (event.isPre())
         return;
      log.infof("Cache entry %s = %s added in cache %s", event.getKey(), event.getValue(), event.getCache());
   }

   @CacheEntryModified
   public void observeUpdate(CacheEntryModifiedEvent<String, String> event) {
      if (event.isPre())
         return;
      log.infof("Cache entry %s = %s modified in cache %s", event.getKey(), event.getValue(), event.getCache());
   }

   @CacheEntryRemoved
   public void observeRemove(CacheEntryRemovedEvent<String, String> event) {
      if (event.isPre())
         return;
      log.infof("Cache entry %s removed in cache %s", event.getKey(), event.getCache());
   }
}
----

Listeners methods are declared using annotations, and receive a payload which contains metadata about the notification.
Listeners are notified of any changes. Here, the listeners simply log any entries added, modified, or removed.

==== What's going on?
The example allows you to start two or more nodes, each of which are started in a separate process.
The node code is very simple, each node starts up, prints the local cache contents, registers a listener that logs
any changes, and starts storing entries of the form `key-<counter> = <local address>-counter`.

.State transfer

{brandname} automatically replicates the cache contents from the existing members to joining members. This can be
controlled in two ways:

* If you don't want the `getCache()` call to block until the entire cache is transferred, you can configure
`clustering.stateTransfer.awaitInitialTransfer = false`.
Note that `cache.get(key)` will still return the correct value, even before the state transfer is finished.
* If it's fast enough to re-create the cache entries from another source, you can disable state transfer completely,
by configuring `clustering.stateTransfer.fetchInMemoryState = false`.

=== Configuring the cluster
First, we need to ensure that the cache manager is cluster aware.
{brandname} provides a default configuration for a clustered cache manager:

[source,java]
----
GlobalConfigurationBuilder.getClusteredDefault().build()
----

==== Tweaking the cluster configuration for your network
Depending on your network setup, you may need to tweak your JGroups set up.
JGroups is configured via an XML file; the file to use can be specified via the GlobalConfiguration: 

[source,java]
----
DefaultCacheManager cacheManager = new DefaultCacheManager(
      GlobalConfigurationBuilder.defaultClusteredBuilder()
            .transport().nodeName(nodeName).addProperty("configurationFile", "jgroups.xml")
            .build()
);
----

The link:http://www.jgroups.org/manual/html/index.html[JGroups documentation] provides extensive advice on getting
JGroups working on your network.
If you are new to configuring JGroups, you may get a little lost, so you might want to try tweaking these configuration
parameters:

*  Using the system property `-Djgroups.bind_addr=127.0.0.1` causes JGroups to bind only to your loopback interface,
meaning any firewall you may have configured won't get in the way.
Very useful for testing a cluster where all nodes are on one machine. 

*TODO - add more tips!*

You can also configure the JGroups configuration to use in {brandname}'s XML configuration:

[source,xml]
----
<infinispan>
  <jgroups>
     <stack-file name="external-file" path="jgroups.xml"/>
  </jgroups>
  <cache-container>
    <transport stack="external-file" />
  </cache-container>

  ...

</infinispan>
----

=== Configuring a replicated data-grid
In replicated mode, {brandname} will store every entry on every node in the grid. This offers high durability and
availability of data, but means the storage capacity is limited by the available heap space on the node with least
memory.
The cache should be configured to work in replication mode (either synchronous or asynchronous), and can otherwise be
configured as normal. For example, if you want to configure the cache programmatically:

[source,java]
----
cacheManager.defineConfiguration("repl", new ConfigurationBuilder()
      .clustering()
      .cacheMode(CacheMode.REPL_SYNC)
      .build()
);
----

You can configure an identical cache using XML:

.infinispan-replication.xml
[source,xml]
----
<infinispan>
  <jgroups/>
  <cache-container default-cache="repl">
     <transport/>
     <replicated-cache name="repl" mode="SYNC" />
  </cache-container>
</infinispan>
----

along with

[source,java]
----
private static EmbeddedCacheManager createCacheManagerFromXml() throws IOException {
   return new DefaultCacheManager("infinispan-replication.xml");
}
----

=== Configuring a distributed data-grid
In distributed mode, {brandname} will store every entry on a subset of the nodes in the grid (the parameter numOwners
controls how many owners each entry will have). Compared to replication, distribution offers increased storage capacity,
but with increased latency to access data from non-owner nodes, and durability (data may be lost if all the owners are
stopped in a short time interval).
Adjusting the number of owners allows you to obtain the trade off between space, durability, and latency.

{brandname} also offers a _topology aware consistent hash_ which will ensure that the owners of entries are located in
different data centers, racks, or physical machines, to offer improved durability in case of node crashes or network
outages.

The cache should be configured to work in distributed mode (either synchronous or asynchronous), and can otherwise
be configured as normal. For example, if you want to configure the cache programmatically:

[source,java]
----
cacheManager.defineConfiguration("dist", new ConfigurationBuilder()
      .clustering()
      .cacheMode(CacheMode.DIST_SYNC)
      .hash().numOwners(2)
      .build()
);
----

You can configure an identical cache using XML:

.infinispan-distribution.xml:
[source,xml]
----
<infinispan>
  <jgroups/>
  <cache-container default-cache="repl">
    <transport/>
    <distributed-cache owners="2" mode="SYNC" />
  </cache-container>
</infinispan>
----

along with

[source,java]
----
private static EmbeddedCacheManager createCacheManagerFromXml() throws IOException {
   return new DefaultCacheManager("infinispan-distribution.xml");
}
----



