[[function-annotations]]
= Annotation Support for Function Execution

{sdg-name} includes annotation support to simplify working with {data-store-name}
{x-data-store-docs}/developing/function_exec/chapter_overview.html[Function execution].

Under the hood, the {data-store-name} API provides classes to implement and register {data-store-name}
{x-data-store-javadoc}/org/apache/geode/cache/execute/Function.html[Functions] that are deployed on {data-store-name}
servers, which may then be invoked by other peer member applications or remotely from cache clients.

Functions can execute in parallel, distributed among multiple {data-store-name} servers in the cluster, aggregating the
results using the map-reduce pattern and sent back to the caller. Functions can also be targeted to run on a single
server or Region. The {data-store-name} API supports remote execution of Functions targeted by using various predefined
scopes: on Region, on members (in groups), on servers, and others. The implementation and execution of remote Functions,
as with any RPC protocol, requires some boilerplate code.

{sdg-name}, true to Spring's core value proposition, aims to hide the mechanics of remote Function execution and let you
focus on core POJO programming and business logic. To this end, {sdg-name} introduces annotations to declaratively
register the public methods of a POJO class as {data-store-name} Functions along with the ability to invoke registered
Functions (including remotely) by using annotated interfaces.

== Implementation Versus Execution

There are two separate concerns to address: implementation and execution.

The first is Function implementation (server-side), which must interact with the
{x-data-store-javadoc}/org/apache/geode/cache/execute/FunctionContext.html[`FunctionContext`]
to access the invocation arguments,
{x-data-store-javadoc}/org/apache/geode/cache/execute/ResultSender.html[`ResultsSender`] to send results,
and other execution context information. The Function implementation typically accesses the cache and Regions
and is registered with the
{x-data-store-javadoc}/org/apache/geode/cache/execute/FunctionService.html[`FunctionService`] under a unique ID.

A cache client application invoking a Function does not depend on the implementation. To invoke a Function,
the application instantiates an
{x-data-store-javadoc}/org/apache/geode/cache/execute/Execution.html[`Execution`]
providing the Function ID, invocation arguments, and the Function target, which defines its scope:
Region, server, servers, member, or members. If the Function produces a result, the invoker uses a
{x-data-store-javadoc}/org/apache/geode/cache/execute/ResultCollector.html[`ResultCollector`]
to aggregate and acquire the execution results. In certain cases, a custom `ResultCollector` implementation
is required and may be registered with the `Execution`.

NOTE: 'Client' and 'Server' are used here in the context of Function execution, which may have a different meaning
than client and server in {data-store-name}'s client-server topology. While it is common for an application using
a `ClientCache` instance to invoke a Function on one or more {data-store-name} servers in a cluster, it is also
possible to execute Functions in a peer-to-peer (P2P) configuration, where the application is a member of the cluster
hosting a peer `Cache` instance. Keep in mind that a peer member cache application is subject to all the constraints
of being a peer member of the cluster.

[[function-implementation]]
== Implementing a Function

Using {data-store-name} APIs, the `FunctionContext` provides a runtime invocation context that includes the client's
calling arguments and a `ResultSender` implementation to send results back to the client. Additionally, if the Function
is executed on a Region, the `FunctionContext` is actually an instance of `RegionFunctionContext`, which provides
additional information, such as the target Region on which the Function was invoked, any filter (a set of specific keys)
associated with the `Execution`, and so on. If the Region is a `PARTITION` Region, the Function should use
the `PartitionRegionHelper` to extract the local data set.

By using Spring, you can write a simple POJO and use the Spring container to bind one or more of your POJO's
public methods to a Function. The signature for a POJO method intended to be used as a Function must generally conform
to the client's execution arguments. However, in the case of a Region execution, the Region data may also be provided
(presumably the data is held in the local partition if the Region is a `PARTITION` Region).

Additionally, the Function may require the filter that was applied, if any. This suggests that the client and server
share a contract for the calling arguments but that the method signature may include additional parameters to pass values
provided by the `FunctionContext`. One possibility is for the client and server to share a common interface, but this
is not strictly required. The only constraint is that the method signature includes the same sequence of calling arguments
with which the Function was invoked after the additional parameters are resolved.

For example, suppose the client provides a `String` and an `int` as the calling arguments. These are provided
in the `FunctionContext` as an array, as the following example shows:

`Object[] args = new Object[] { "test", 123 };`

The Spring container should be able to bind to any method signature similar to the following (ignoring the return type
for the moment):

[source,java]
----
public Object method1(String s1, int i2) { ... }
public Object method2(Map<?, ?> data, String s1, int i2) { ... }
public Object method3(String s1, Map<?, ?> data, int i2) { ... }
public Object method4(String s1, Map<?, ?> data, Set<?> filter, int i2) { ... }
public void method4(String s1, Set<?> filter, int i2, Region<?,?> data) { ... }
public void method5(String s1, ResultSender rs, int i2) { ... }
public void method6(FunctionContest context) { ... }
----

The general rule is that once any additional arguments (that is, Region data and filter) are resolved,
the remaining arguments must correspond exactly, in order and type, to the expected Function method parameters.
The method's return type must be void or a type that may be serialized (as a `java.io.Serializable`, `DataSerializable`,
or `PdxSerializable`). The latter is also a requirement for the calling arguments.

The Region data should normally be defined as a `Map`, to facilitate unit testing, but may also be of type Region,
if necessary. As shown in the preceding example, it is also valid to pass the `FunctionContext` itself
or the `ResultSender` if you need to control over how the results are returned to the client.

=== Annotations for Function Implementation

The following example shows how {sdg-acronym}'s Function annotations are used to expose POJO methods
as {data-store-name} Functions:

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

   @GemfireFunction
   public String function1(String value, @RegionData Map<?, ?> data, int i2) { ... }

   @GemfireFunction(id = "myFunction", batchSize=100, HA=true, optimizedForWrite=true)
   public List<String> function2(String value, @RegionData Map<?, ?> data, int i2, @Filter Set<?> keys) { ... }

   @GemfireFunction(hasResult=true)
   public void functionWithContext(FunctionContext functionContext) { ... }

}
----

Note that the class itself must be registered as a Spring bean and each {data-store-name} Function is annotated with
`@GemfireFunction`. In the preceding example, Spring's `@Component` annotation was used, but you can register the bean
by using any method supported by Spring (such as XML configuration or with a Java configuration class when using
Spring Boot). This lets the Spring container create an instance of this class and wrap it in a
https://docs.spring.io/spring-data-gemfire/docs/current/api/org/springframework/data/gemfire/function/PojoFunctionWrapper.html[`PojoFunctionWrapper`].
Spring creates a wrapper instance for each method annotated with `@GemfireFunction`. Each wrapper instance shares
the same target object instance to invoke the corresponding method.

TIP: The fact that the POJO Function class is a Spring bean may offer other benefits. Since it shares
the `ApplicationContext` with {data-store-name} components, such as the cache and Regions, these may be injected into
the class if necessary.

Spring creates the wrapper class and registers the Functions with {data-store-name}'s `FunctionService`. The Function ID
used to register each Function must be unique. By using convention, it defaults to the simple (unqualified) method name.
The name can be explicitly defined by using the `id` attribute of the `@GemfireFunction` annotation.

The `@GemfireFunction` annotation also provides other configuration attributes: `HA` and `optimizedForWrite`,
which correspond to properties defined by {data-store-name}'s
{x-data-store-javadoc}/org/apache/geode/cache/execute/Function.html[`Function`] interface.

If the POJO Function method's return type is `void`, then the `hasResult` attribute is automatically set to `false`.
Otherwise, if the method returns a value, the `hasResult` attributes is set to `true`. Even for `void` method return
types, the `GemfireFunction` annotation's `hasResult` attribute can be set to `true` to override this convention,
as shown in the `functionWithContext` method shown previously. Presumably, the intention is that you will use
the `ResultSender` directly to send results to the caller.

Finally, the `GemfireFunction` annotation supports the `requiredPermissions` attribute, which specifies the permissions
required to execute the Function.  By default, all Functions require the `DATA:WRITE` permission.  The attribute
accepts an array of Strings allowing you to modify the permissions as required by your application and/or Function UC.
Each resource permission is expected to be in the following format: `<RESOURCE>:<OPERATION>:[Target]:[Key]`.

`RESOURCE` can be 1 of the {data-store-javadoc]/org/apache/geode/security/ResourcePermission.Resource.html[`ResourcePermission.Resource`]
enumerated values.  `OPERATION` can be 1 of the {data-store-javadoc}/org/apache/geode/security/ResourcePermission.Operation.html[`ResourcePermission.Operation`]
enumerated values.  Optionally, `Target` can be the name of a Region or 1 of the
{data-store-javadoc}/org/apache/geode/security/ResourcePermission.Target.html[`ResourcePermission.Target`]
enumerated values. And finally, optionally, `Key` is a valid Key in the `Target` Region if specified.

The `PojoFunctionWrapper` implements {data-store-name}'s `Function` interface, binds method parameters, and invokes
the target method in its `execute()` method. It also sends the method's return value back to the caller
by using the `ResultSender`.

=== Batching Results

If the return type is an array or `Collection`, then some consideration must be given to how the results are returned.
By default, the `PojoFunctionWrapper` returns the entire array or `Collection` at once. If the number of elements
in the array or `Collection` is quite large, it may incur a performance penalty. To divide the payload into smaller,
more manageable chunks, you can set the `batchSize` attribute, as illustrated in `function2`, shown earlier.

TIP: If you need more control of the `ResultSender`, especially if the method itself would use too much memory
to create the `Collection`, you can pass in the `ResultSender` or access it through the `FunctionContext`
and use it directly within the method to sends results back to the caller.

=== Enabling Annotation Processing

In accordance with Spring standards, you must explicitly activate annotation processing for `@GemfireFunction`
annotations. The following example activates annotation processing with XML:

[source,xml]
----
<gfe:annotation-driven/>
----

The following example activates annotation processing by annotating a Java configuration class:

[source,java]
----
@Configuration
@EnableGemfireFunctions
class ApplicationConfiguration { ... }
----

[[function-execution]]
== Executing a Function

A process that invokes a remote Function needs to provide the Function's ID, calling arguments, the execution target
(`onRegion`, `onServers`, `onServer`, `onMember`, or `onMembers`) and (optionally) a filter set. By using {sdg-name},
all you need do is define an interface supported by annotations. Spring creates a dynamic proxy for the interface,
which uses the `FunctionService` to create an `Execution`, invoke the `Execution`, and (if necessary) coerce
the results to the defined return type. This technique is similar to the way {sdg-name}'s Repository extension works.
Thus, some of the configuration and concepts should be familiar.

Generally, a single interface definition maps to multiple Function executions, one corresponding to each method
defined in the interface.

=== Annotations for Function Execution

To support client-side Function execution, the following {sdg-acronym} Function annotations are provided: `@OnRegion`,
`@OnServer`, `@OnServers`, `@OnMember`, and `@OnMembers`.  These annotations correspond to the `Execution`
implementations provided by {data-store-name}'s
{x-data-store-javadoc}/org/apache/geode/cache/execute/FunctionService.html[`FunctionService`] class.

Each annotation exposes the appropriate attributes. These annotations also provide an optional `resultCollector` attribute
whose value is the name of a Spring bean implementing the
{x-data-store-javadoc}/org/apache/geode/cache/execute/ResultCollector.html[`ResultCollector`] interface
to use for the execution.

CAUTION: The proxy interface binds all declared methods to the same execution configuration. Although it is expected
that single method interfaces are common, all methods in the interface are backed by the same proxy instance
and therefore all share the same configuration.

The following listing shows a few examples:

[source,java]
----
@OnRegion(region="SomeRegion", resultCollector="myCollector")
public interface FunctionExecution {

    @FunctionId("function1")
    String doIt(String s1, int i2);

    String getString(Object arg1, @Filter Set<Object> keys);

}
----

By default, the Function ID is the simple (unqualified) method name. The `@FunctionId` annotation can be used
to bind this invocation to a different Function ID.

=== Enabling Annotation Processing

The client-side uses Spring's classpath component scanning capability to discover annotated interfaces. To enable
Function execution annotation processing in XML, insert the following element in your XML configuration:

[source,xml]
----
<gfe-data:function-executions base-package="org.example.myapp.gemfire.functions"/>
----

The `function-executions` element is provided in the `gfe-data` XML namespace. The `base-package` attribute is required
to avoid scanning the entire classpath. Additional filters can be provided as described in the Spring
https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-scanning-filters[reference documentation].

Optionally, you can annotate your Java configuration class as follows:

[source,java]
----
@EnableGemfireFunctionExecutions(basePackages = "org.example.myapp.gemfire.functions")
----

[[function-execution-programmatic]]
== Programmatic Function Execution

Using the Function execution annotated interface defined in the previous section, simply auto-wire your interface
into an application bean that will invoke the Function:

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

    @Autowired
    FunctionExecution functionExecution;

    public void doSomething() {
         functionExecution.doIt("hello", 123);
    }
}
----

Alternately, you can use a Function execution template directly. In the following example,
the `GemfireOnRegionFunctionTemplate` creates an `onRegion` Function `Execution`:

.Using the `GemfireOnRegionFunctionTemplate`
====
[source,java]
----
Set<?, ?> myFilter = getFilter();
Region<?, ?> myRegion = getRegion();
GemfireOnRegionOperations template = new GemfireOnRegionFunctionTemplate(myRegion);
String result = template.executeAndExtract("someFunction", myFilter, "hello", "world", 1234);
----
====

Internally, Function `Executions` always return a `List`. `executeAndExtract` assumes a singleton `List`
containing the result and attempts to coerce that value into the requested type. There is also an `execute` method
that returns the `List` as is. The first parameter is the Function ID. The filter argument is optional. The remaining
arguments are a variable argument `List`.

[[function-execution-pdx]]
== Function Execution with PDX

When using {sdg-name}'s Function annotation support combined with {data-store-name}'s
{x-data-store-docs}/developing/data_serialization/gemfire_pdx_serialization.html[PDX Serialization],
there are a few logistical things to keep in mind.

As explained earlier in this section, and by way of example, you should typically define {data-store-name} Functions
by using POJO classes annotated with {sdg-name}
https://docs.spring.io/spring-data-gemfire/docs/current/api/org/springframework/data/gemfire/function/annotation/package-summary.html[Function annotations],
as follows:

[source,java]
----
public class OrderFunctions {

  @GemfireFunction(...)
  Order process(@RegionData data, Order order, OrderSource orderSourceEnum, Integer count) { ... }

}
----

NOTE: The `Integer` typed `count` parameter is arbitrary, as is the separation of the `Order` class
and the `OrderSource` enum, which might be logical to combine. However, the arguments were setup this way
to demonstrate the problem with Function executions in the context of PDX.

Your `Order` class and `OrderSource` enum might be defined as follows:

[source,java]
----
public class Order ... {

  private Long orderNumber;
  private LocalDateTime orderDateTime;
  private Customer customer;
  private List<Item> items

  ...
}


public enum OrderSource {
  ONLINE,
  PHONE,
  POINT_OF_SALE
  ...
}
----

Of course, you can define a Function `Execution` interface to call the 'process' {data-store-name} server Function,
as follows:

[source,java]
----
@OnServer
public interface OrderProcessingFunctions {
  Order process(Order order, OrderSource orderSourceEnum, Integer count);
}
----

Clearly, this `process(..)` `Order` Function is being called from the client-side with a `ClientCache` instance
(that is `<gfe:client-cache/>`). This implies that the Function arguments must also be serializable. The same is true
when invoking peer-to-peer member Functions (such as `@OnMember(s)`) between peers in the cluster. Any form of
`distribution` requires the data transmitted between client and server (or peers) to be serialized.

Now, if you have configured {data-store-name} to use PDX for serialization (instead of Java serialization, for instance)
you can also set the `pdx-read-serialized` attribute to `true` in your configuration of the {data-store-name} server(s),
as follows:

[source,xml]
----
<gfe:cache ... pdx-read-serialized="true"/>
----

Alternatively, you can set the `pdx-read-serialized` attribute to `true` for a {data-store-name} cache client application,
as follows:

[source,xml]
----
<gfe:client-cache ... pdx-read-serialized="true"/>
----

Doing so causes all values read from the cache (that is, Regions) as well as information passed between client and servers
(or peers) to remain in serialized form, including, but not limited to, Function arguments.

{data-store-name} serializes only application domain object types that you have specifically configured (registered)
either by using {data-store-name}'s
{x-data-store-javadoc}/org/apache/geode/pdx/ReflectionBasedAutoSerializer.html[`ReflectionBasedAutoSerializer`],
or specifically (and recommended) by using a "`custom`" {data-store-name}
{x-data-store-javadoc}/org/apache/geode/pdx/PdxSerializer.html[`PdxSerializer`].
If you use {sdg-name}'s Repository extension, you might even want to consider using {sdg-name}'s
{sdg-javadoc}/org/springframework/data/gemfire/mapping/MappingPdxSerializer.html[`MappingPdxSerializer`],
which uses an entity's mapping metadata to determine data from the application domain object that is serialized
to the PDX instance.

What is less than apparent, though, is that {data-store-name} automatically handles Java `Enum` types regardless
of whether they are explicitly configured (that is, registered with a `ReflectionBasedAutoSerializer`,
using a regex pattern and the `classes` parameter or are handled by a "`custom`" {data-store-name} `PdxSerializer`),
despite the fact that Java enumerations implement `java.io.Serializable`.

So, when you set `pdx-read-serialized` to `true` on {data-store-name} servers where the {data-store-name} Functions
(including {sdg-name} Function-annotated POJO classes) are registered, then you may encounter surprising behavior
when invoking the Function `Execution`.

You might pass the following arguments when invoking the Function:

[source,java]
----
orderProcessingFunctions.process(new Order(123, customer, LocalDateTime.now(), items), OrderSource.ONLINE, 400);
----

However, the {data-store-name} Function on the server gets the following:

[source,java]
----
process(regionData, order:PdxInstance, :PdxInstanceEnum, 400);
----

The `Order` and `OrderSource` have been passed to the Function as
{x-data-store-javadoc}/org/apache/geode/pdx/PdxInstance.html[PDX instances].
Again, this all happens because `pdx-read-serialized` is set to `true`, which may be necessary in cases where
the {data-store-name} servers interact with multiple different clients (for example, a combination of Java clients
and native clients, such as C/C++, C#, and others).

This flies in the face of {sdg-name}'s strongly-typed Function-annotated POJO class method signatures, where you would
reasonably expect application domain object types instead, not PDX serialized instances.

Consequently, {sdg-name} includes enhanced Function support to automatically convert PDX typed method arguments
to the desired application domain object types defined by the Function method's signature (parameter types).

However, this also requires you to explicitly register a {data-store-name} `PdxSerializer` on {data-store-name} servers
where {sdg-name} Function-annotated POJOs are registered and used, as the following example shows:

[source,java]
----
<bean id="customPdxSerializer" class="x.y.z.gemfire.serialization.pdx.MyCustomPdxSerializer"/>

<gfe:cache ... pdx-serializer-ref="customPdxSerializeer" pdx-read-serialized="true"/>
----

Alternatively, you can use {data-store-name}'s
{x-data-store-javadoc}/org/apache/geode/pdx/ReflectionBasedAutoSerializer.html[`ReflectionBasedAutoSerializer`]
for convenience. Of course, we recommend that, where possible, you use a custom `PdxSerializer` to maintain
finer-grained control over your serialization strategy.

Finally, {sdg-name} is careful not to convert your Function arguments if you treat your Function arguments generically
or as one of {data-store-name}'s PDX types, as follows:

[source,java]
----
@GemfireFunction
public Object genericFunction(String value, Object domainObject, PdxInstanceEnum enum) {
 ...
}
----

{sdg-name} converts PDX typed data to the corresponding application domain types if and only if the corresponding
application domain types are on the classpath and the Function-annotated POJO method expects it.

For a good example of custom, composed application-specific {data-store-name} `PdxSerializers` as well as appropriate
POJO Function parameter type handling based on the method signatures, see {sdg-name}'s
https://github.com/spring-projects/spring-data-gemfire/blob/{revnumber}/src/test/java/org/springframework/data/gemfire/function/ClientCacheFunctionExecutionWithPdxIntegrationTest.java[`ClientCacheFunctionExecutionWithPdxIntegrationTest`] class.
