[[bootstrap:snapshot]]
= Configuring the Snapshot Service

_Spring Data for Pivotal GemFire_ supports `Cache` and `Region` snapshots using
http://geode.apache.org/docs/guide/11/managing/cache_snapshots/chapter_overview.html[Pivotal GemFire's Snapshot Service].
The out-of-the-box Snapshot Service support offers several convenient features to simplify the use of Pivotal GemFire's
http://geode.apache.org/releases/latest/javadoc/org/apache/geode/cache/snapshot/CacheSnapshotService.html[Cache]
and http://geode.apache.org/releases/latest/javadoc/org/apache/geode/cache/snapshot/RegionSnapshotService.html[Region]
Snapshot Service APIs.

As the http://geode.apache.org/docs/guide/11/managing/cache_snapshots/chapter_overview.html[Pivotal GemFire documentation]
describes, snapshots allow you to save and subsequently reload the cached data later, which can be useful for
moving data between environments, such as from production to a staging or test environment in order to reproduce
data-related issues in a controlled context. You can imagine combining _Spring Data for Pivotal GemFire's_ Snapshot Service support
with http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-definition-profiles[Spring's bean definition profiles]
to load snapshot data specific to the environment as necessary.

_Spring Data for Pivotal GemFire's_ support for Pivotal GemFire's Snapshot Service begins with the `<gfe-data:snapshot-service>` element
from the `<gfe-data>` namespace.

For example, I might want to define Cache-wide snapshots to be loaded as well as saved using a couple snapshot imports
and a data export definition as follows:

[source,xml]
----
<gfe-data:snapshot-service id="gemfireCacheSnapshotService">
  <gfe-data:snapshot-import location="/absolute/filesystem/path/to/import/fileOne.snapshot"/>
  <gfe-data:snapshot-import location="relative/filesystem/path/to/import/fileTwo.snapshot"/>
  <gfe-data:snapshot-export
      location="/absolute/or/relative/filesystem/path/to/export/directory"/>
</gfe-data:snapshot-service>
----

You can define as many imports and/or exports as you like.  You can define just imports or just exports.
The file locations and directory paths can be absolute, or relative to the _Spring Data for Pivotal GemFire_ application,
JVM process's working directory.

This is a pretty simple example and the Snapshot Service defined in this case refers to the Pivotal GemFire `Cache` with
the default name of `gemfireCache` (as described in <<bootstrap:cache>>).  If you name your cache bean definition
something other than the default, than you can use the `cache-ref` attribute to refer to the cache bean by name:

[source,xml]
----
<gfe:cache id="myCache"/>
...
<gfe-data:snapshot-service id="mySnapshotService" cache-ref="myCache">
  ...
</gfe-data:snapshot-service>
----

It is also straightforward to define a Snapshot Service for a particular Pivotal GemFire Region by specifying
the `region-ref` attribute:

[source,xml]
----
<gfe:partitioned-region id="Example" persistent="false" .../>
...
<gfe-data:snapshot-service id="gemfireCacheRegionSnapshotService" region-ref="Example">
  <gfe-data:snapshot-import location="relative/path/to/import/example.snapshot/>
  <gfe-data:snapshot-export location="/absolute/path/to/export/example.snapshot/>
</gfe-data:snapshot-service>
----

When the `region-ref` attribute is specified, _Spring Data for Pivotal GemFire's_ `SnapshotServiceFactoryBean` resolves
the `region-ref` attribute value to a Region bean defined in the _Spring_ context and proceeds to create a
http://geode.apache.org/releases/latest/javadoc/org/apache/geode/cache/snapshot/RegionSnapshotService.html[RegionSnapshotService].
The snapshot import and export definitions function the same way, however, the `location` must refer to a file
on export.

NOTE: Pivotal GemFire is strict about imported snapshot files actually existing before they are referenced.  For exports,
Pivotal GemFire will create the snapshot file if it does not already exist.  If the snapshot file for export already exists,
the data will be overwritten.

TIP: _Spring Data for Pivotal GemFire_ includes a `suppress-import-on-init` attribute on the `<gfe-data:snapshot-service>` element
to suppress the configured Snapshot Service from trying to import data into the Cache or Region on initialization.
This is useful when data exported from 1 Region is used to feed the import of another Region, for example.

[[bootstrap:snapshot:location]]
== Snapshot Location

For a `Cache`-based Snapshot Service
(i.e. http://geode.apache.org/releases/latest/javadoc/org/apache/geode/cache/snapshot/CacheSnapshotService.html[CacheSnapshotService])
a developer would typically pass it a directory containing all the snapshot files to load rather than
individual snapshot files, as the overloaded
http://geode.apache.org/releases/latest/javadoc/org/apache/geode/cache/snapshot/CacheSnapshotService.html#load-java.io.File-org.apache.geode.cache.snapshot.SnapshotOptions.SnapshotFormat-[load]
method in the `CacheSnapshotService` API indicates.

NOTE: Of course, a developer may use the other, overloaded `load(:File[], :SnapshotFormat, :SnapshotOptions)` method
variant to get specific about which snapshot files are to be loaded into the Pivotal GemFire `Cache`.

However, _Spring Data for Pivotal GemFire_ recognizes that a typical developer workflow might be to extract and export data
from one environment into several snapshot files, zip all of them up, and then conveniently move the ZIP file
to another environment for import.

Therefore, _Spring Data for Pivotal GemFire_ enables the developer to specify a JAR or ZIP file on import for a `Cache`-based
Snapshot Service as follows:

[source,xml]
----
  <gfe-data:snapshot-service id="cacheBasedSnapshotService" cache-ref="gemfireCache">
    <gfe-data:snapshot-import location="/path/to/snapshots.zip"/>
  </gfe-data:snapshot-service>
----

_Spring Data for Pivotal GemFire_ will conveniently extract the provided ZIP file and treat it like a directory import (load).

[[bootstrap:snapshot:filters]]
== Snapshot Filters

The real power of defining multiple snapshot imports and exports is realized through the use of snapshot filters.
Snapshot filters implement Pivotal GemFire's
http://geode.apache.org/releases/latest/javadoc/org/apache/geode/cache/snapshot/SnapshotFilter.html[SnapshotFilter]
interface and are used to filter Region entries for inclusion into the Region on import
and for inclusion into the snapshot on export.

_Spring Data for Pivotal GemFire_ makes it brain dead simple to utilize snapshot filters on import and export using the `filter-ref`
attribute or an anonymous, nested bean definition:

[source,xml]
----
<gfe:cache/>

<gfe:partitioned-region id="Admins" persistent="false"/>
<gfe:partitioned-region id="Guests" persistent="false"/>

<bean id="activeUsersFilter" class="example.gemfire.snapshot.filter.ActiveUsersFilter/>

<gfe-data:snapshot-service id="adminsSnapshotService" region-ref="Admins">
  <gfe-data:snapshot-import location="/path/to/import/users.snapshot">
    <bean class="example.gemfire.snapshot.filter.AdminsFilter/>
  </gfe-data:snapshot-import>
  <gfe-data:snapshot-export location="/path/to/export/active/admins.snapshot" filter-ref="activeUsersFilter"/>
</gfe-data:snapshot-service>

<gfe-data:snapshot-service id="guestsSnapshotService" region-ref="Guests">
  <gfe-data:snapshot-import location="/path/to/import/users.snapshot">
    <bean class="example.gemfire.snapshot.filter.GuestsFilter/>
  </gfe-data:snapshot-import>
  <gfe-data:snapshot-export location="/path/to/export/active/guests.snapshot" filter-ref="activeUsersFilter"/>
</gfe-data:snapshot-service>
----

In addition, more complex snapshot filters can be expressed with the `ComposableSnapshotFilter` _Spring Data for Pivotal GemFire_
provided class.  This class implements Pivotal GemFire's
http://geode.apache.org/releases/latest/javadoc/org/apache/geode/cache/snapshot/SnapshotFilter.html[SnapshotFilter]
interface as well as the https://en.wikipedia.org/wiki/Composite_pattern[Composite] software design pattern.

In a nutshell, the https://en.wikipedia.org/wiki/Composite_pattern[Composite] software design pattern allows developers
to compose multiple objects of the same type and treat the aggregate as single instance of the object type,
a very powerful and useful abstraction.

`ComposableSnapshotFilter` has two factory methods, `'and'` and `'or'`, allowing developers to logically combine
individual snapshot filters using the AND and OR logical operators, respectively.  The factory methods take a
list of `SnapshotFilters`.

In this case, the developer is only limited by his/her imagination to leverage this powerful construct.

For instance:

[source,xml]
----
<bean id="activeUsersSinceFilter" class="org.springframework.data.gemfire.snapshot.filter.ComposableSnapshotFilter"
      factory-method="and">
  <constructor-arg index="0">
    <list>
      <bean class="org.example.app.gemfire.snapshot.filter.ActiveUsersFilter"/>
      <bean class="org.example.app.gemfire.snapshot.filter.UsersSinceFilter"
            p:since="2015-01-01"/>
    </list>
  </constructor-arg>
</bean>
----

The developer could then go onto combine the `activesUsersSinceFilter` with another filter using `'or'` like so:

[source,xml]
----
<bean id="covertOrActiveUsersSinceFilter" class="org.springframework.data.gemfire.snapshot.filter.ComposableSnapshotFilter"
      factory-method="or">
  <constructor-arg index="0">
    <list>
      <ref bean="activeUsersSinceFilter"/>
      <bean class="example.gemfire.snapshot.filter.CovertUsersFilter"/>
    </list>
  </constructor-arg>
</bean>
----

[[bootstrap::snapshot::events]]
== Snapshot Events

By default, _Spring Data for Pivotal GemFire_ uses Pivotal GemFire's Snapshot Services on startup to import data and shutdown
to export data.  However, you may want to trigger periodic, event-based snapshots, for either import or export
from within your _Spring_ application.

For this purpose, _Spring Data for Pivotal GemFire_ defines two additional _Spring_ application events, extending _Spring's_
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/ApplicationEvent.html[ApplicationEvent]
class for imports and exports, respectively: `ImportSnapshotApplicationEvent` and `ExportSnapshotApplicationEvent`.

The two application events can be targeted at the entire Pivotal GemFire Cache, or individual Pivotal GemFire Regions.  The constructors
in these classes accept an optional Region pathname (e.g. "/Example") as well as 0 or more `SnapshotMetadata` instances.

The array of `SnapshotMetadata` is used to override the snapshot meta-data defined by `<gfe-data:snapshot-import>`
and `<gfe-data:snapshot-export>` sub-elements in XML, which will be used in cases where snapshot application events
do not explicitly provide `SnapshotMetadata`.  Each individual `SnapshotMetadata` instance can define it's own
`location` and `filters` properties.

Import/export snapshot application events are received by all snapshot service beans defined in the _Spring_
`ApplicationContext`.  However, import/export events are only processed by "matching" Snapshot Service beans.

A Region-based `[Import|Export]SnapshotApplicationEvent` matches if the Snapshot Service bean defined
is a `RegionSnapshotService` and it's Region reference (as determined by the `region-ref` attribute) matches
the Region's pathname specified by the snapshot application event.

A Cache-based `[Import|Export]SnapshotApplicationEvent` (i.e. a snapshot application event without a Region pathname)
triggers all Snapshot Service beans, including any `RegionSnapshotService` beans, to perform either an import or export,
respectively.

It is very easy to use _Spring's_
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/ApplicationEventPublisher.html[ApplicationEventPublisher]
interface to fire import and/or export snapshot application events from your application like so:

[source,java]
----
@Component
public class ExampleApplicationComponent {

  @Autowired
  private ApplicationEventPublisher eventPublisher;

  @Resource(name = "Example")
  private Region<?, ?> example;

  public void someMethod() {
    ...

    SnapshotFilter myFilter = ...;

    SnapshotMetadata exportSnapshotMetadata = new SnapshotMetadata(new File(System.getProperty("user.dir"),
      "/path/to/export/data.snapshot"), myFilter, null);

    eventPublisher.publishEvent(new ExportSnapshotApplicationEvent(this, example.getFullPath(), exportSnapshotMetadata);

    ...
  }
}
----

In this particular example, only the "/Example" Region's Snapshot Service bean will pick up and handle the export event,
saving the filtered, "/Example" Region's data to the "data.snapshot" file in a sub-direcrtory
of the application's working directory.

Using _Spring_ application events and messaging subsystem is a good way to keep your application loosely coupled.
It is also not difficult to imagine that the snapshot application events could be fired on a periodic basis
using _Spring's_
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#scheduling-task-scheduler[Scheduling]
services.
