You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by rx...@apache.org on 2020/08/05 10:44:18 UTC

[pulsar] 07/07: Add window context function example

This is an automated email from the ASF dual-hosted git repository.

rxl pushed a commit to branch branch-2.6
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit 8b4a92186b45f3109012e32b5aea3b46b264f252
Author: 冉小龙 <rx...@apache.org>
AuthorDate: Wed Aug 5 11:12:24 2020 +0800

    Add window context function example
    
    Signed-off-by: xiaolong.ran <rx...@apache.org>
---
 site2/docs/window-functions-context.md             | 528 ++++++++++++++++++++
 site2/website/sidebars.json                        |   3 +-
 .../version-2.3.0/window-functions-context.md      | 529 +++++++++++++++++++++
 .../version-2.3.1/window-functions-context.md      | 529 +++++++++++++++++++++
 .../version-2.3.2/window-functions-context.md      | 529 +++++++++++++++++++++
 .../version-2.4.0/window-functions-context.md      | 529 +++++++++++++++++++++
 .../version-2.4.1/window-functions-context.md      | 529 +++++++++++++++++++++
 .../version-2.4.2/window-functions-context.md      | 529 +++++++++++++++++++++
 .../version-2.5.0/window-functions-context.md      | 529 +++++++++++++++++++++
 .../version-2.5.1/window-functions-context.md      | 529 +++++++++++++++++++++
 .../version-2.5.2/window-functions-context.md      | 529 +++++++++++++++++++++
 .../version-2.6.0/window-functions-context.md      | 529 +++++++++++++++++++++
 .../versioned_sidebars/version-2.3.0-sidebars.json |   3 +-
 .../versioned_sidebars/version-2.3.1-sidebars.json |   3 +-
 .../versioned_sidebars/version-2.3.2-sidebars.json |   3 +-
 .../versioned_sidebars/version-2.4.0-sidebars.json |   3 +-
 .../versioned_sidebars/version-2.4.1-sidebars.json |   3 +-
 .../versioned_sidebars/version-2.4.2-sidebars.json |   3 +-
 .../versioned_sidebars/version-2.5.0-sidebars.json |   3 +-
 .../versioned_sidebars/version-2.5.1-sidebars.json |   3 +-
 .../versioned_sidebars/version-2.5.2-sidebars.json |   3 +-
 .../versioned_sidebars/version-2.6.0-sidebars.json | 153 ++++++
 22 files changed, 5991 insertions(+), 10 deletions(-)

diff --git a/site2/docs/window-functions-context.md b/site2/docs/window-functions-context.md
new file mode 100644
index 0000000..e81f6e8
--- /dev/null
+++ b/site2/docs/window-functions-context.md
@@ -0,0 +1,528 @@
+---
+id: window-functions-context
+title: Window Functions Context
+sidebar_label: "Window Functions: Context"
+---
+
+Java SDK provides access to a **window context object** that can be used by a window function. This context object provides a wide variety of information and functionality for Pulsar window functions as below.
+
+- [Spec](#spec)
+
+  * Names of all input topics and the output topic associated with the function.
+  * Tenant and namespace associated with the function.
+  * Pulsar window function name, ID, and version.
+  * ID of the Pulsar function instance running the window function.
+  * Number of instances that invoke the window function.
+  * Built-in type or custom class name of the output schema.
+  
+- [Logger](#logger)
+  
+  * Logger object used by the window function, which can be used to create window function log messages.
+
+- [User config](#user-config)
+  
+  * Access to arbitrary user configuration values.
+
+- [Routing](#routing)
+  
+  * Routing is supported in Pulsar window functions. Pulsar window functions send messages to arbitrary topics as per the `publish` interface.
+
+- [Metrics](#metrics)
+  
+  * Interface for recording metrics.
+
+- [State storage](#state-storage)
+  
+  * Interface for storing and retrieving state in [state storage](#state-storage).
+
+## Spec
+
+Spec contains the basic information of a function.
+
+### Get input topics
+
+The `getInputTopics` method gets the **name list** of all input topics.
+
+This example demonstrates how to get the name list of all input topics in a Java window function.
+
+```java
+public class GetInputTopicsWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Collection<String> inputTopics = context.getInputTopics();
+        System.out.println(inputTopics);
+
+        return null;
+    }
+
+}
+```
+
+### Get output topic
+
+The `getOutputTopic` method gets the **name of a topic** to which the message is sent.
+
+This example demonstrates how to get the name of an output topic in a Java window function.
+
+```java
+public class GetOutputTopicWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String outputTopic = context.getOutputTopic();
+        System.out.println(outputTopic);
+
+        return null;
+    }
+}
+```
+
+### Get tenant
+
+The `getTenant` method gets the tenant name associated with the window function.
+
+This example demonstrates how to get the tenant name in a Java window function.
+
+```java
+public class GetTenantWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String tenant = context.getTenant();
+        System.out.println(tenant);
+
+        return null;
+    }
+
+}
+```
+
+### Get namespace
+
+The `getNamespace` method gets the namespace associated with the window function.
+
+This example demonstrates how to get the namespace in a Java window function.
+
+```java
+public class GetNamespaceWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String ns = context.getNamespace();
+        System.out.println(ns);
+
+        return null;
+    }
+
+}
+```
+
+### Get function name
+
+The `getFunctionName` method gets the window function name.
+
+This example demonstrates how to get the function name in a Java window function.
+
+```java
+public class GetNameOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionName = context.getFunctionName();
+        System.out.println(functionName);
+
+        return null;
+    }
+
+}
+```
+
+### Get function ID
+
+The `getFunctionId` method gets the window function ID.
+
+This example demonstrates how to get the function ID in a Java window function.
+
+```java
+public class GetFunctionIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionID = context.getFunctionId();
+        System.out.println(functionID);
+
+        return null;
+    }
+
+}
+```
+
+### Get function version
+
+The `getFunctionVersion` method gets the window function version.
+
+This example demonstrates how to get the function version of a Java window function.
+
+```java
+public class GetVersionOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionVersion = context.getFunctionVersion();
+        System.out.println(functionVersion);
+
+        return null;
+    }
+
+}
+```
+
+### Get instance ID
+
+The `getInstanceId` method gets the instance ID of a window function.
+
+This example demonstrates how to get the instance ID in a Java window function.
+
+```java
+public class GetInstanceIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int instanceId = context.getInstanceId();
+        System.out.println(instanceId);
+
+        return null;
+    }
+
+}
+```
+
+### Get num instances
+
+The `getNumInstances` method gets the number of instances that invoke the window function.
+
+This example demonstrates how to get the number of instances in a Java window function.
+
+```java
+public class GetNumInstancesWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int numInstances = context.getNumInstances();
+        System.out.println(numInstances);
+
+        return null;
+    }
+
+}
+```
+
+### Get output schema type
+
+The `getOutputSchemaType` method gets the built-in type or custom class name of the output schema.
+
+This example demonstrates how to get the output schema type of a Java window function.
+
+```java
+public class GetOutputSchemaTypeWindowFunction implements WindowFunction<String, Void> {
+
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String schemaType = context.getOutputSchemaType();
+        System.out.println(schemaType);
+
+        return null;
+    }
+}
+```
+
+## Logger
+
+Pulsar window functions using Java SDK has access to an [SLF4j](https://www.slf4j.org/) [`Logger`](https://www.slf4j.org/api/org/apache/log4j/Logger.html) object that can be used to produce logs at the chosen log level.
+
+This example logs either a `WARNING`-level or `INFO`-level log based on whether the incoming string contains the word `danger` or not in a Java function.
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+import org.slf4j.Logger;
+
+public class LoggingWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Logger log = context.getLogger();
+        for (Record<String> record : inputs) {
+            log.info(record + "-window-log");
+        }
+        return null;
+    }
+
+}
+```
+
+If you need your function to produce logs, specify a log topic when creating or running the function. 
+
+```bash
+bin/pulsar-admin functions create \
+  --jar my-functions.jar \
+  --classname my.package.LoggingFunction \
+  --log-topic persistent://public/default/logging-function-logs \
+  # Other function configs
+```
+
+You can access all logs produced by `LoggingFunction` via the `persistent://public/default/logging-function-logs` topic.
+
+## Metrics
+
+Pulsar window functions can publish arbitrary metrics to the metrics interface which can be queried. 
+
+> **Note**
+>
+> If a Pulsar window function uses the language-native interface for Java, that function is not able to publish metrics and stats to Pulsar.
+
+You can record metrics using the context object on a per-key basis. 
+
+This example sets a metric for the `process-count` key and a different metric for the `elevens-count` key every time the function processes a message in a Java function. 
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+
+
+/**
+ * Example function that wants to keep track of
+ * the event time of each message sent.
+ */
+public class UserMetricWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+
+        for (Record<String> record : inputs) {
+            if (record.getEventTime().isPresent()) {
+                context.recordMetric("MessageEventTime", record.getEventTime().get().doubleValue());
+            }
+        }
+
+        return null;
+    }
+}
+```
+
+## User config
+
+When you run or update Pulsar Functions that are created using SDK, you can pass arbitrary key/value pairs to them with the `--user-config` flag. Key/value pairs **must** be specified as JSON. 
+
+This example passes a user configured key/value to a function.
+
+```bash
+bin/pulsar-admin functions create \
+  --name word-filter \
+ --user-config '{"forbidden-word":"rosebud"}' \
+  # Other function configs
+```
+
+### API
+You can use the following APIs to get user-defined information for window functions.
+#### getUserConfigMap
+
+`getUserConfigMap` API gets a map of all user-defined key/value configurations for the window function.
+
+
+```java
+/**
+     * Get a map of all user-defined key/value configs for the function.
+     *
+     * @return The full map of user-defined config values
+     */
+    Map<String, Object> getUserConfigMap();
+```
+
+
+#### getUserConfigValue
+
+The `getUserConfigValue` API gets a user-defined key/value.
+
+```java
+/**
+     * Get any user-defined key/value.
+     *
+     * @param key The key
+     * @return The Optional value specified by the user for that key.
+     */
+    Optional<Object> getUserConfigValue(String key);
+```
+
+#### getUserConfigValueOrDefault
+
+The `getUserConfigValueOrDefault` API gets a user-defined key/value or a default value if none is present.
+
+```java
+/**
+     * Get any user-defined key/value or a default value if none is present.
+     *
+     * @param key
+     * @param defaultValue
+     * @return Either the user config value associated with a given key or a supplied default value
+     */
+    Object getUserConfigValueOrDefault(String key, Object defaultValue);
+```
+
+This example demonstrates how to access key/value pairs provided to Pulsar window functions.
+
+Java SDK context object enables you to access key/value pairs provided to Pulsar window functions via the command line (as JSON). 
+
+>**Tip**
+>
+> For all key/value pairs passed to Java window functions, both the `key` and the `value` are `String`. To set the value to be a different type, you need to deserialize it from the `String` type.
+
+This example passes a key/value pair in a Java window function.
+
+```bash
+bin/pulsar-admin functions create \
+   --user-config '{"word-of-the-day":"verdure"}' \
+  # Other function configs
+ ```
+
+This example accesses values in a Java window function.
+
+The `UserConfigFunction` function logs the string `"The word of the day is verdure"` every time the function is invoked (which means every time a message arrives). The user config of `word-of-the-day` is changed **only** when the function is updated with a new config value via 
+multiple ways, such as the command line tool or REST API.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+import org.slf4j.Logger;
+
+import java.util.Optional;
+
+public class UserConfigWindowFunction implements WindowFunction<String, String> {
+    @Override
+    public String process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        Optional<Object> whatToWrite = context.getUserConfigValue("WhatToWrite");
+        if (whatToWrite.get() != null) {
+            return (String)whatToWrite.get();
+        } else {
+            return "Not a nice way";
+        }
+    }
+
+}
+```
+
+If no value is provided, you can access the entire user config map or set a default value.
+
+```java
+// Get the whole config map
+Map<String, String> allConfigs = context.getUserConfigMap();
+
+// Get value or resort to default
+String wotd = context.getUserConfigValueOrDefault("word-of-the-day", "perspicacious");
+```
+
+## Routing
+
+You can use the `context.publish()` interface to publish as many results as you want.
+
+This example shows that the `PublishFunction` class uses the built-in function in the context to publish messages to the `publishTopic` in a Java function.
+
+```java
+public class PublishWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        String publishTopic = (String) context.getUserConfigValueOrDefault("publish-topic", "publishtopic");
+        String output = String.format("%s!", input);
+        context.publish(publishTopic, output);
+
+        return null;
+    }
+
+}
+```
+
+## State storage
+
+Pulsar window functions use [Apache BookKeeper](https://bookkeeper.apache.org) as a state storage interface. Apache Pulsar installation (including the standalone installation) includes the deployment of BookKeeper bookies.
+
+Apache Pulsar integrates with Apache BookKeeper `table service` to store the `state` for functions. For example, the `WordCount` function can store its `counters` state into BookKeeper table service via Pulsar Functions state APIs.
+
+States are key-value pairs, where the key is a string and the value is arbitrary binary data—counters are stored as 64-bit big-endian binary values. Keys are scoped to an individual Pulsar Function and shared between instances of that function.
+
+Currently, Pulsar window functions expose Java API to access, update, and manage states. These APIs are available in the context object when you use Java SDK functions.
+
+| Java API| Description
+|---|---
+|`incrCounter`|Increases a built-in distributed counter referred by key.
+|`getCounter`|Gets the counter value for the key.
+|`putState`|Updates the state value for the key.
+
+You can use the following APIs to access, update, and manage states in Java window functions. 
+
+#### incrCounter
+
+The `incrCounter` API increases a built-in distributed counter referred by key.
+
+Applications use the `incrCounter` API to change the counter of a given `key` by the given `amount`. If the `key` does not exist, a new key is created.
+
+```java
+    /**
+     * Increment the builtin distributed counter referred by key
+     * @param key The name of the key
+     * @param amount The amount to be incremented
+     */
+    void incrCounter(String key, long amount);
+```
+
+#### getCounter
+
+The `getCounter` API gets the counter value for the key.
+
+Applications uses the `getCounter` API to retrieve the counter of a given `key` changed by the `incrCounter` API.
+
+```java
+    /**
+     * Retrieve the counter value for the key.
+     *
+     * @param key name of the key
+     * @return the amount of the counter value for this key
+     */
+    long getCounter(String key);
+```
+
+Except the `getCounter` API, Pulsar also exposes a general key/value API (`putState`) for functions to store general key/value state.
+
+#### putState
+
+The `putState` API updates the state value for the key.
+
+```java
+    /**
+     * Update the state value for the key.
+     *
+     * @param key name of the key
+     * @param value state value of the key
+     */
+    void putState(String key, ByteBuffer value);
+```
+
+This example demonstrates how applications store states in Pulsar window functions.
+
+The logic of the `WordCountWindowFunction` is simple and straightforward.
+
+1. The function first splits the received string into multiple words using regex `\\.`.
+
+2. For each `word`, the function increments the corresponding `counter` by 1 via `incrCounter(key, amount)`.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+
+import java.util.Arrays;
+
+public class WordCountWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        for (Record<String> input : inputs) {
+            Arrays.asList(input.getValue().split("\\.")).forEach(word -> context.incrCounter(word, 1));
+        }
+        return null;
+
+    }
+}
+```
+
diff --git a/site2/website/sidebars.json b/site2/website/sidebars.json
index 480e276..a402a13 100644
--- a/site2/website/sidebars.json
+++ b/site2/website/sidebars.json
@@ -32,7 +32,8 @@
       "functions-develop",
       "functions-debug",
       "functions-deploy",
-      "functions-cli"
+      "functions-cli",
+      "window-functions-context"
     ],
     "Pulsar IO": [
       "io-overview",
diff --git a/site2/website/versioned_docs/version-2.3.0/window-functions-context.md b/site2/website/versioned_docs/version-2.3.0/window-functions-context.md
new file mode 100644
index 0000000..752f95a
--- /dev/null
+++ b/site2/website/versioned_docs/version-2.3.0/window-functions-context.md
@@ -0,0 +1,529 @@
+---
+id: version-2.3.0-window-functions-context
+title: Window Functions Context
+sidebar_label: "Window Functions: Context"
+original_id: window-functions-context
+---
+
+Java SDK provides access to a **window context object** that can be used by a window function. This context object provides a wide variety of information and functionality for Pulsar window functions as below.
+
+- [Spec](#spec)
+
+  * Names of all input topics and the output topic associated with the function.
+  * Tenant and namespace associated with the function.
+  * Pulsar window function name, ID, and version.
+  * ID of the Pulsar function instance running the window function.
+  * Number of instances that invoke the window function.
+  * Built-in type or custom class name of the output schema.
+  
+- [Logger](#logger)
+  
+  * Logger object used by the window function, which can be used to create window function log messages.
+
+- [User config](#user-config)
+  
+  * Access to arbitrary user configuration values.
+
+- [Routing](#routing)
+  
+  * Routing is supported in Pulsar window functions. Pulsar window functions send messages to arbitrary topics as per the `publish` interface.
+
+- [Metrics](#metrics)
+  
+  * Interface for recording metrics.
+
+- [State storage](#state-storage)
+  
+  * Interface for storing and retrieving state in [state storage](#state-storage).
+
+## Spec
+
+Spec contains the basic information of a function.
+
+### Get input topics
+
+The `getInputTopics` method gets the **name list** of all input topics.
+
+This example demonstrates how to get the name list of all input topics in a Java window function.
+
+```java
+public class GetInputTopicsWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Collection<String> inputTopics = context.getInputTopics();
+        System.out.println(inputTopics);
+
+        return null;
+    }
+
+}
+```
+
+### Get output topic
+
+The `getOutputTopic` method gets the **name of a topic** to which the message is sent.
+
+This example demonstrates how to get the name of an output topic in a Java window function.
+
+```java
+public class GetOutputTopicWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String outputTopic = context.getOutputTopic();
+        System.out.println(outputTopic);
+
+        return null;
+    }
+}
+```
+
+### Get tenant
+
+The `getTenant` method gets the tenant name associated with the window function.
+
+This example demonstrates how to get the tenant name in a Java window function.
+
+```java
+public class GetTenantWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String tenant = context.getTenant();
+        System.out.println(tenant);
+
+        return null;
+    }
+
+}
+```
+
+### Get namespace
+
+The `getNamespace` method gets the namespace associated with the window function.
+
+This example demonstrates how to get the namespace in a Java window function.
+
+```java
+public class GetNamespaceWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String ns = context.getNamespace();
+        System.out.println(ns);
+
+        return null;
+    }
+
+}
+```
+
+### Get function name
+
+The `getFunctionName` method gets the window function name.
+
+This example demonstrates how to get the function name in a Java window function.
+
+```java
+public class GetNameOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionName = context.getFunctionName();
+        System.out.println(functionName);
+
+        return null;
+    }
+
+}
+```
+
+### Get function ID
+
+The `getFunctionId` method gets the window function ID.
+
+This example demonstrates how to get the function ID in a Java window function.
+
+```java
+public class GetFunctionIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionID = context.getFunctionId();
+        System.out.println(functionID);
+
+        return null;
+    }
+
+}
+```
+
+### Get function version
+
+The `getFunctionVersion` method gets the window function version.
+
+This example demonstrates how to get the function version of a Java window function.
+
+```java
+public class GetVersionOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionVersion = context.getFunctionVersion();
+        System.out.println(functionVersion);
+
+        return null;
+    }
+
+}
+```
+
+### Get instance ID
+
+The `getInstanceId` method gets the instance ID of a window function.
+
+This example demonstrates how to get the instance ID in a Java window function.
+
+```java
+public class GetInstanceIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int instanceId = context.getInstanceId();
+        System.out.println(instanceId);
+
+        return null;
+    }
+
+}
+```
+
+### Get num instances
+
+The `getNumInstances` method gets the number of instances that invoke the window function.
+
+This example demonstrates how to get the number of instances in a Java window function.
+
+```java
+public class GetNumInstancesWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int numInstances = context.getNumInstances();
+        System.out.println(numInstances);
+
+        return null;
+    }
+
+}
+```
+
+### Get output schema type
+
+The `getOutputSchemaType` method gets the built-in type or custom class name of the output schema.
+
+This example demonstrates how to get the output schema type of a Java window function.
+
+```java
+public class GetOutputSchemaTypeWindowFunction implements WindowFunction<String, Void> {
+
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String schemaType = context.getOutputSchemaType();
+        System.out.println(schemaType);
+
+        return null;
+    }
+}
+```
+
+## Logger
+
+Pulsar window functions using Java SDK has access to an [SLF4j](https://www.slf4j.org/) [`Logger`](https://www.slf4j.org/api/org/apache/log4j/Logger.html) object that can be used to produce logs at the chosen log level.
+
+This example logs either a `WARNING`-level or `INFO`-level log based on whether the incoming string contains the word `danger` or not in a Java function.
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+import org.slf4j.Logger;
+
+public class LoggingWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Logger log = context.getLogger();
+        for (Record<String> record : inputs) {
+            log.info(record + "-window-log");
+        }
+        return null;
+    }
+
+}
+```
+
+If you need your function to produce logs, specify a log topic when creating or running the function. 
+
+```bash
+bin/pulsar-admin functions create \
+  --jar my-functions.jar \
+  --classname my.package.LoggingFunction \
+  --log-topic persistent://public/default/logging-function-logs \
+  # Other function configs
+```
+
+You can access all logs produced by `LoggingFunction` via the `persistent://public/default/logging-function-logs` topic.
+
+## Metrics
+
+Pulsar window functions can publish arbitrary metrics to the metrics interface which can be queried. 
+
+> **Note**
+>
+> If a Pulsar window function uses the language-native interface for Java, that function is not able to publish metrics and stats to Pulsar.
+
+You can record metrics using the context object on a per-key basis. 
+
+This example sets a metric for the `process-count` key and a different metric for the `elevens-count` key every time the function processes a message in a Java function. 
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+
+
+/**
+ * Example function that wants to keep track of
+ * the event time of each message sent.
+ */
+public class UserMetricWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+
+        for (Record<String> record : inputs) {
+            if (record.getEventTime().isPresent()) {
+                context.recordMetric("MessageEventTime", record.getEventTime().get().doubleValue());
+            }
+        }
+
+        return null;
+    }
+}
+```
+
+## User config
+
+When you run or update Pulsar Functions that are created using SDK, you can pass arbitrary key/value pairs to them with the `--user-config` flag. Key/value pairs **must** be specified as JSON. 
+
+This example passes a user configured key/value to a function.
+
+```bash
+bin/pulsar-admin functions create \
+  --name word-filter \
+ --user-config '{"forbidden-word":"rosebud"}' \
+  # Other function configs
+```
+
+### API
+You can use the following APIs to get user-defined information for window functions.
+#### getUserConfigMap
+
+`getUserConfigMap` API gets a map of all user-defined key/value configurations for the window function.
+
+
+```java
+/**
+     * Get a map of all user-defined key/value configs for the function.
+     *
+     * @return The full map of user-defined config values
+     */
+    Map<String, Object> getUserConfigMap();
+```
+
+
+#### getUserConfigValue
+
+The `getUserConfigValue` API gets a user-defined key/value.
+
+```java
+/**
+     * Get any user-defined key/value.
+     *
+     * @param key The key
+     * @return The Optional value specified by the user for that key.
+     */
+    Optional<Object> getUserConfigValue(String key);
+```
+
+#### getUserConfigValueOrDefault
+
+The `getUserConfigValueOrDefault` API gets a user-defined key/value or a default value if none is present.
+
+```java
+/**
+     * Get any user-defined key/value or a default value if none is present.
+     *
+     * @param key
+     * @param defaultValue
+     * @return Either the user config value associated with a given key or a supplied default value
+     */
+    Object getUserConfigValueOrDefault(String key, Object defaultValue);
+```
+
+This example demonstrates how to access key/value pairs provided to Pulsar window functions.
+
+Java SDK context object enables you to access key/value pairs provided to Pulsar window functions via the command line (as JSON). 
+
+>**Tip**
+>
+> For all key/value pairs passed to Java window functions, both the `key` and the `value` are `String`. To set the value to be a different type, you need to deserialize it from the `String` type.
+
+This example passes a key/value pair in a Java window function.
+
+```bash
+bin/pulsar-admin functions create \
+   --user-config '{"word-of-the-day":"verdure"}' \
+  # Other function configs
+ ```
+
+This example accesses values in a Java window function.
+
+The `UserConfigFunction` function logs the string `"The word of the day is verdure"` every time the function is invoked (which means every time a message arrives). The user config of `word-of-the-day` is changed **only** when the function is updated with a new config value via 
+multiple ways, such as the command line tool or REST API.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+import org.slf4j.Logger;
+
+import java.util.Optional;
+
+public class UserConfigWindowFunction implements WindowFunction<String, String> {
+    @Override
+    public String process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        Optional<Object> whatToWrite = context.getUserConfigValue("WhatToWrite");
+        if (whatToWrite.get() != null) {
+            return (String)whatToWrite.get();
+        } else {
+            return "Not a nice way";
+        }
+    }
+
+}
+```
+
+If no value is provided, you can access the entire user config map or set a default value.
+
+```java
+// Get the whole config map
+Map<String, String> allConfigs = context.getUserConfigMap();
+
+// Get value or resort to default
+String wotd = context.getUserConfigValueOrDefault("word-of-the-day", "perspicacious");
+```
+
+## Routing
+
+You can use the `context.publish()` interface to publish as many results as you want.
+
+This example shows that the `PublishFunction` class uses the built-in function in the context to publish messages to the `publishTopic` in a Java function.
+
+```java
+public class PublishWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        String publishTopic = (String) context.getUserConfigValueOrDefault("publish-topic", "publishtopic");
+        String output = String.format("%s!", input);
+        context.publish(publishTopic, output);
+
+        return null;
+    }
+
+}
+```
+
+## State storage
+
+Pulsar window functions use [Apache BookKeeper](https://bookkeeper.apache.org) as a state storage interface. Apache Pulsar installation (including the standalone installation) includes the deployment of BookKeeper bookies.
+
+Apache Pulsar integrates with Apache BookKeeper `table service` to store the `state` for functions. For example, the `WordCount` function can store its `counters` state into BookKeeper table service via Pulsar Functions state APIs.
+
+States are key-value pairs, where the key is a string and the value is arbitrary binary data—counters are stored as 64-bit big-endian binary values. Keys are scoped to an individual Pulsar Function and shared between instances of that function.
+
+Currently, Pulsar window functions expose Java API to access, update, and manage states. These APIs are available in the context object when you use Java SDK functions.
+
+| Java API| Description
+|---|---
+|`incrCounter`|Increases a built-in distributed counter referred by key.
+|`getCounter`|Gets the counter value for the key.
+|`putState`|Updates the state value for the key.
+
+You can use the following APIs to access, update, and manage states in Java window functions. 
+
+#### incrCounter
+
+The `incrCounter` API increases a built-in distributed counter referred by key.
+
+Applications use the `incrCounter` API to change the counter of a given `key` by the given `amount`. If the `key` does not exist, a new key is created.
+
+```java
+    /**
+     * Increment the builtin distributed counter referred by key
+     * @param key The name of the key
+     * @param amount The amount to be incremented
+     */
+    void incrCounter(String key, long amount);
+```
+
+#### getCounter
+
+The `getCounter` API gets the counter value for the key.
+
+Applications uses the `getCounter` API to retrieve the counter of a given `key` changed by the `incrCounter` API.
+
+```java
+    /**
+     * Retrieve the counter value for the key.
+     *
+     * @param key name of the key
+     * @return the amount of the counter value for this key
+     */
+    long getCounter(String key);
+```
+
+Except the `getCounter` API, Pulsar also exposes a general key/value API (`putState`) for functions to store general key/value state.
+
+#### putState
+
+The `putState` API updates the state value for the key.
+
+```java
+    /**
+     * Update the state value for the key.
+     *
+     * @param key name of the key
+     * @param value state value of the key
+     */
+    void putState(String key, ByteBuffer value);
+```
+
+This example demonstrates how applications store states in Pulsar window functions.
+
+The logic of the `WordCountWindowFunction` is simple and straightforward.
+
+1. The function first splits the received string into multiple words using regex `\\.`.
+
+2. For each `word`, the function increments the corresponding `counter` by 1 via `incrCounter(key, amount)`.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+
+import java.util.Arrays;
+
+public class WordCountWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        for (Record<String> input : inputs) {
+            Arrays.asList(input.getValue().split("\\.")).forEach(word -> context.incrCounter(word, 1));
+        }
+        return null;
+
+    }
+}
+```
+
diff --git a/site2/website/versioned_docs/version-2.3.1/window-functions-context.md b/site2/website/versioned_docs/version-2.3.1/window-functions-context.md
new file mode 100644
index 0000000..94280f6
--- /dev/null
+++ b/site2/website/versioned_docs/version-2.3.1/window-functions-context.md
@@ -0,0 +1,529 @@
+---
+id: version-2.3.1-window-functions-context
+title: Window Functions Context
+sidebar_label: "Window Functions: Context"
+original_id: window-functions-context
+---
+
+Java SDK provides access to a **window context object** that can be used by a window function. This context object provides a wide variety of information and functionality for Pulsar window functions as below.
+
+- [Spec](#spec)
+
+  * Names of all input topics and the output topic associated with the function.
+  * Tenant and namespace associated with the function.
+  * Pulsar window function name, ID, and version.
+  * ID of the Pulsar function instance running the window function.
+  * Number of instances that invoke the window function.
+  * Built-in type or custom class name of the output schema.
+  
+- [Logger](#logger)
+  
+  * Logger object used by the window function, which can be used to create window function log messages.
+
+- [User config](#user-config)
+  
+  * Access to arbitrary user configuration values.
+
+- [Routing](#routing)
+  
+  * Routing is supported in Pulsar window functions. Pulsar window functions send messages to arbitrary topics as per the `publish` interface.
+
+- [Metrics](#metrics)
+  
+  * Interface for recording metrics.
+
+- [State storage](#state-storage)
+  
+  * Interface for storing and retrieving state in [state storage](#state-storage).
+
+## Spec
+
+Spec contains the basic information of a function.
+
+### Get input topics
+
+The `getInputTopics` method gets the **name list** of all input topics.
+
+This example demonstrates how to get the name list of all input topics in a Java window function.
+
+```java
+public class GetInputTopicsWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Collection<String> inputTopics = context.getInputTopics();
+        System.out.println(inputTopics);
+
+        return null;
+    }
+
+}
+```
+
+### Get output topic
+
+The `getOutputTopic` method gets the **name of a topic** to which the message is sent.
+
+This example demonstrates how to get the name of an output topic in a Java window function.
+
+```java
+public class GetOutputTopicWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String outputTopic = context.getOutputTopic();
+        System.out.println(outputTopic);
+
+        return null;
+    }
+}
+```
+
+### Get tenant
+
+The `getTenant` method gets the tenant name associated with the window function.
+
+This example demonstrates how to get the tenant name in a Java window function.
+
+```java
+public class GetTenantWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String tenant = context.getTenant();
+        System.out.println(tenant);
+
+        return null;
+    }
+
+}
+```
+
+### Get namespace
+
+The `getNamespace` method gets the namespace associated with the window function.
+
+This example demonstrates how to get the namespace in a Java window function.
+
+```java
+public class GetNamespaceWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String ns = context.getNamespace();
+        System.out.println(ns);
+
+        return null;
+    }
+
+}
+```
+
+### Get function name
+
+The `getFunctionName` method gets the window function name.
+
+This example demonstrates how to get the function name in a Java window function.
+
+```java
+public class GetNameOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionName = context.getFunctionName();
+        System.out.println(functionName);
+
+        return null;
+    }
+
+}
+```
+
+### Get function ID
+
+The `getFunctionId` method gets the window function ID.
+
+This example demonstrates how to get the function ID in a Java window function.
+
+```java
+public class GetFunctionIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionID = context.getFunctionId();
+        System.out.println(functionID);
+
+        return null;
+    }
+
+}
+```
+
+### Get function version
+
+The `getFunctionVersion` method gets the window function version.
+
+This example demonstrates how to get the function version of a Java window function.
+
+```java
+public class GetVersionOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionVersion = context.getFunctionVersion();
+        System.out.println(functionVersion);
+
+        return null;
+    }
+
+}
+```
+
+### Get instance ID
+
+The `getInstanceId` method gets the instance ID of a window function.
+
+This example demonstrates how to get the instance ID in a Java window function.
+
+```java
+public class GetInstanceIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int instanceId = context.getInstanceId();
+        System.out.println(instanceId);
+
+        return null;
+    }
+
+}
+```
+
+### Get num instances
+
+The `getNumInstances` method gets the number of instances that invoke the window function.
+
+This example demonstrates how to get the number of instances in a Java window function.
+
+```java
+public class GetNumInstancesWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int numInstances = context.getNumInstances();
+        System.out.println(numInstances);
+
+        return null;
+    }
+
+}
+```
+
+### Get output schema type
+
+The `getOutputSchemaType` method gets the built-in type or custom class name of the output schema.
+
+This example demonstrates how to get the output schema type of a Java window function.
+
+```java
+public class GetOutputSchemaTypeWindowFunction implements WindowFunction<String, Void> {
+
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String schemaType = context.getOutputSchemaType();
+        System.out.println(schemaType);
+
+        return null;
+    }
+}
+```
+
+## Logger
+
+Pulsar window functions using Java SDK has access to an [SLF4j](https://www.slf4j.org/) [`Logger`](https://www.slf4j.org/api/org/apache/log4j/Logger.html) object that can be used to produce logs at the chosen log level.
+
+This example logs either a `WARNING`-level or `INFO`-level log based on whether the incoming string contains the word `danger` or not in a Java function.
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+import org.slf4j.Logger;
+
+public class LoggingWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Logger log = context.getLogger();
+        for (Record<String> record : inputs) {
+            log.info(record + "-window-log");
+        }
+        return null;
+    }
+
+}
+```
+
+If you need your function to produce logs, specify a log topic when creating or running the function. 
+
+```bash
+bin/pulsar-admin functions create \
+  --jar my-functions.jar \
+  --classname my.package.LoggingFunction \
+  --log-topic persistent://public/default/logging-function-logs \
+  # Other function configs
+```
+
+You can access all logs produced by `LoggingFunction` via the `persistent://public/default/logging-function-logs` topic.
+
+## Metrics
+
+Pulsar window functions can publish arbitrary metrics to the metrics interface which can be queried. 
+
+> **Note**
+>
+> If a Pulsar window function uses the language-native interface for Java, that function is not able to publish metrics and stats to Pulsar.
+
+You can record metrics using the context object on a per-key basis. 
+
+This example sets a metric for the `process-count` key and a different metric for the `elevens-count` key every time the function processes a message in a Java function. 
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+
+
+/**
+ * Example function that wants to keep track of
+ * the event time of each message sent.
+ */
+public class UserMetricWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+
+        for (Record<String> record : inputs) {
+            if (record.getEventTime().isPresent()) {
+                context.recordMetric("MessageEventTime", record.getEventTime().get().doubleValue());
+            }
+        }
+
+        return null;
+    }
+}
+```
+
+## User config
+
+When you run or update Pulsar Functions that are created using SDK, you can pass arbitrary key/value pairs to them with the `--user-config` flag. Key/value pairs **must** be specified as JSON. 
+
+This example passes a user configured key/value to a function.
+
+```bash
+bin/pulsar-admin functions create \
+  --name word-filter \
+ --user-config '{"forbidden-word":"rosebud"}' \
+  # Other function configs
+```
+
+### API
+You can use the following APIs to get user-defined information for window functions.
+#### getUserConfigMap
+
+`getUserConfigMap` API gets a map of all user-defined key/value configurations for the window function.
+
+
+```java
+/**
+     * Get a map of all user-defined key/value configs for the function.
+     *
+     * @return The full map of user-defined config values
+     */
+    Map<String, Object> getUserConfigMap();
+```
+
+
+#### getUserConfigValue
+
+The `getUserConfigValue` API gets a user-defined key/value.
+
+```java
+/**
+     * Get any user-defined key/value.
+     *
+     * @param key The key
+     * @return The Optional value specified by the user for that key.
+     */
+    Optional<Object> getUserConfigValue(String key);
+```
+
+#### getUserConfigValueOrDefault
+
+The `getUserConfigValueOrDefault` API gets a user-defined key/value or a default value if none is present.
+
+```java
+/**
+     * Get any user-defined key/value or a default value if none is present.
+     *
+     * @param key
+     * @param defaultValue
+     * @return Either the user config value associated with a given key or a supplied default value
+     */
+    Object getUserConfigValueOrDefault(String key, Object defaultValue);
+```
+
+This example demonstrates how to access key/value pairs provided to Pulsar window functions.
+
+Java SDK context object enables you to access key/value pairs provided to Pulsar window functions via the command line (as JSON). 
+
+>**Tip**
+>
+> For all key/value pairs passed to Java window functions, both the `key` and the `value` are `String`. To set the value to be a different type, you need to deserialize it from the `String` type.
+
+This example passes a key/value pair in a Java window function.
+
+```bash
+bin/pulsar-admin functions create \
+   --user-config '{"word-of-the-day":"verdure"}' \
+  # Other function configs
+ ```
+
+This example accesses values in a Java window function.
+
+The `UserConfigFunction` function logs the string `"The word of the day is verdure"` every time the function is invoked (which means every time a message arrives). The user config of `word-of-the-day` is changed **only** when the function is updated with a new config value via 
+multiple ways, such as the command line tool or REST API.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+import org.slf4j.Logger;
+
+import java.util.Optional;
+
+public class UserConfigWindowFunction implements WindowFunction<String, String> {
+    @Override
+    public String process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        Optional<Object> whatToWrite = context.getUserConfigValue("WhatToWrite");
+        if (whatToWrite.get() != null) {
+            return (String)whatToWrite.get();
+        } else {
+            return "Not a nice way";
+        }
+    }
+
+}
+```
+
+If no value is provided, you can access the entire user config map or set a default value.
+
+```java
+// Get the whole config map
+Map<String, String> allConfigs = context.getUserConfigMap();
+
+// Get value or resort to default
+String wotd = context.getUserConfigValueOrDefault("word-of-the-day", "perspicacious");
+```
+
+## Routing
+
+You can use the `context.publish()` interface to publish as many results as you want.
+
+This example shows that the `PublishFunction` class uses the built-in function in the context to publish messages to the `publishTopic` in a Java function.
+
+```java
+public class PublishWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        String publishTopic = (String) context.getUserConfigValueOrDefault("publish-topic", "publishtopic");
+        String output = String.format("%s!", input);
+        context.publish(publishTopic, output);
+
+        return null;
+    }
+
+}
+```
+
+## State storage
+
+Pulsar window functions use [Apache BookKeeper](https://bookkeeper.apache.org) as a state storage interface. Apache Pulsar installation (including the standalone installation) includes the deployment of BookKeeper bookies.
+
+Apache Pulsar integrates with Apache BookKeeper `table service` to store the `state` for functions. For example, the `WordCount` function can store its `counters` state into BookKeeper table service via Pulsar Functions state APIs.
+
+States are key-value pairs, where the key is a string and the value is arbitrary binary data—counters are stored as 64-bit big-endian binary values. Keys are scoped to an individual Pulsar Function and shared between instances of that function.
+
+Currently, Pulsar window functions expose Java API to access, update, and manage states. These APIs are available in the context object when you use Java SDK functions.
+
+| Java API| Description
+|---|---
+|`incrCounter`|Increases a built-in distributed counter referred by key.
+|`getCounter`|Gets the counter value for the key.
+|`putState`|Updates the state value for the key.
+
+You can use the following APIs to access, update, and manage states in Java window functions. 
+
+#### incrCounter
+
+The `incrCounter` API increases a built-in distributed counter referred by key.
+
+Applications use the `incrCounter` API to change the counter of a given `key` by the given `amount`. If the `key` does not exist, a new key is created.
+
+```java
+    /**
+     * Increment the builtin distributed counter referred by key
+     * @param key The name of the key
+     * @param amount The amount to be incremented
+     */
+    void incrCounter(String key, long amount);
+```
+
+#### getCounter
+
+The `getCounter` API gets the counter value for the key.
+
+Applications uses the `getCounter` API to retrieve the counter of a given `key` changed by the `incrCounter` API.
+
+```java
+    /**
+     * Retrieve the counter value for the key.
+     *
+     * @param key name of the key
+     * @return the amount of the counter value for this key
+     */
+    long getCounter(String key);
+```
+
+Except the `getCounter` API, Pulsar also exposes a general key/value API (`putState`) for functions to store general key/value state.
+
+#### putState
+
+The `putState` API updates the state value for the key.
+
+```java
+    /**
+     * Update the state value for the key.
+     *
+     * @param key name of the key
+     * @param value state value of the key
+     */
+    void putState(String key, ByteBuffer value);
+```
+
+This example demonstrates how applications store states in Pulsar window functions.
+
+The logic of the `WordCountWindowFunction` is simple and straightforward.
+
+1. The function first splits the received string into multiple words using regex `\\.`.
+
+2. For each `word`, the function increments the corresponding `counter` by 1 via `incrCounter(key, amount)`.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+
+import java.util.Arrays;
+
+public class WordCountWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        for (Record<String> input : inputs) {
+            Arrays.asList(input.getValue().split("\\.")).forEach(word -> context.incrCounter(word, 1));
+        }
+        return null;
+
+    }
+}
+```
+
diff --git a/site2/website/versioned_docs/version-2.3.2/window-functions-context.md b/site2/website/versioned_docs/version-2.3.2/window-functions-context.md
new file mode 100644
index 0000000..0a4ae0e
--- /dev/null
+++ b/site2/website/versioned_docs/version-2.3.2/window-functions-context.md
@@ -0,0 +1,529 @@
+---
+id: version-2.3.2-window-functions-context
+title: Window Functions Context
+sidebar_label: "Window Functions: Context"
+original_id: window-functions-context
+---
+
+Java SDK provides access to a **window context object** that can be used by a window function. This context object provides a wide variety of information and functionality for Pulsar window functions as below.
+
+- [Spec](#spec)
+
+  * Names of all input topics and the output topic associated with the function.
+  * Tenant and namespace associated with the function.
+  * Pulsar window function name, ID, and version.
+  * ID of the Pulsar function instance running the window function.
+  * Number of instances that invoke the window function.
+  * Built-in type or custom class name of the output schema.
+  
+- [Logger](#logger)
+  
+  * Logger object used by the window function, which can be used to create window function log messages.
+
+- [User config](#user-config)
+  
+  * Access to arbitrary user configuration values.
+
+- [Routing](#routing)
+  
+  * Routing is supported in Pulsar window functions. Pulsar window functions send messages to arbitrary topics as per the `publish` interface.
+
+- [Metrics](#metrics)
+  
+  * Interface for recording metrics.
+
+- [State storage](#state-storage)
+  
+  * Interface for storing and retrieving state in [state storage](#state-storage).
+
+## Spec
+
+Spec contains the basic information of a function.
+
+### Get input topics
+
+The `getInputTopics` method gets the **name list** of all input topics.
+
+This example demonstrates how to get the name list of all input topics in a Java window function.
+
+```java
+public class GetInputTopicsWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Collection<String> inputTopics = context.getInputTopics();
+        System.out.println(inputTopics);
+
+        return null;
+    }
+
+}
+```
+
+### Get output topic
+
+The `getOutputTopic` method gets the **name of a topic** to which the message is sent.
+
+This example demonstrates how to get the name of an output topic in a Java window function.
+
+```java
+public class GetOutputTopicWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String outputTopic = context.getOutputTopic();
+        System.out.println(outputTopic);
+
+        return null;
+    }
+}
+```
+
+### Get tenant
+
+The `getTenant` method gets the tenant name associated with the window function.
+
+This example demonstrates how to get the tenant name in a Java window function.
+
+```java
+public class GetTenantWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String tenant = context.getTenant();
+        System.out.println(tenant);
+
+        return null;
+    }
+
+}
+```
+
+### Get namespace
+
+The `getNamespace` method gets the namespace associated with the window function.
+
+This example demonstrates how to get the namespace in a Java window function.
+
+```java
+public class GetNamespaceWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String ns = context.getNamespace();
+        System.out.println(ns);
+
+        return null;
+    }
+
+}
+```
+
+### Get function name
+
+The `getFunctionName` method gets the window function name.
+
+This example demonstrates how to get the function name in a Java window function.
+
+```java
+public class GetNameOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionName = context.getFunctionName();
+        System.out.println(functionName);
+
+        return null;
+    }
+
+}
+```
+
+### Get function ID
+
+The `getFunctionId` method gets the window function ID.
+
+This example demonstrates how to get the function ID in a Java window function.
+
+```java
+public class GetFunctionIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionID = context.getFunctionId();
+        System.out.println(functionID);
+
+        return null;
+    }
+
+}
+```
+
+### Get function version
+
+The `getFunctionVersion` method gets the window function version.
+
+This example demonstrates how to get the function version of a Java window function.
+
+```java
+public class GetVersionOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionVersion = context.getFunctionVersion();
+        System.out.println(functionVersion);
+
+        return null;
+    }
+
+}
+```
+
+### Get instance ID
+
+The `getInstanceId` method gets the instance ID of a window function.
+
+This example demonstrates how to get the instance ID in a Java window function.
+
+```java
+public class GetInstanceIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int instanceId = context.getInstanceId();
+        System.out.println(instanceId);
+
+        return null;
+    }
+
+}
+```
+
+### Get num instances
+
+The `getNumInstances` method gets the number of instances that invoke the window function.
+
+This example demonstrates how to get the number of instances in a Java window function.
+
+```java
+public class GetNumInstancesWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int numInstances = context.getNumInstances();
+        System.out.println(numInstances);
+
+        return null;
+    }
+
+}
+```
+
+### Get output schema type
+
+The `getOutputSchemaType` method gets the built-in type or custom class name of the output schema.
+
+This example demonstrates how to get the output schema type of a Java window function.
+
+```java
+public class GetOutputSchemaTypeWindowFunction implements WindowFunction<String, Void> {
+
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String schemaType = context.getOutputSchemaType();
+        System.out.println(schemaType);
+
+        return null;
+    }
+}
+```
+
+## Logger
+
+Pulsar window functions using Java SDK has access to an [SLF4j](https://www.slf4j.org/) [`Logger`](https://www.slf4j.org/api/org/apache/log4j/Logger.html) object that can be used to produce logs at the chosen log level.
+
+This example logs either a `WARNING`-level or `INFO`-level log based on whether the incoming string contains the word `danger` or not in a Java function.
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+import org.slf4j.Logger;
+
+public class LoggingWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Logger log = context.getLogger();
+        for (Record<String> record : inputs) {
+            log.info(record + "-window-log");
+        }
+        return null;
+    }
+
+}
+```
+
+If you need your function to produce logs, specify a log topic when creating or running the function. 
+
+```bash
+bin/pulsar-admin functions create \
+  --jar my-functions.jar \
+  --classname my.package.LoggingFunction \
+  --log-topic persistent://public/default/logging-function-logs \
+  # Other function configs
+```
+
+You can access all logs produced by `LoggingFunction` via the `persistent://public/default/logging-function-logs` topic.
+
+## Metrics
+
+Pulsar window functions can publish arbitrary metrics to the metrics interface which can be queried. 
+
+> **Note**
+>
+> If a Pulsar window function uses the language-native interface for Java, that function is not able to publish metrics and stats to Pulsar.
+
+You can record metrics using the context object on a per-key basis. 
+
+This example sets a metric for the `process-count` key and a different metric for the `elevens-count` key every time the function processes a message in a Java function. 
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+
+
+/**
+ * Example function that wants to keep track of
+ * the event time of each message sent.
+ */
+public class UserMetricWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+
+        for (Record<String> record : inputs) {
+            if (record.getEventTime().isPresent()) {
+                context.recordMetric("MessageEventTime", record.getEventTime().get().doubleValue());
+            }
+        }
+
+        return null;
+    }
+}
+```
+
+## User config
+
+When you run or update Pulsar Functions that are created using SDK, you can pass arbitrary key/value pairs to them with the `--user-config` flag. Key/value pairs **must** be specified as JSON. 
+
+This example passes a user configured key/value to a function.
+
+```bash
+bin/pulsar-admin functions create \
+  --name word-filter \
+ --user-config '{"forbidden-word":"rosebud"}' \
+  # Other function configs
+```
+
+### API
+You can use the following APIs to get user-defined information for window functions.
+#### getUserConfigMap
+
+`getUserConfigMap` API gets a map of all user-defined key/value configurations for the window function.
+
+
+```java
+/**
+     * Get a map of all user-defined key/value configs for the function.
+     *
+     * @return The full map of user-defined config values
+     */
+    Map<String, Object> getUserConfigMap();
+```
+
+
+#### getUserConfigValue
+
+The `getUserConfigValue` API gets a user-defined key/value.
+
+```java
+/**
+     * Get any user-defined key/value.
+     *
+     * @param key The key
+     * @return The Optional value specified by the user for that key.
+     */
+    Optional<Object> getUserConfigValue(String key);
+```
+
+#### getUserConfigValueOrDefault
+
+The `getUserConfigValueOrDefault` API gets a user-defined key/value or a default value if none is present.
+
+```java
+/**
+     * Get any user-defined key/value or a default value if none is present.
+     *
+     * @param key
+     * @param defaultValue
+     * @return Either the user config value associated with a given key or a supplied default value
+     */
+    Object getUserConfigValueOrDefault(String key, Object defaultValue);
+```
+
+This example demonstrates how to access key/value pairs provided to Pulsar window functions.
+
+Java SDK context object enables you to access key/value pairs provided to Pulsar window functions via the command line (as JSON). 
+
+>**Tip**
+>
+> For all key/value pairs passed to Java window functions, both the `key` and the `value` are `String`. To set the value to be a different type, you need to deserialize it from the `String` type.
+
+This example passes a key/value pair in a Java window function.
+
+```bash
+bin/pulsar-admin functions create \
+   --user-config '{"word-of-the-day":"verdure"}' \
+  # Other function configs
+ ```
+
+This example accesses values in a Java window function.
+
+The `UserConfigFunction` function logs the string `"The word of the day is verdure"` every time the function is invoked (which means every time a message arrives). The user config of `word-of-the-day` is changed **only** when the function is updated with a new config value via 
+multiple ways, such as the command line tool or REST API.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+import org.slf4j.Logger;
+
+import java.util.Optional;
+
+public class UserConfigWindowFunction implements WindowFunction<String, String> {
+    @Override
+    public String process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        Optional<Object> whatToWrite = context.getUserConfigValue("WhatToWrite");
+        if (whatToWrite.get() != null) {
+            return (String)whatToWrite.get();
+        } else {
+            return "Not a nice way";
+        }
+    }
+
+}
+```
+
+If no value is provided, you can access the entire user config map or set a default value.
+
+```java
+// Get the whole config map
+Map<String, String> allConfigs = context.getUserConfigMap();
+
+// Get value or resort to default
+String wotd = context.getUserConfigValueOrDefault("word-of-the-day", "perspicacious");
+```
+
+## Routing
+
+You can use the `context.publish()` interface to publish as many results as you want.
+
+This example shows that the `PublishFunction` class uses the built-in function in the context to publish messages to the `publishTopic` in a Java function.
+
+```java
+public class PublishWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        String publishTopic = (String) context.getUserConfigValueOrDefault("publish-topic", "publishtopic");
+        String output = String.format("%s!", input);
+        context.publish(publishTopic, output);
+
+        return null;
+    }
+
+}
+```
+
+## State storage
+
+Pulsar window functions use [Apache BookKeeper](https://bookkeeper.apache.org) as a state storage interface. Apache Pulsar installation (including the standalone installation) includes the deployment of BookKeeper bookies.
+
+Apache Pulsar integrates with Apache BookKeeper `table service` to store the `state` for functions. For example, the `WordCount` function can store its `counters` state into BookKeeper table service via Pulsar Functions state APIs.
+
+States are key-value pairs, where the key is a string and the value is arbitrary binary data—counters are stored as 64-bit big-endian binary values. Keys are scoped to an individual Pulsar Function and shared between instances of that function.
+
+Currently, Pulsar window functions expose Java API to access, update, and manage states. These APIs are available in the context object when you use Java SDK functions.
+
+| Java API| Description
+|---|---
+|`incrCounter`|Increases a built-in distributed counter referred by key.
+|`getCounter`|Gets the counter value for the key.
+|`putState`|Updates the state value for the key.
+
+You can use the following APIs to access, update, and manage states in Java window functions. 
+
+#### incrCounter
+
+The `incrCounter` API increases a built-in distributed counter referred by key.
+
+Applications use the `incrCounter` API to change the counter of a given `key` by the given `amount`. If the `key` does not exist, a new key is created.
+
+```java
+    /**
+     * Increment the builtin distributed counter referred by key
+     * @param key The name of the key
+     * @param amount The amount to be incremented
+     */
+    void incrCounter(String key, long amount);
+```
+
+#### getCounter
+
+The `getCounter` API gets the counter value for the key.
+
+Applications uses the `getCounter` API to retrieve the counter of a given `key` changed by the `incrCounter` API.
+
+```java
+    /**
+     * Retrieve the counter value for the key.
+     *
+     * @param key name of the key
+     * @return the amount of the counter value for this key
+     */
+    long getCounter(String key);
+```
+
+Except the `getCounter` API, Pulsar also exposes a general key/value API (`putState`) for functions to store general key/value state.
+
+#### putState
+
+The `putState` API updates the state value for the key.
+
+```java
+    /**
+     * Update the state value for the key.
+     *
+     * @param key name of the key
+     * @param value state value of the key
+     */
+    void putState(String key, ByteBuffer value);
+```
+
+This example demonstrates how applications store states in Pulsar window functions.
+
+The logic of the `WordCountWindowFunction` is simple and straightforward.
+
+1. The function first splits the received string into multiple words using regex `\\.`.
+
+2. For each `word`, the function increments the corresponding `counter` by 1 via `incrCounter(key, amount)`.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+
+import java.util.Arrays;
+
+public class WordCountWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        for (Record<String> input : inputs) {
+            Arrays.asList(input.getValue().split("\\.")).forEach(word -> context.incrCounter(word, 1));
+        }
+        return null;
+
+    }
+}
+```
+
diff --git a/site2/website/versioned_docs/version-2.4.0/window-functions-context.md b/site2/website/versioned_docs/version-2.4.0/window-functions-context.md
new file mode 100644
index 0000000..f1a72e0
--- /dev/null
+++ b/site2/website/versioned_docs/version-2.4.0/window-functions-context.md
@@ -0,0 +1,529 @@
+---
+id: version-2.4.0-window-functions-context
+title: Window Functions Context
+sidebar_label: "Window Functions: Context"
+original_id: window-functions-context
+---
+
+Java SDK provides access to a **window context object** that can be used by a window function. This context object provides a wide variety of information and functionality for Pulsar window functions as below.
+
+- [Spec](#spec)
+
+  * Names of all input topics and the output topic associated with the function.
+  * Tenant and namespace associated with the function.
+  * Pulsar window function name, ID, and version.
+  * ID of the Pulsar function instance running the window function.
+  * Number of instances that invoke the window function.
+  * Built-in type or custom class name of the output schema.
+  
+- [Logger](#logger)
+  
+  * Logger object used by the window function, which can be used to create window function log messages.
+
+- [User config](#user-config)
+  
+  * Access to arbitrary user configuration values.
+
+- [Routing](#routing)
+  
+  * Routing is supported in Pulsar window functions. Pulsar window functions send messages to arbitrary topics as per the `publish` interface.
+
+- [Metrics](#metrics)
+  
+  * Interface for recording metrics.
+
+- [State storage](#state-storage)
+  
+  * Interface for storing and retrieving state in [state storage](#state-storage).
+
+## Spec
+
+Spec contains the basic information of a function.
+
+### Get input topics
+
+The `getInputTopics` method gets the **name list** of all input topics.
+
+This example demonstrates how to get the name list of all input topics in a Java window function.
+
+```java
+public class GetInputTopicsWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Collection<String> inputTopics = context.getInputTopics();
+        System.out.println(inputTopics);
+
+        return null;
+    }
+
+}
+```
+
+### Get output topic
+
+The `getOutputTopic` method gets the **name of a topic** to which the message is sent.
+
+This example demonstrates how to get the name of an output topic in a Java window function.
+
+```java
+public class GetOutputTopicWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String outputTopic = context.getOutputTopic();
+        System.out.println(outputTopic);
+
+        return null;
+    }
+}
+```
+
+### Get tenant
+
+The `getTenant` method gets the tenant name associated with the window function.
+
+This example demonstrates how to get the tenant name in a Java window function.
+
+```java
+public class GetTenantWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String tenant = context.getTenant();
+        System.out.println(tenant);
+
+        return null;
+    }
+
+}
+```
+
+### Get namespace
+
+The `getNamespace` method gets the namespace associated with the window function.
+
+This example demonstrates how to get the namespace in a Java window function.
+
+```java
+public class GetNamespaceWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String ns = context.getNamespace();
+        System.out.println(ns);
+
+        return null;
+    }
+
+}
+```
+
+### Get function name
+
+The `getFunctionName` method gets the window function name.
+
+This example demonstrates how to get the function name in a Java window function.
+
+```java
+public class GetNameOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionName = context.getFunctionName();
+        System.out.println(functionName);
+
+        return null;
+    }
+
+}
+```
+
+### Get function ID
+
+The `getFunctionId` method gets the window function ID.
+
+This example demonstrates how to get the function ID in a Java window function.
+
+```java
+public class GetFunctionIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionID = context.getFunctionId();
+        System.out.println(functionID);
+
+        return null;
+    }
+
+}
+```
+
+### Get function version
+
+The `getFunctionVersion` method gets the window function version.
+
+This example demonstrates how to get the function version of a Java window function.
+
+```java
+public class GetVersionOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionVersion = context.getFunctionVersion();
+        System.out.println(functionVersion);
+
+        return null;
+    }
+
+}
+```
+
+### Get instance ID
+
+The `getInstanceId` method gets the instance ID of a window function.
+
+This example demonstrates how to get the instance ID in a Java window function.
+
+```java
+public class GetInstanceIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int instanceId = context.getInstanceId();
+        System.out.println(instanceId);
+
+        return null;
+    }
+
+}
+```
+
+### Get num instances
+
+The `getNumInstances` method gets the number of instances that invoke the window function.
+
+This example demonstrates how to get the number of instances in a Java window function.
+
+```java
+public class GetNumInstancesWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int numInstances = context.getNumInstances();
+        System.out.println(numInstances);
+
+        return null;
+    }
+
+}
+```
+
+### Get output schema type
+
+The `getOutputSchemaType` method gets the built-in type or custom class name of the output schema.
+
+This example demonstrates how to get the output schema type of a Java window function.
+
+```java
+public class GetOutputSchemaTypeWindowFunction implements WindowFunction<String, Void> {
+
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String schemaType = context.getOutputSchemaType();
+        System.out.println(schemaType);
+
+        return null;
+    }
+}
+```
+
+## Logger
+
+Pulsar window functions using Java SDK has access to an [SLF4j](https://www.slf4j.org/) [`Logger`](https://www.slf4j.org/api/org/apache/log4j/Logger.html) object that can be used to produce logs at the chosen log level.
+
+This example logs either a `WARNING`-level or `INFO`-level log based on whether the incoming string contains the word `danger` or not in a Java function.
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+import org.slf4j.Logger;
+
+public class LoggingWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Logger log = context.getLogger();
+        for (Record<String> record : inputs) {
+            log.info(record + "-window-log");
+        }
+        return null;
+    }
+
+}
+```
+
+If you need your function to produce logs, specify a log topic when creating or running the function. 
+
+```bash
+bin/pulsar-admin functions create \
+  --jar my-functions.jar \
+  --classname my.package.LoggingFunction \
+  --log-topic persistent://public/default/logging-function-logs \
+  # Other function configs
+```
+
+You can access all logs produced by `LoggingFunction` via the `persistent://public/default/logging-function-logs` topic.
+
+## Metrics
+
+Pulsar window functions can publish arbitrary metrics to the metrics interface which can be queried. 
+
+> **Note**
+>
+> If a Pulsar window function uses the language-native interface for Java, that function is not able to publish metrics and stats to Pulsar.
+
+You can record metrics using the context object on a per-key basis. 
+
+This example sets a metric for the `process-count` key and a different metric for the `elevens-count` key every time the function processes a message in a Java function. 
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+
+
+/**
+ * Example function that wants to keep track of
+ * the event time of each message sent.
+ */
+public class UserMetricWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+
+        for (Record<String> record : inputs) {
+            if (record.getEventTime().isPresent()) {
+                context.recordMetric("MessageEventTime", record.getEventTime().get().doubleValue());
+            }
+        }
+
+        return null;
+    }
+}
+```
+
+## User config
+
+When you run or update Pulsar Functions that are created using SDK, you can pass arbitrary key/value pairs to them with the `--user-config` flag. Key/value pairs **must** be specified as JSON. 
+
+This example passes a user configured key/value to a function.
+
+```bash
+bin/pulsar-admin functions create \
+  --name word-filter \
+ --user-config '{"forbidden-word":"rosebud"}' \
+  # Other function configs
+```
+
+### API
+You can use the following APIs to get user-defined information for window functions.
+#### getUserConfigMap
+
+`getUserConfigMap` API gets a map of all user-defined key/value configurations for the window function.
+
+
+```java
+/**
+     * Get a map of all user-defined key/value configs for the function.
+     *
+     * @return The full map of user-defined config values
+     */
+    Map<String, Object> getUserConfigMap();
+```
+
+
+#### getUserConfigValue
+
+The `getUserConfigValue` API gets a user-defined key/value.
+
+```java
+/**
+     * Get any user-defined key/value.
+     *
+     * @param key The key
+     * @return The Optional value specified by the user for that key.
+     */
+    Optional<Object> getUserConfigValue(String key);
+```
+
+#### getUserConfigValueOrDefault
+
+The `getUserConfigValueOrDefault` API gets a user-defined key/value or a default value if none is present.
+
+```java
+/**
+     * Get any user-defined key/value or a default value if none is present.
+     *
+     * @param key
+     * @param defaultValue
+     * @return Either the user config value associated with a given key or a supplied default value
+     */
+    Object getUserConfigValueOrDefault(String key, Object defaultValue);
+```
+
+This example demonstrates how to access key/value pairs provided to Pulsar window functions.
+
+Java SDK context object enables you to access key/value pairs provided to Pulsar window functions via the command line (as JSON). 
+
+>**Tip**
+>
+> For all key/value pairs passed to Java window functions, both the `key` and the `value` are `String`. To set the value to be a different type, you need to deserialize it from the `String` type.
+
+This example passes a key/value pair in a Java window function.
+
+```bash
+bin/pulsar-admin functions create \
+   --user-config '{"word-of-the-day":"verdure"}' \
+  # Other function configs
+ ```
+
+This example accesses values in a Java window function.
+
+The `UserConfigFunction` function logs the string `"The word of the day is verdure"` every time the function is invoked (which means every time a message arrives). The user config of `word-of-the-day` is changed **only** when the function is updated with a new config value via 
+multiple ways, such as the command line tool or REST API.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+import org.slf4j.Logger;
+
+import java.util.Optional;
+
+public class UserConfigWindowFunction implements WindowFunction<String, String> {
+    @Override
+    public String process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        Optional<Object> whatToWrite = context.getUserConfigValue("WhatToWrite");
+        if (whatToWrite.get() != null) {
+            return (String)whatToWrite.get();
+        } else {
+            return "Not a nice way";
+        }
+    }
+
+}
+```
+
+If no value is provided, you can access the entire user config map or set a default value.
+
+```java
+// Get the whole config map
+Map<String, String> allConfigs = context.getUserConfigMap();
+
+// Get value or resort to default
+String wotd = context.getUserConfigValueOrDefault("word-of-the-day", "perspicacious");
+```
+
+## Routing
+
+You can use the `context.publish()` interface to publish as many results as you want.
+
+This example shows that the `PublishFunction` class uses the built-in function in the context to publish messages to the `publishTopic` in a Java function.
+
+```java
+public class PublishWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        String publishTopic = (String) context.getUserConfigValueOrDefault("publish-topic", "publishtopic");
+        String output = String.format("%s!", input);
+        context.publish(publishTopic, output);
+
+        return null;
+    }
+
+}
+```
+
+## State storage
+
+Pulsar window functions use [Apache BookKeeper](https://bookkeeper.apache.org) as a state storage interface. Apache Pulsar installation (including the standalone installation) includes the deployment of BookKeeper bookies.
+
+Apache Pulsar integrates with Apache BookKeeper `table service` to store the `state` for functions. For example, the `WordCount` function can store its `counters` state into BookKeeper table service via Pulsar Functions state APIs.
+
+States are key-value pairs, where the key is a string and the value is arbitrary binary data—counters are stored as 64-bit big-endian binary values. Keys are scoped to an individual Pulsar Function and shared between instances of that function.
+
+Currently, Pulsar window functions expose Java API to access, update, and manage states. These APIs are available in the context object when you use Java SDK functions.
+
+| Java API| Description
+|---|---
+|`incrCounter`|Increases a built-in distributed counter referred by key.
+|`getCounter`|Gets the counter value for the key.
+|`putState`|Updates the state value for the key.
+
+You can use the following APIs to access, update, and manage states in Java window functions. 
+
+#### incrCounter
+
+The `incrCounter` API increases a built-in distributed counter referred by key.
+
+Applications use the `incrCounter` API to change the counter of a given `key` by the given `amount`. If the `key` does not exist, a new key is created.
+
+```java
+    /**
+     * Increment the builtin distributed counter referred by key
+     * @param key The name of the key
+     * @param amount The amount to be incremented
+     */
+    void incrCounter(String key, long amount);
+```
+
+#### getCounter
+
+The `getCounter` API gets the counter value for the key.
+
+Applications uses the `getCounter` API to retrieve the counter of a given `key` changed by the `incrCounter` API.
+
+```java
+    /**
+     * Retrieve the counter value for the key.
+     *
+     * @param key name of the key
+     * @return the amount of the counter value for this key
+     */
+    long getCounter(String key);
+```
+
+Except the `getCounter` API, Pulsar also exposes a general key/value API (`putState`) for functions to store general key/value state.
+
+#### putState
+
+The `putState` API updates the state value for the key.
+
+```java
+    /**
+     * Update the state value for the key.
+     *
+     * @param key name of the key
+     * @param value state value of the key
+     */
+    void putState(String key, ByteBuffer value);
+```
+
+This example demonstrates how applications store states in Pulsar window functions.
+
+The logic of the `WordCountWindowFunction` is simple and straightforward.
+
+1. The function first splits the received string into multiple words using regex `\\.`.
+
+2. For each `word`, the function increments the corresponding `counter` by 1 via `incrCounter(key, amount)`.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+
+import java.util.Arrays;
+
+public class WordCountWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        for (Record<String> input : inputs) {
+            Arrays.asList(input.getValue().split("\\.")).forEach(word -> context.incrCounter(word, 1));
+        }
+        return null;
+
+    }
+}
+```
+
diff --git a/site2/website/versioned_docs/version-2.4.1/window-functions-context.md b/site2/website/versioned_docs/version-2.4.1/window-functions-context.md
new file mode 100644
index 0000000..e0b0e36
--- /dev/null
+++ b/site2/website/versioned_docs/version-2.4.1/window-functions-context.md
@@ -0,0 +1,529 @@
+---
+id: version-2.4.1-window-functions-context
+title: Window Functions Context
+sidebar_label: "Window Functions: Context"
+original_id: window-functions-context
+---
+
+Java SDK provides access to a **window context object** that can be used by a window function. This context object provides a wide variety of information and functionality for Pulsar window functions as below.
+
+- [Spec](#spec)
+
+  * Names of all input topics and the output topic associated with the function.
+  * Tenant and namespace associated with the function.
+  * Pulsar window function name, ID, and version.
+  * ID of the Pulsar function instance running the window function.
+  * Number of instances that invoke the window function.
+  * Built-in type or custom class name of the output schema.
+  
+- [Logger](#logger)
+  
+  * Logger object used by the window function, which can be used to create window function log messages.
+
+- [User config](#user-config)
+  
+  * Access to arbitrary user configuration values.
+
+- [Routing](#routing)
+  
+  * Routing is supported in Pulsar window functions. Pulsar window functions send messages to arbitrary topics as per the `publish` interface.
+
+- [Metrics](#metrics)
+  
+  * Interface for recording metrics.
+
+- [State storage](#state-storage)
+  
+  * Interface for storing and retrieving state in [state storage](#state-storage).
+
+## Spec
+
+Spec contains the basic information of a function.
+
+### Get input topics
+
+The `getInputTopics` method gets the **name list** of all input topics.
+
+This example demonstrates how to get the name list of all input topics in a Java window function.
+
+```java
+public class GetInputTopicsWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Collection<String> inputTopics = context.getInputTopics();
+        System.out.println(inputTopics);
+
+        return null;
+    }
+
+}
+```
+
+### Get output topic
+
+The `getOutputTopic` method gets the **name of a topic** to which the message is sent.
+
+This example demonstrates how to get the name of an output topic in a Java window function.
+
+```java
+public class GetOutputTopicWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String outputTopic = context.getOutputTopic();
+        System.out.println(outputTopic);
+
+        return null;
+    }
+}
+```
+
+### Get tenant
+
+The `getTenant` method gets the tenant name associated with the window function.
+
+This example demonstrates how to get the tenant name in a Java window function.
+
+```java
+public class GetTenantWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String tenant = context.getTenant();
+        System.out.println(tenant);
+
+        return null;
+    }
+
+}
+```
+
+### Get namespace
+
+The `getNamespace` method gets the namespace associated with the window function.
+
+This example demonstrates how to get the namespace in a Java window function.
+
+```java
+public class GetNamespaceWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String ns = context.getNamespace();
+        System.out.println(ns);
+
+        return null;
+    }
+
+}
+```
+
+### Get function name
+
+The `getFunctionName` method gets the window function name.
+
+This example demonstrates how to get the function name in a Java window function.
+
+```java
+public class GetNameOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionName = context.getFunctionName();
+        System.out.println(functionName);
+
+        return null;
+    }
+
+}
+```
+
+### Get function ID
+
+The `getFunctionId` method gets the window function ID.
+
+This example demonstrates how to get the function ID in a Java window function.
+
+```java
+public class GetFunctionIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionID = context.getFunctionId();
+        System.out.println(functionID);
+
+        return null;
+    }
+
+}
+```
+
+### Get function version
+
+The `getFunctionVersion` method gets the window function version.
+
+This example demonstrates how to get the function version of a Java window function.
+
+```java
+public class GetVersionOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionVersion = context.getFunctionVersion();
+        System.out.println(functionVersion);
+
+        return null;
+    }
+
+}
+```
+
+### Get instance ID
+
+The `getInstanceId` method gets the instance ID of a window function.
+
+This example demonstrates how to get the instance ID in a Java window function.
+
+```java
+public class GetInstanceIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int instanceId = context.getInstanceId();
+        System.out.println(instanceId);
+
+        return null;
+    }
+
+}
+```
+
+### Get num instances
+
+The `getNumInstances` method gets the number of instances that invoke the window function.
+
+This example demonstrates how to get the number of instances in a Java window function.
+
+```java
+public class GetNumInstancesWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int numInstances = context.getNumInstances();
+        System.out.println(numInstances);
+
+        return null;
+    }
+
+}
+```
+
+### Get output schema type
+
+The `getOutputSchemaType` method gets the built-in type or custom class name of the output schema.
+
+This example demonstrates how to get the output schema type of a Java window function.
+
+```java
+public class GetOutputSchemaTypeWindowFunction implements WindowFunction<String, Void> {
+
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String schemaType = context.getOutputSchemaType();
+        System.out.println(schemaType);
+
+        return null;
+    }
+}
+```
+
+## Logger
+
+Pulsar window functions using Java SDK has access to an [SLF4j](https://www.slf4j.org/) [`Logger`](https://www.slf4j.org/api/org/apache/log4j/Logger.html) object that can be used to produce logs at the chosen log level.
+
+This example logs either a `WARNING`-level or `INFO`-level log based on whether the incoming string contains the word `danger` or not in a Java function.
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+import org.slf4j.Logger;
+
+public class LoggingWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Logger log = context.getLogger();
+        for (Record<String> record : inputs) {
+            log.info(record + "-window-log");
+        }
+        return null;
+    }
+
+}
+```
+
+If you need your function to produce logs, specify a log topic when creating or running the function. 
+
+```bash
+bin/pulsar-admin functions create \
+  --jar my-functions.jar \
+  --classname my.package.LoggingFunction \
+  --log-topic persistent://public/default/logging-function-logs \
+  # Other function configs
+```
+
+You can access all logs produced by `LoggingFunction` via the `persistent://public/default/logging-function-logs` topic.
+
+## Metrics
+
+Pulsar window functions can publish arbitrary metrics to the metrics interface which can be queried. 
+
+> **Note**
+>
+> If a Pulsar window function uses the language-native interface for Java, that function is not able to publish metrics and stats to Pulsar.
+
+You can record metrics using the context object on a per-key basis. 
+
+This example sets a metric for the `process-count` key and a different metric for the `elevens-count` key every time the function processes a message in a Java function. 
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+
+
+/**
+ * Example function that wants to keep track of
+ * the event time of each message sent.
+ */
+public class UserMetricWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+
+        for (Record<String> record : inputs) {
+            if (record.getEventTime().isPresent()) {
+                context.recordMetric("MessageEventTime", record.getEventTime().get().doubleValue());
+            }
+        }
+
+        return null;
+    }
+}
+```
+
+## User config
+
+When you run or update Pulsar Functions that are created using SDK, you can pass arbitrary key/value pairs to them with the `--user-config` flag. Key/value pairs **must** be specified as JSON. 
+
+This example passes a user configured key/value to a function.
+
+```bash
+bin/pulsar-admin functions create \
+  --name word-filter \
+ --user-config '{"forbidden-word":"rosebud"}' \
+  # Other function configs
+```
+
+### API
+You can use the following APIs to get user-defined information for window functions.
+#### getUserConfigMap
+
+`getUserConfigMap` API gets a map of all user-defined key/value configurations for the window function.
+
+
+```java
+/**
+     * Get a map of all user-defined key/value configs for the function.
+     *
+     * @return The full map of user-defined config values
+     */
+    Map<String, Object> getUserConfigMap();
+```
+
+
+#### getUserConfigValue
+
+The `getUserConfigValue` API gets a user-defined key/value.
+
+```java
+/**
+     * Get any user-defined key/value.
+     *
+     * @param key The key
+     * @return The Optional value specified by the user for that key.
+     */
+    Optional<Object> getUserConfigValue(String key);
+```
+
+#### getUserConfigValueOrDefault
+
+The `getUserConfigValueOrDefault` API gets a user-defined key/value or a default value if none is present.
+
+```java
+/**
+     * Get any user-defined key/value or a default value if none is present.
+     *
+     * @param key
+     * @param defaultValue
+     * @return Either the user config value associated with a given key or a supplied default value
+     */
+    Object getUserConfigValueOrDefault(String key, Object defaultValue);
+```
+
+This example demonstrates how to access key/value pairs provided to Pulsar window functions.
+
+Java SDK context object enables you to access key/value pairs provided to Pulsar window functions via the command line (as JSON). 
+
+>**Tip**
+>
+> For all key/value pairs passed to Java window functions, both the `key` and the `value` are `String`. To set the value to be a different type, you need to deserialize it from the `String` type.
+
+This example passes a key/value pair in a Java window function.
+
+```bash
+bin/pulsar-admin functions create \
+   --user-config '{"word-of-the-day":"verdure"}' \
+  # Other function configs
+ ```
+
+This example accesses values in a Java window function.
+
+The `UserConfigFunction` function logs the string `"The word of the day is verdure"` every time the function is invoked (which means every time a message arrives). The user config of `word-of-the-day` is changed **only** when the function is updated with a new config value via 
+multiple ways, such as the command line tool or REST API.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+import org.slf4j.Logger;
+
+import java.util.Optional;
+
+public class UserConfigWindowFunction implements WindowFunction<String, String> {
+    @Override
+    public String process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        Optional<Object> whatToWrite = context.getUserConfigValue("WhatToWrite");
+        if (whatToWrite.get() != null) {
+            return (String)whatToWrite.get();
+        } else {
+            return "Not a nice way";
+        }
+    }
+
+}
+```
+
+If no value is provided, you can access the entire user config map or set a default value.
+
+```java
+// Get the whole config map
+Map<String, String> allConfigs = context.getUserConfigMap();
+
+// Get value or resort to default
+String wotd = context.getUserConfigValueOrDefault("word-of-the-day", "perspicacious");
+```
+
+## Routing
+
+You can use the `context.publish()` interface to publish as many results as you want.
+
+This example shows that the `PublishFunction` class uses the built-in function in the context to publish messages to the `publishTopic` in a Java function.
+
+```java
+public class PublishWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        String publishTopic = (String) context.getUserConfigValueOrDefault("publish-topic", "publishtopic");
+        String output = String.format("%s!", input);
+        context.publish(publishTopic, output);
+
+        return null;
+    }
+
+}
+```
+
+## State storage
+
+Pulsar window functions use [Apache BookKeeper](https://bookkeeper.apache.org) as a state storage interface. Apache Pulsar installation (including the standalone installation) includes the deployment of BookKeeper bookies.
+
+Apache Pulsar integrates with Apache BookKeeper `table service` to store the `state` for functions. For example, the `WordCount` function can store its `counters` state into BookKeeper table service via Pulsar Functions state APIs.
+
+States are key-value pairs, where the key is a string and the value is arbitrary binary data—counters are stored as 64-bit big-endian binary values. Keys are scoped to an individual Pulsar Function and shared between instances of that function.
+
+Currently, Pulsar window functions expose Java API to access, update, and manage states. These APIs are available in the context object when you use Java SDK functions.
+
+| Java API| Description
+|---|---
+|`incrCounter`|Increases a built-in distributed counter referred by key.
+|`getCounter`|Gets the counter value for the key.
+|`putState`|Updates the state value for the key.
+
+You can use the following APIs to access, update, and manage states in Java window functions. 
+
+#### incrCounter
+
+The `incrCounter` API increases a built-in distributed counter referred by key.
+
+Applications use the `incrCounter` API to change the counter of a given `key` by the given `amount`. If the `key` does not exist, a new key is created.
+
+```java
+    /**
+     * Increment the builtin distributed counter referred by key
+     * @param key The name of the key
+     * @param amount The amount to be incremented
+     */
+    void incrCounter(String key, long amount);
+```
+
+#### getCounter
+
+The `getCounter` API gets the counter value for the key.
+
+Applications uses the `getCounter` API to retrieve the counter of a given `key` changed by the `incrCounter` API.
+
+```java
+    /**
+     * Retrieve the counter value for the key.
+     *
+     * @param key name of the key
+     * @return the amount of the counter value for this key
+     */
+    long getCounter(String key);
+```
+
+Except the `getCounter` API, Pulsar also exposes a general key/value API (`putState`) for functions to store general key/value state.
+
+#### putState
+
+The `putState` API updates the state value for the key.
+
+```java
+    /**
+     * Update the state value for the key.
+     *
+     * @param key name of the key
+     * @param value state value of the key
+     */
+    void putState(String key, ByteBuffer value);
+```
+
+This example demonstrates how applications store states in Pulsar window functions.
+
+The logic of the `WordCountWindowFunction` is simple and straightforward.
+
+1. The function first splits the received string into multiple words using regex `\\.`.
+
+2. For each `word`, the function increments the corresponding `counter` by 1 via `incrCounter(key, amount)`.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+
+import java.util.Arrays;
+
+public class WordCountWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        for (Record<String> input : inputs) {
+            Arrays.asList(input.getValue().split("\\.")).forEach(word -> context.incrCounter(word, 1));
+        }
+        return null;
+
+    }
+}
+```
+
diff --git a/site2/website/versioned_docs/version-2.4.2/window-functions-context.md b/site2/website/versioned_docs/version-2.4.2/window-functions-context.md
new file mode 100644
index 0000000..1faa230
--- /dev/null
+++ b/site2/website/versioned_docs/version-2.4.2/window-functions-context.md
@@ -0,0 +1,529 @@
+---
+id: version-2.4.2-window-functions-context
+title: Window Functions Context
+sidebar_label: "Window Functions: Context"
+original_id: window-functions-context
+---
+
+Java SDK provides access to a **window context object** that can be used by a window function. This context object provides a wide variety of information and functionality for Pulsar window functions as below.
+
+- [Spec](#spec)
+
+  * Names of all input topics and the output topic associated with the function.
+  * Tenant and namespace associated with the function.
+  * Pulsar window function name, ID, and version.
+  * ID of the Pulsar function instance running the window function.
+  * Number of instances that invoke the window function.
+  * Built-in type or custom class name of the output schema.
+  
+- [Logger](#logger)
+  
+  * Logger object used by the window function, which can be used to create window function log messages.
+
+- [User config](#user-config)
+  
+  * Access to arbitrary user configuration values.
+
+- [Routing](#routing)
+  
+  * Routing is supported in Pulsar window functions. Pulsar window functions send messages to arbitrary topics as per the `publish` interface.
+
+- [Metrics](#metrics)
+  
+  * Interface for recording metrics.
+
+- [State storage](#state-storage)
+  
+  * Interface for storing and retrieving state in [state storage](#state-storage).
+
+## Spec
+
+Spec contains the basic information of a function.
+
+### Get input topics
+
+The `getInputTopics` method gets the **name list** of all input topics.
+
+This example demonstrates how to get the name list of all input topics in a Java window function.
+
+```java
+public class GetInputTopicsWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Collection<String> inputTopics = context.getInputTopics();
+        System.out.println(inputTopics);
+
+        return null;
+    }
+
+}
+```
+
+### Get output topic
+
+The `getOutputTopic` method gets the **name of a topic** to which the message is sent.
+
+This example demonstrates how to get the name of an output topic in a Java window function.
+
+```java
+public class GetOutputTopicWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String outputTopic = context.getOutputTopic();
+        System.out.println(outputTopic);
+
+        return null;
+    }
+}
+```
+
+### Get tenant
+
+The `getTenant` method gets the tenant name associated with the window function.
+
+This example demonstrates how to get the tenant name in a Java window function.
+
+```java
+public class GetTenantWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String tenant = context.getTenant();
+        System.out.println(tenant);
+
+        return null;
+    }
+
+}
+```
+
+### Get namespace
+
+The `getNamespace` method gets the namespace associated with the window function.
+
+This example demonstrates how to get the namespace in a Java window function.
+
+```java
+public class GetNamespaceWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String ns = context.getNamespace();
+        System.out.println(ns);
+
+        return null;
+    }
+
+}
+```
+
+### Get function name
+
+The `getFunctionName` method gets the window function name.
+
+This example demonstrates how to get the function name in a Java window function.
+
+```java
+public class GetNameOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionName = context.getFunctionName();
+        System.out.println(functionName);
+
+        return null;
+    }
+
+}
+```
+
+### Get function ID
+
+The `getFunctionId` method gets the window function ID.
+
+This example demonstrates how to get the function ID in a Java window function.
+
+```java
+public class GetFunctionIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionID = context.getFunctionId();
+        System.out.println(functionID);
+
+        return null;
+    }
+
+}
+```
+
+### Get function version
+
+The `getFunctionVersion` method gets the window function version.
+
+This example demonstrates how to get the function version of a Java window function.
+
+```java
+public class GetVersionOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionVersion = context.getFunctionVersion();
+        System.out.println(functionVersion);
+
+        return null;
+    }
+
+}
+```
+
+### Get instance ID
+
+The `getInstanceId` method gets the instance ID of a window function.
+
+This example demonstrates how to get the instance ID in a Java window function.
+
+```java
+public class GetInstanceIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int instanceId = context.getInstanceId();
+        System.out.println(instanceId);
+
+        return null;
+    }
+
+}
+```
+
+### Get num instances
+
+The `getNumInstances` method gets the number of instances that invoke the window function.
+
+This example demonstrates how to get the number of instances in a Java window function.
+
+```java
+public class GetNumInstancesWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int numInstances = context.getNumInstances();
+        System.out.println(numInstances);
+
+        return null;
+    }
+
+}
+```
+
+### Get output schema type
+
+The `getOutputSchemaType` method gets the built-in type or custom class name of the output schema.
+
+This example demonstrates how to get the output schema type of a Java window function.
+
+```java
+public class GetOutputSchemaTypeWindowFunction implements WindowFunction<String, Void> {
+
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String schemaType = context.getOutputSchemaType();
+        System.out.println(schemaType);
+
+        return null;
+    }
+}
+```
+
+## Logger
+
+Pulsar window functions using Java SDK has access to an [SLF4j](https://www.slf4j.org/) [`Logger`](https://www.slf4j.org/api/org/apache/log4j/Logger.html) object that can be used to produce logs at the chosen log level.
+
+This example logs either a `WARNING`-level or `INFO`-level log based on whether the incoming string contains the word `danger` or not in a Java function.
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+import org.slf4j.Logger;
+
+public class LoggingWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Logger log = context.getLogger();
+        for (Record<String> record : inputs) {
+            log.info(record + "-window-log");
+        }
+        return null;
+    }
+
+}
+```
+
+If you need your function to produce logs, specify a log topic when creating or running the function. 
+
+```bash
+bin/pulsar-admin functions create \
+  --jar my-functions.jar \
+  --classname my.package.LoggingFunction \
+  --log-topic persistent://public/default/logging-function-logs \
+  # Other function configs
+```
+
+You can access all logs produced by `LoggingFunction` via the `persistent://public/default/logging-function-logs` topic.
+
+## Metrics
+
+Pulsar window functions can publish arbitrary metrics to the metrics interface which can be queried. 
+
+> **Note**
+>
+> If a Pulsar window function uses the language-native interface for Java, that function is not able to publish metrics and stats to Pulsar.
+
+You can record metrics using the context object on a per-key basis. 
+
+This example sets a metric for the `process-count` key and a different metric for the `elevens-count` key every time the function processes a message in a Java function. 
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+
+
+/**
+ * Example function that wants to keep track of
+ * the event time of each message sent.
+ */
+public class UserMetricWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+
+        for (Record<String> record : inputs) {
+            if (record.getEventTime().isPresent()) {
+                context.recordMetric("MessageEventTime", record.getEventTime().get().doubleValue());
+            }
+        }
+
+        return null;
+    }
+}
+```
+
+## User config
+
+When you run or update Pulsar Functions that are created using SDK, you can pass arbitrary key/value pairs to them with the `--user-config` flag. Key/value pairs **must** be specified as JSON. 
+
+This example passes a user configured key/value to a function.
+
+```bash
+bin/pulsar-admin functions create \
+  --name word-filter \
+ --user-config '{"forbidden-word":"rosebud"}' \
+  # Other function configs
+```
+
+### API
+You can use the following APIs to get user-defined information for window functions.
+#### getUserConfigMap
+
+`getUserConfigMap` API gets a map of all user-defined key/value configurations for the window function.
+
+
+```java
+/**
+     * Get a map of all user-defined key/value configs for the function.
+     *
+     * @return The full map of user-defined config values
+     */
+    Map<String, Object> getUserConfigMap();
+```
+
+
+#### getUserConfigValue
+
+The `getUserConfigValue` API gets a user-defined key/value.
+
+```java
+/**
+     * Get any user-defined key/value.
+     *
+     * @param key The key
+     * @return The Optional value specified by the user for that key.
+     */
+    Optional<Object> getUserConfigValue(String key);
+```
+
+#### getUserConfigValueOrDefault
+
+The `getUserConfigValueOrDefault` API gets a user-defined key/value or a default value if none is present.
+
+```java
+/**
+     * Get any user-defined key/value or a default value if none is present.
+     *
+     * @param key
+     * @param defaultValue
+     * @return Either the user config value associated with a given key or a supplied default value
+     */
+    Object getUserConfigValueOrDefault(String key, Object defaultValue);
+```
+
+This example demonstrates how to access key/value pairs provided to Pulsar window functions.
+
+Java SDK context object enables you to access key/value pairs provided to Pulsar window functions via the command line (as JSON). 
+
+>**Tip**
+>
+> For all key/value pairs passed to Java window functions, both the `key` and the `value` are `String`. To set the value to be a different type, you need to deserialize it from the `String` type.
+
+This example passes a key/value pair in a Java window function.
+
+```bash
+bin/pulsar-admin functions create \
+   --user-config '{"word-of-the-day":"verdure"}' \
+  # Other function configs
+ ```
+
+This example accesses values in a Java window function.
+
+The `UserConfigFunction` function logs the string `"The word of the day is verdure"` every time the function is invoked (which means every time a message arrives). The user config of `word-of-the-day` is changed **only** when the function is updated with a new config value via 
+multiple ways, such as the command line tool or REST API.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+import org.slf4j.Logger;
+
+import java.util.Optional;
+
+public class UserConfigWindowFunction implements WindowFunction<String, String> {
+    @Override
+    public String process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        Optional<Object> whatToWrite = context.getUserConfigValue("WhatToWrite");
+        if (whatToWrite.get() != null) {
+            return (String)whatToWrite.get();
+        } else {
+            return "Not a nice way";
+        }
+    }
+
+}
+```
+
+If no value is provided, you can access the entire user config map or set a default value.
+
+```java
+// Get the whole config map
+Map<String, String> allConfigs = context.getUserConfigMap();
+
+// Get value or resort to default
+String wotd = context.getUserConfigValueOrDefault("word-of-the-day", "perspicacious");
+```
+
+## Routing
+
+You can use the `context.publish()` interface to publish as many results as you want.
+
+This example shows that the `PublishFunction` class uses the built-in function in the context to publish messages to the `publishTopic` in a Java function.
+
+```java
+public class PublishWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        String publishTopic = (String) context.getUserConfigValueOrDefault("publish-topic", "publishtopic");
+        String output = String.format("%s!", input);
+        context.publish(publishTopic, output);
+
+        return null;
+    }
+
+}
+```
+
+## State storage
+
+Pulsar window functions use [Apache BookKeeper](https://bookkeeper.apache.org) as a state storage interface. Apache Pulsar installation (including the standalone installation) includes the deployment of BookKeeper bookies.
+
+Apache Pulsar integrates with Apache BookKeeper `table service` to store the `state` for functions. For example, the `WordCount` function can store its `counters` state into BookKeeper table service via Pulsar Functions state APIs.
+
+States are key-value pairs, where the key is a string and the value is arbitrary binary data—counters are stored as 64-bit big-endian binary values. Keys are scoped to an individual Pulsar Function and shared between instances of that function.
+
+Currently, Pulsar window functions expose Java API to access, update, and manage states. These APIs are available in the context object when you use Java SDK functions.
+
+| Java API| Description
+|---|---
+|`incrCounter`|Increases a built-in distributed counter referred by key.
+|`getCounter`|Gets the counter value for the key.
+|`putState`|Updates the state value for the key.
+
+You can use the following APIs to access, update, and manage states in Java window functions. 
+
+#### incrCounter
+
+The `incrCounter` API increases a built-in distributed counter referred by key.
+
+Applications use the `incrCounter` API to change the counter of a given `key` by the given `amount`. If the `key` does not exist, a new key is created.
+
+```java
+    /**
+     * Increment the builtin distributed counter referred by key
+     * @param key The name of the key
+     * @param amount The amount to be incremented
+     */
+    void incrCounter(String key, long amount);
+```
+
+#### getCounter
+
+The `getCounter` API gets the counter value for the key.
+
+Applications uses the `getCounter` API to retrieve the counter of a given `key` changed by the `incrCounter` API.
+
+```java
+    /**
+     * Retrieve the counter value for the key.
+     *
+     * @param key name of the key
+     * @return the amount of the counter value for this key
+     */
+    long getCounter(String key);
+```
+
+Except the `getCounter` API, Pulsar also exposes a general key/value API (`putState`) for functions to store general key/value state.
+
+#### putState
+
+The `putState` API updates the state value for the key.
+
+```java
+    /**
+     * Update the state value for the key.
+     *
+     * @param key name of the key
+     * @param value state value of the key
+     */
+    void putState(String key, ByteBuffer value);
+```
+
+This example demonstrates how applications store states in Pulsar window functions.
+
+The logic of the `WordCountWindowFunction` is simple and straightforward.
+
+1. The function first splits the received string into multiple words using regex `\\.`.
+
+2. For each `word`, the function increments the corresponding `counter` by 1 via `incrCounter(key, amount)`.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+
+import java.util.Arrays;
+
+public class WordCountWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        for (Record<String> input : inputs) {
+            Arrays.asList(input.getValue().split("\\.")).forEach(word -> context.incrCounter(word, 1));
+        }
+        return null;
+
+    }
+}
+```
+
diff --git a/site2/website/versioned_docs/version-2.5.0/window-functions-context.md b/site2/website/versioned_docs/version-2.5.0/window-functions-context.md
new file mode 100644
index 0000000..d9dfd21
--- /dev/null
+++ b/site2/website/versioned_docs/version-2.5.0/window-functions-context.md
@@ -0,0 +1,529 @@
+---
+id: version-2.5.0-window-functions-context
+title: Window Functions Context
+sidebar_label: "Window Functions: Context"
+original_id: window-functions-context
+---
+
+Java SDK provides access to a **window context object** that can be used by a window function. This context object provides a wide variety of information and functionality for Pulsar window functions as below.
+
+- [Spec](#spec)
+
+  * Names of all input topics and the output topic associated with the function.
+  * Tenant and namespace associated with the function.
+  * Pulsar window function name, ID, and version.
+  * ID of the Pulsar function instance running the window function.
+  * Number of instances that invoke the window function.
+  * Built-in type or custom class name of the output schema.
+  
+- [Logger](#logger)
+  
+  * Logger object used by the window function, which can be used to create window function log messages.
+
+- [User config](#user-config)
+  
+  * Access to arbitrary user configuration values.
+
+- [Routing](#routing)
+  
+  * Routing is supported in Pulsar window functions. Pulsar window functions send messages to arbitrary topics as per the `publish` interface.
+
+- [Metrics](#metrics)
+  
+  * Interface for recording metrics.
+
+- [State storage](#state-storage)
+  
+  * Interface for storing and retrieving state in [state storage](#state-storage).
+
+## Spec
+
+Spec contains the basic information of a function.
+
+### Get input topics
+
+The `getInputTopics` method gets the **name list** of all input topics.
+
+This example demonstrates how to get the name list of all input topics in a Java window function.
+
+```java
+public class GetInputTopicsWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Collection<String> inputTopics = context.getInputTopics();
+        System.out.println(inputTopics);
+
+        return null;
+    }
+
+}
+```
+
+### Get output topic
+
+The `getOutputTopic` method gets the **name of a topic** to which the message is sent.
+
+This example demonstrates how to get the name of an output topic in a Java window function.
+
+```java
+public class GetOutputTopicWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String outputTopic = context.getOutputTopic();
+        System.out.println(outputTopic);
+
+        return null;
+    }
+}
+```
+
+### Get tenant
+
+The `getTenant` method gets the tenant name associated with the window function.
+
+This example demonstrates how to get the tenant name in a Java window function.
+
+```java
+public class GetTenantWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String tenant = context.getTenant();
+        System.out.println(tenant);
+
+        return null;
+    }
+
+}
+```
+
+### Get namespace
+
+The `getNamespace` method gets the namespace associated with the window function.
+
+This example demonstrates how to get the namespace in a Java window function.
+
+```java
+public class GetNamespaceWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String ns = context.getNamespace();
+        System.out.println(ns);
+
+        return null;
+    }
+
+}
+```
+
+### Get function name
+
+The `getFunctionName` method gets the window function name.
+
+This example demonstrates how to get the function name in a Java window function.
+
+```java
+public class GetNameOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionName = context.getFunctionName();
+        System.out.println(functionName);
+
+        return null;
+    }
+
+}
+```
+
+### Get function ID
+
+The `getFunctionId` method gets the window function ID.
+
+This example demonstrates how to get the function ID in a Java window function.
+
+```java
+public class GetFunctionIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionID = context.getFunctionId();
+        System.out.println(functionID);
+
+        return null;
+    }
+
+}
+```
+
+### Get function version
+
+The `getFunctionVersion` method gets the window function version.
+
+This example demonstrates how to get the function version of a Java window function.
+
+```java
+public class GetVersionOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionVersion = context.getFunctionVersion();
+        System.out.println(functionVersion);
+
+        return null;
+    }
+
+}
+```
+
+### Get instance ID
+
+The `getInstanceId` method gets the instance ID of a window function.
+
+This example demonstrates how to get the instance ID in a Java window function.
+
+```java
+public class GetInstanceIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int instanceId = context.getInstanceId();
+        System.out.println(instanceId);
+
+        return null;
+    }
+
+}
+```
+
+### Get num instances
+
+The `getNumInstances` method gets the number of instances that invoke the window function.
+
+This example demonstrates how to get the number of instances in a Java window function.
+
+```java
+public class GetNumInstancesWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int numInstances = context.getNumInstances();
+        System.out.println(numInstances);
+
+        return null;
+    }
+
+}
+```
+
+### Get output schema type
+
+The `getOutputSchemaType` method gets the built-in type or custom class name of the output schema.
+
+This example demonstrates how to get the output schema type of a Java window function.
+
+```java
+public class GetOutputSchemaTypeWindowFunction implements WindowFunction<String, Void> {
+
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String schemaType = context.getOutputSchemaType();
+        System.out.println(schemaType);
+
+        return null;
+    }
+}
+```
+
+## Logger
+
+Pulsar window functions using Java SDK has access to an [SLF4j](https://www.slf4j.org/) [`Logger`](https://www.slf4j.org/api/org/apache/log4j/Logger.html) object that can be used to produce logs at the chosen log level.
+
+This example logs either a `WARNING`-level or `INFO`-level log based on whether the incoming string contains the word `danger` or not in a Java function.
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+import org.slf4j.Logger;
+
+public class LoggingWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Logger log = context.getLogger();
+        for (Record<String> record : inputs) {
+            log.info(record + "-window-log");
+        }
+        return null;
+    }
+
+}
+```
+
+If you need your function to produce logs, specify a log topic when creating or running the function. 
+
+```bash
+bin/pulsar-admin functions create \
+  --jar my-functions.jar \
+  --classname my.package.LoggingFunction \
+  --log-topic persistent://public/default/logging-function-logs \
+  # Other function configs
+```
+
+You can access all logs produced by `LoggingFunction` via the `persistent://public/default/logging-function-logs` topic.
+
+## Metrics
+
+Pulsar window functions can publish arbitrary metrics to the metrics interface which can be queried. 
+
+> **Note**
+>
+> If a Pulsar window function uses the language-native interface for Java, that function is not able to publish metrics and stats to Pulsar.
+
+You can record metrics using the context object on a per-key basis. 
+
+This example sets a metric for the `process-count` key and a different metric for the `elevens-count` key every time the function processes a message in a Java function. 
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+
+
+/**
+ * Example function that wants to keep track of
+ * the event time of each message sent.
+ */
+public class UserMetricWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+
+        for (Record<String> record : inputs) {
+            if (record.getEventTime().isPresent()) {
+                context.recordMetric("MessageEventTime", record.getEventTime().get().doubleValue());
+            }
+        }
+
+        return null;
+    }
+}
+```
+
+## User config
+
+When you run or update Pulsar Functions that are created using SDK, you can pass arbitrary key/value pairs to them with the `--user-config` flag. Key/value pairs **must** be specified as JSON. 
+
+This example passes a user configured key/value to a function.
+
+```bash
+bin/pulsar-admin functions create \
+  --name word-filter \
+ --user-config '{"forbidden-word":"rosebud"}' \
+  # Other function configs
+```
+
+### API
+You can use the following APIs to get user-defined information for window functions.
+#### getUserConfigMap
+
+`getUserConfigMap` API gets a map of all user-defined key/value configurations for the window function.
+
+
+```java
+/**
+     * Get a map of all user-defined key/value configs for the function.
+     *
+     * @return The full map of user-defined config values
+     */
+    Map<String, Object> getUserConfigMap();
+```
+
+
+#### getUserConfigValue
+
+The `getUserConfigValue` API gets a user-defined key/value.
+
+```java
+/**
+     * Get any user-defined key/value.
+     *
+     * @param key The key
+     * @return The Optional value specified by the user for that key.
+     */
+    Optional<Object> getUserConfigValue(String key);
+```
+
+#### getUserConfigValueOrDefault
+
+The `getUserConfigValueOrDefault` API gets a user-defined key/value or a default value if none is present.
+
+```java
+/**
+     * Get any user-defined key/value or a default value if none is present.
+     *
+     * @param key
+     * @param defaultValue
+     * @return Either the user config value associated with a given key or a supplied default value
+     */
+    Object getUserConfigValueOrDefault(String key, Object defaultValue);
+```
+
+This example demonstrates how to access key/value pairs provided to Pulsar window functions.
+
+Java SDK context object enables you to access key/value pairs provided to Pulsar window functions via the command line (as JSON). 
+
+>**Tip**
+>
+> For all key/value pairs passed to Java window functions, both the `key` and the `value` are `String`. To set the value to be a different type, you need to deserialize it from the `String` type.
+
+This example passes a key/value pair in a Java window function.
+
+```bash
+bin/pulsar-admin functions create \
+   --user-config '{"word-of-the-day":"verdure"}' \
+  # Other function configs
+ ```
+
+This example accesses values in a Java window function.
+
+The `UserConfigFunction` function logs the string `"The word of the day is verdure"` every time the function is invoked (which means every time a message arrives). The user config of `word-of-the-day` is changed **only** when the function is updated with a new config value via 
+multiple ways, such as the command line tool or REST API.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+import org.slf4j.Logger;
+
+import java.util.Optional;
+
+public class UserConfigWindowFunction implements WindowFunction<String, String> {
+    @Override
+    public String process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        Optional<Object> whatToWrite = context.getUserConfigValue("WhatToWrite");
+        if (whatToWrite.get() != null) {
+            return (String)whatToWrite.get();
+        } else {
+            return "Not a nice way";
+        }
+    }
+
+}
+```
+
+If no value is provided, you can access the entire user config map or set a default value.
+
+```java
+// Get the whole config map
+Map<String, String> allConfigs = context.getUserConfigMap();
+
+// Get value or resort to default
+String wotd = context.getUserConfigValueOrDefault("word-of-the-day", "perspicacious");
+```
+
+## Routing
+
+You can use the `context.publish()` interface to publish as many results as you want.
+
+This example shows that the `PublishFunction` class uses the built-in function in the context to publish messages to the `publishTopic` in a Java function.
+
+```java
+public class PublishWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        String publishTopic = (String) context.getUserConfigValueOrDefault("publish-topic", "publishtopic");
+        String output = String.format("%s!", input);
+        context.publish(publishTopic, output);
+
+        return null;
+    }
+
+}
+```
+
+## State storage
+
+Pulsar window functions use [Apache BookKeeper](https://bookkeeper.apache.org) as a state storage interface. Apache Pulsar installation (including the standalone installation) includes the deployment of BookKeeper bookies.
+
+Apache Pulsar integrates with Apache BookKeeper `table service` to store the `state` for functions. For example, the `WordCount` function can store its `counters` state into BookKeeper table service via Pulsar Functions state APIs.
+
+States are key-value pairs, where the key is a string and the value is arbitrary binary data—counters are stored as 64-bit big-endian binary values. Keys are scoped to an individual Pulsar Function and shared between instances of that function.
+
+Currently, Pulsar window functions expose Java API to access, update, and manage states. These APIs are available in the context object when you use Java SDK functions.
+
+| Java API| Description
+|---|---
+|`incrCounter`|Increases a built-in distributed counter referred by key.
+|`getCounter`|Gets the counter value for the key.
+|`putState`|Updates the state value for the key.
+
+You can use the following APIs to access, update, and manage states in Java window functions. 
+
+#### incrCounter
+
+The `incrCounter` API increases a built-in distributed counter referred by key.
+
+Applications use the `incrCounter` API to change the counter of a given `key` by the given `amount`. If the `key` does not exist, a new key is created.
+
+```java
+    /**
+     * Increment the builtin distributed counter referred by key
+     * @param key The name of the key
+     * @param amount The amount to be incremented
+     */
+    void incrCounter(String key, long amount);
+```
+
+#### getCounter
+
+The `getCounter` API gets the counter value for the key.
+
+Applications uses the `getCounter` API to retrieve the counter of a given `key` changed by the `incrCounter` API.
+
+```java
+    /**
+     * Retrieve the counter value for the key.
+     *
+     * @param key name of the key
+     * @return the amount of the counter value for this key
+     */
+    long getCounter(String key);
+```
+
+Except the `getCounter` API, Pulsar also exposes a general key/value API (`putState`) for functions to store general key/value state.
+
+#### putState
+
+The `putState` API updates the state value for the key.
+
+```java
+    /**
+     * Update the state value for the key.
+     *
+     * @param key name of the key
+     * @param value state value of the key
+     */
+    void putState(String key, ByteBuffer value);
+```
+
+This example demonstrates how applications store states in Pulsar window functions.
+
+The logic of the `WordCountWindowFunction` is simple and straightforward.
+
+1. The function first splits the received string into multiple words using regex `\\.`.
+
+2. For each `word`, the function increments the corresponding `counter` by 1 via `incrCounter(key, amount)`.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+
+import java.util.Arrays;
+
+public class WordCountWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        for (Record<String> input : inputs) {
+            Arrays.asList(input.getValue().split("\\.")).forEach(word -> context.incrCounter(word, 1));
+        }
+        return null;
+
+    }
+}
+```
+
diff --git a/site2/website/versioned_docs/version-2.5.1/window-functions-context.md b/site2/website/versioned_docs/version-2.5.1/window-functions-context.md
new file mode 100644
index 0000000..2541cb1
--- /dev/null
+++ b/site2/website/versioned_docs/version-2.5.1/window-functions-context.md
@@ -0,0 +1,529 @@
+---
+id: version-2.5.1-window-functions-context
+title: Window Functions Context
+sidebar_label: "Window Functions: Context"
+original_id: window-functions-context
+---
+
+Java SDK provides access to a **window context object** that can be used by a window function. This context object provides a wide variety of information and functionality for Pulsar window functions as below.
+
+- [Spec](#spec)
+
+  * Names of all input topics and the output topic associated with the function.
+  * Tenant and namespace associated with the function.
+  * Pulsar window function name, ID, and version.
+  * ID of the Pulsar function instance running the window function.
+  * Number of instances that invoke the window function.
+  * Built-in type or custom class name of the output schema.
+  
+- [Logger](#logger)
+  
+  * Logger object used by the window function, which can be used to create window function log messages.
+
+- [User config](#user-config)
+  
+  * Access to arbitrary user configuration values.
+
+- [Routing](#routing)
+  
+  * Routing is supported in Pulsar window functions. Pulsar window functions send messages to arbitrary topics as per the `publish` interface.
+
+- [Metrics](#metrics)
+  
+  * Interface for recording metrics.
+
+- [State storage](#state-storage)
+  
+  * Interface for storing and retrieving state in [state storage](#state-storage).
+
+## Spec
+
+Spec contains the basic information of a function.
+
+### Get input topics
+
+The `getInputTopics` method gets the **name list** of all input topics.
+
+This example demonstrates how to get the name list of all input topics in a Java window function.
+
+```java
+public class GetInputTopicsWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Collection<String> inputTopics = context.getInputTopics();
+        System.out.println(inputTopics);
+
+        return null;
+    }
+
+}
+```
+
+### Get output topic
+
+The `getOutputTopic` method gets the **name of a topic** to which the message is sent.
+
+This example demonstrates how to get the name of an output topic in a Java window function.
+
+```java
+public class GetOutputTopicWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String outputTopic = context.getOutputTopic();
+        System.out.println(outputTopic);
+
+        return null;
+    }
+}
+```
+
+### Get tenant
+
+The `getTenant` method gets the tenant name associated with the window function.
+
+This example demonstrates how to get the tenant name in a Java window function.
+
+```java
+public class GetTenantWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String tenant = context.getTenant();
+        System.out.println(tenant);
+
+        return null;
+    }
+
+}
+```
+
+### Get namespace
+
+The `getNamespace` method gets the namespace associated with the window function.
+
+This example demonstrates how to get the namespace in a Java window function.
+
+```java
+public class GetNamespaceWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String ns = context.getNamespace();
+        System.out.println(ns);
+
+        return null;
+    }
+
+}
+```
+
+### Get function name
+
+The `getFunctionName` method gets the window function name.
+
+This example demonstrates how to get the function name in a Java window function.
+
+```java
+public class GetNameOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionName = context.getFunctionName();
+        System.out.println(functionName);
+
+        return null;
+    }
+
+}
+```
+
+### Get function ID
+
+The `getFunctionId` method gets the window function ID.
+
+This example demonstrates how to get the function ID in a Java window function.
+
+```java
+public class GetFunctionIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionID = context.getFunctionId();
+        System.out.println(functionID);
+
+        return null;
+    }
+
+}
+```
+
+### Get function version
+
+The `getFunctionVersion` method gets the window function version.
+
+This example demonstrates how to get the function version of a Java window function.
+
+```java
+public class GetVersionOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionVersion = context.getFunctionVersion();
+        System.out.println(functionVersion);
+
+        return null;
+    }
+
+}
+```
+
+### Get instance ID
+
+The `getInstanceId` method gets the instance ID of a window function.
+
+This example demonstrates how to get the instance ID in a Java window function.
+
+```java
+public class GetInstanceIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int instanceId = context.getInstanceId();
+        System.out.println(instanceId);
+
+        return null;
+    }
+
+}
+```
+
+### Get num instances
+
+The `getNumInstances` method gets the number of instances that invoke the window function.
+
+This example demonstrates how to get the number of instances in a Java window function.
+
+```java
+public class GetNumInstancesWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int numInstances = context.getNumInstances();
+        System.out.println(numInstances);
+
+        return null;
+    }
+
+}
+```
+
+### Get output schema type
+
+The `getOutputSchemaType` method gets the built-in type or custom class name of the output schema.
+
+This example demonstrates how to get the output schema type of a Java window function.
+
+```java
+public class GetOutputSchemaTypeWindowFunction implements WindowFunction<String, Void> {
+
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String schemaType = context.getOutputSchemaType();
+        System.out.println(schemaType);
+
+        return null;
+    }
+}
+```
+
+## Logger
+
+Pulsar window functions using Java SDK has access to an [SLF4j](https://www.slf4j.org/) [`Logger`](https://www.slf4j.org/api/org/apache/log4j/Logger.html) object that can be used to produce logs at the chosen log level.
+
+This example logs either a `WARNING`-level or `INFO`-level log based on whether the incoming string contains the word `danger` or not in a Java function.
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+import org.slf4j.Logger;
+
+public class LoggingWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Logger log = context.getLogger();
+        for (Record<String> record : inputs) {
+            log.info(record + "-window-log");
+        }
+        return null;
+    }
+
+}
+```
+
+If you need your function to produce logs, specify a log topic when creating or running the function. 
+
+```bash
+bin/pulsar-admin functions create \
+  --jar my-functions.jar \
+  --classname my.package.LoggingFunction \
+  --log-topic persistent://public/default/logging-function-logs \
+  # Other function configs
+```
+
+You can access all logs produced by `LoggingFunction` via the `persistent://public/default/logging-function-logs` topic.
+
+## Metrics
+
+Pulsar window functions can publish arbitrary metrics to the metrics interface which can be queried. 
+
+> **Note**
+>
+> If a Pulsar window function uses the language-native interface for Java, that function is not able to publish metrics and stats to Pulsar.
+
+You can record metrics using the context object on a per-key basis. 
+
+This example sets a metric for the `process-count` key and a different metric for the `elevens-count` key every time the function processes a message in a Java function. 
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+
+
+/**
+ * Example function that wants to keep track of
+ * the event time of each message sent.
+ */
+public class UserMetricWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+
+        for (Record<String> record : inputs) {
+            if (record.getEventTime().isPresent()) {
+                context.recordMetric("MessageEventTime", record.getEventTime().get().doubleValue());
+            }
+        }
+
+        return null;
+    }
+}
+```
+
+## User config
+
+When you run or update Pulsar Functions that are created using SDK, you can pass arbitrary key/value pairs to them with the `--user-config` flag. Key/value pairs **must** be specified as JSON. 
+
+This example passes a user configured key/value to a function.
+
+```bash
+bin/pulsar-admin functions create \
+  --name word-filter \
+ --user-config '{"forbidden-word":"rosebud"}' \
+  # Other function configs
+```
+
+### API
+You can use the following APIs to get user-defined information for window functions.
+#### getUserConfigMap
+
+`getUserConfigMap` API gets a map of all user-defined key/value configurations for the window function.
+
+
+```java
+/**
+     * Get a map of all user-defined key/value configs for the function.
+     *
+     * @return The full map of user-defined config values
+     */
+    Map<String, Object> getUserConfigMap();
+```
+
+
+#### getUserConfigValue
+
+The `getUserConfigValue` API gets a user-defined key/value.
+
+```java
+/**
+     * Get any user-defined key/value.
+     *
+     * @param key The key
+     * @return The Optional value specified by the user for that key.
+     */
+    Optional<Object> getUserConfigValue(String key);
+```
+
+#### getUserConfigValueOrDefault
+
+The `getUserConfigValueOrDefault` API gets a user-defined key/value or a default value if none is present.
+
+```java
+/**
+     * Get any user-defined key/value or a default value if none is present.
+     *
+     * @param key
+     * @param defaultValue
+     * @return Either the user config value associated with a given key or a supplied default value
+     */
+    Object getUserConfigValueOrDefault(String key, Object defaultValue);
+```
+
+This example demonstrates how to access key/value pairs provided to Pulsar window functions.
+
+Java SDK context object enables you to access key/value pairs provided to Pulsar window functions via the command line (as JSON). 
+
+>**Tip**
+>
+> For all key/value pairs passed to Java window functions, both the `key` and the `value` are `String`. To set the value to be a different type, you need to deserialize it from the `String` type.
+
+This example passes a key/value pair in a Java window function.
+
+```bash
+bin/pulsar-admin functions create \
+   --user-config '{"word-of-the-day":"verdure"}' \
+  # Other function configs
+ ```
+
+This example accesses values in a Java window function.
+
+The `UserConfigFunction` function logs the string `"The word of the day is verdure"` every time the function is invoked (which means every time a message arrives). The user config of `word-of-the-day` is changed **only** when the function is updated with a new config value via 
+multiple ways, such as the command line tool or REST API.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+import org.slf4j.Logger;
+
+import java.util.Optional;
+
+public class UserConfigWindowFunction implements WindowFunction<String, String> {
+    @Override
+    public String process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        Optional<Object> whatToWrite = context.getUserConfigValue("WhatToWrite");
+        if (whatToWrite.get() != null) {
+            return (String)whatToWrite.get();
+        } else {
+            return "Not a nice way";
+        }
+    }
+
+}
+```
+
+If no value is provided, you can access the entire user config map or set a default value.
+
+```java
+// Get the whole config map
+Map<String, String> allConfigs = context.getUserConfigMap();
+
+// Get value or resort to default
+String wotd = context.getUserConfigValueOrDefault("word-of-the-day", "perspicacious");
+```
+
+## Routing
+
+You can use the `context.publish()` interface to publish as many results as you want.
+
+This example shows that the `PublishFunction` class uses the built-in function in the context to publish messages to the `publishTopic` in a Java function.
+
+```java
+public class PublishWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        String publishTopic = (String) context.getUserConfigValueOrDefault("publish-topic", "publishtopic");
+        String output = String.format("%s!", input);
+        context.publish(publishTopic, output);
+
+        return null;
+    }
+
+}
+```
+
+## State storage
+
+Pulsar window functions use [Apache BookKeeper](https://bookkeeper.apache.org) as a state storage interface. Apache Pulsar installation (including the standalone installation) includes the deployment of BookKeeper bookies.
+
+Apache Pulsar integrates with Apache BookKeeper `table service` to store the `state` for functions. For example, the `WordCount` function can store its `counters` state into BookKeeper table service via Pulsar Functions state APIs.
+
+States are key-value pairs, where the key is a string and the value is arbitrary binary data—counters are stored as 64-bit big-endian binary values. Keys are scoped to an individual Pulsar Function and shared between instances of that function.
+
+Currently, Pulsar window functions expose Java API to access, update, and manage states. These APIs are available in the context object when you use Java SDK functions.
+
+| Java API| Description
+|---|---
+|`incrCounter`|Increases a built-in distributed counter referred by key.
+|`getCounter`|Gets the counter value for the key.
+|`putState`|Updates the state value for the key.
+
+You can use the following APIs to access, update, and manage states in Java window functions. 
+
+#### incrCounter
+
+The `incrCounter` API increases a built-in distributed counter referred by key.
+
+Applications use the `incrCounter` API to change the counter of a given `key` by the given `amount`. If the `key` does not exist, a new key is created.
+
+```java
+    /**
+     * Increment the builtin distributed counter referred by key
+     * @param key The name of the key
+     * @param amount The amount to be incremented
+     */
+    void incrCounter(String key, long amount);
+```
+
+#### getCounter
+
+The `getCounter` API gets the counter value for the key.
+
+Applications uses the `getCounter` API to retrieve the counter of a given `key` changed by the `incrCounter` API.
+
+```java
+    /**
+     * Retrieve the counter value for the key.
+     *
+     * @param key name of the key
+     * @return the amount of the counter value for this key
+     */
+    long getCounter(String key);
+```
+
+Except the `getCounter` API, Pulsar also exposes a general key/value API (`putState`) for functions to store general key/value state.
+
+#### putState
+
+The `putState` API updates the state value for the key.
+
+```java
+    /**
+     * Update the state value for the key.
+     *
+     * @param key name of the key
+     * @param value state value of the key
+     */
+    void putState(String key, ByteBuffer value);
+```
+
+This example demonstrates how applications store states in Pulsar window functions.
+
+The logic of the `WordCountWindowFunction` is simple and straightforward.
+
+1. The function first splits the received string into multiple words using regex `\\.`.
+
+2. For each `word`, the function increments the corresponding `counter` by 1 via `incrCounter(key, amount)`.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+
+import java.util.Arrays;
+
+public class WordCountWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        for (Record<String> input : inputs) {
+            Arrays.asList(input.getValue().split("\\.")).forEach(word -> context.incrCounter(word, 1));
+        }
+        return null;
+
+    }
+}
+```
+
diff --git a/site2/website/versioned_docs/version-2.5.2/window-functions-context.md b/site2/website/versioned_docs/version-2.5.2/window-functions-context.md
new file mode 100644
index 0000000..b51add3
--- /dev/null
+++ b/site2/website/versioned_docs/version-2.5.2/window-functions-context.md
@@ -0,0 +1,529 @@
+---
+id: version-2.5.2-window-functions-context
+title: Window Functions Context
+sidebar_label: "Window Functions: Context"
+original_id: window-functions-context
+---
+
+Java SDK provides access to a **window context object** that can be used by a window function. This context object provides a wide variety of information and functionality for Pulsar window functions as below.
+
+- [Spec](#spec)
+
+  * Names of all input topics and the output topic associated with the function.
+  * Tenant and namespace associated with the function.
+  * Pulsar window function name, ID, and version.
+  * ID of the Pulsar function instance running the window function.
+  * Number of instances that invoke the window function.
+  * Built-in type or custom class name of the output schema.
+  
+- [Logger](#logger)
+  
+  * Logger object used by the window function, which can be used to create window function log messages.
+
+- [User config](#user-config)
+  
+  * Access to arbitrary user configuration values.
+
+- [Routing](#routing)
+  
+  * Routing is supported in Pulsar window functions. Pulsar window functions send messages to arbitrary topics as per the `publish` interface.
+
+- [Metrics](#metrics)
+  
+  * Interface for recording metrics.
+
+- [State storage](#state-storage)
+  
+  * Interface for storing and retrieving state in [state storage](#state-storage).
+
+## Spec
+
+Spec contains the basic information of a function.
+
+### Get input topics
+
+The `getInputTopics` method gets the **name list** of all input topics.
+
+This example demonstrates how to get the name list of all input topics in a Java window function.
+
+```java
+public class GetInputTopicsWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Collection<String> inputTopics = context.getInputTopics();
+        System.out.println(inputTopics);
+
+        return null;
+    }
+
+}
+```
+
+### Get output topic
+
+The `getOutputTopic` method gets the **name of a topic** to which the message is sent.
+
+This example demonstrates how to get the name of an output topic in a Java window function.
+
+```java
+public class GetOutputTopicWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String outputTopic = context.getOutputTopic();
+        System.out.println(outputTopic);
+
+        return null;
+    }
+}
+```
+
+### Get tenant
+
+The `getTenant` method gets the tenant name associated with the window function.
+
+This example demonstrates how to get the tenant name in a Java window function.
+
+```java
+public class GetTenantWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String tenant = context.getTenant();
+        System.out.println(tenant);
+
+        return null;
+    }
+
+}
+```
+
+### Get namespace
+
+The `getNamespace` method gets the namespace associated with the window function.
+
+This example demonstrates how to get the namespace in a Java window function.
+
+```java
+public class GetNamespaceWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String ns = context.getNamespace();
+        System.out.println(ns);
+
+        return null;
+    }
+
+}
+```
+
+### Get function name
+
+The `getFunctionName` method gets the window function name.
+
+This example demonstrates how to get the function name in a Java window function.
+
+```java
+public class GetNameOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionName = context.getFunctionName();
+        System.out.println(functionName);
+
+        return null;
+    }
+
+}
+```
+
+### Get function ID
+
+The `getFunctionId` method gets the window function ID.
+
+This example demonstrates how to get the function ID in a Java window function.
+
+```java
+public class GetFunctionIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionID = context.getFunctionId();
+        System.out.println(functionID);
+
+        return null;
+    }
+
+}
+```
+
+### Get function version
+
+The `getFunctionVersion` method gets the window function version.
+
+This example demonstrates how to get the function version of a Java window function.
+
+```java
+public class GetVersionOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionVersion = context.getFunctionVersion();
+        System.out.println(functionVersion);
+
+        return null;
+    }
+
+}
+```
+
+### Get instance ID
+
+The `getInstanceId` method gets the instance ID of a window function.
+
+This example demonstrates how to get the instance ID in a Java window function.
+
+```java
+public class GetInstanceIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int instanceId = context.getInstanceId();
+        System.out.println(instanceId);
+
+        return null;
+    }
+
+}
+```
+
+### Get num instances
+
+The `getNumInstances` method gets the number of instances that invoke the window function.
+
+This example demonstrates how to get the number of instances in a Java window function.
+
+```java
+public class GetNumInstancesWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int numInstances = context.getNumInstances();
+        System.out.println(numInstances);
+
+        return null;
+    }
+
+}
+```
+
+### Get output schema type
+
+The `getOutputSchemaType` method gets the built-in type or custom class name of the output schema.
+
+This example demonstrates how to get the output schema type of a Java window function.
+
+```java
+public class GetOutputSchemaTypeWindowFunction implements WindowFunction<String, Void> {
+
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String schemaType = context.getOutputSchemaType();
+        System.out.println(schemaType);
+
+        return null;
+    }
+}
+```
+
+## Logger
+
+Pulsar window functions using Java SDK has access to an [SLF4j](https://www.slf4j.org/) [`Logger`](https://www.slf4j.org/api/org/apache/log4j/Logger.html) object that can be used to produce logs at the chosen log level.
+
+This example logs either a `WARNING`-level or `INFO`-level log based on whether the incoming string contains the word `danger` or not in a Java function.
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+import org.slf4j.Logger;
+
+public class LoggingWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Logger log = context.getLogger();
+        for (Record<String> record : inputs) {
+            log.info(record + "-window-log");
+        }
+        return null;
+    }
+
+}
+```
+
+If you need your function to produce logs, specify a log topic when creating or running the function. 
+
+```bash
+bin/pulsar-admin functions create \
+  --jar my-functions.jar \
+  --classname my.package.LoggingFunction \
+  --log-topic persistent://public/default/logging-function-logs \
+  # Other function configs
+```
+
+You can access all logs produced by `LoggingFunction` via the `persistent://public/default/logging-function-logs` topic.
+
+## Metrics
+
+Pulsar window functions can publish arbitrary metrics to the metrics interface which can be queried. 
+
+> **Note**
+>
+> If a Pulsar window function uses the language-native interface for Java, that function is not able to publish metrics and stats to Pulsar.
+
+You can record metrics using the context object on a per-key basis. 
+
+This example sets a metric for the `process-count` key and a different metric for the `elevens-count` key every time the function processes a message in a Java function. 
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+
+
+/**
+ * Example function that wants to keep track of
+ * the event time of each message sent.
+ */
+public class UserMetricWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+
+        for (Record<String> record : inputs) {
+            if (record.getEventTime().isPresent()) {
+                context.recordMetric("MessageEventTime", record.getEventTime().get().doubleValue());
+            }
+        }
+
+        return null;
+    }
+}
+```
+
+## User config
+
+When you run or update Pulsar Functions that are created using SDK, you can pass arbitrary key/value pairs to them with the `--user-config` flag. Key/value pairs **must** be specified as JSON. 
+
+This example passes a user configured key/value to a function.
+
+```bash
+bin/pulsar-admin functions create \
+  --name word-filter \
+ --user-config '{"forbidden-word":"rosebud"}' \
+  # Other function configs
+```
+
+### API
+You can use the following APIs to get user-defined information for window functions.
+#### getUserConfigMap
+
+`getUserConfigMap` API gets a map of all user-defined key/value configurations for the window function.
+
+
+```java
+/**
+     * Get a map of all user-defined key/value configs for the function.
+     *
+     * @return The full map of user-defined config values
+     */
+    Map<String, Object> getUserConfigMap();
+```
+
+
+#### getUserConfigValue
+
+The `getUserConfigValue` API gets a user-defined key/value.
+
+```java
+/**
+     * Get any user-defined key/value.
+     *
+     * @param key The key
+     * @return The Optional value specified by the user for that key.
+     */
+    Optional<Object> getUserConfigValue(String key);
+```
+
+#### getUserConfigValueOrDefault
+
+The `getUserConfigValueOrDefault` API gets a user-defined key/value or a default value if none is present.
+
+```java
+/**
+     * Get any user-defined key/value or a default value if none is present.
+     *
+     * @param key
+     * @param defaultValue
+     * @return Either the user config value associated with a given key or a supplied default value
+     */
+    Object getUserConfigValueOrDefault(String key, Object defaultValue);
+```
+
+This example demonstrates how to access key/value pairs provided to Pulsar window functions.
+
+Java SDK context object enables you to access key/value pairs provided to Pulsar window functions via the command line (as JSON). 
+
+>**Tip**
+>
+> For all key/value pairs passed to Java window functions, both the `key` and the `value` are `String`. To set the value to be a different type, you need to deserialize it from the `String` type.
+
+This example passes a key/value pair in a Java window function.
+
+```bash
+bin/pulsar-admin functions create \
+   --user-config '{"word-of-the-day":"verdure"}' \
+  # Other function configs
+ ```
+
+This example accesses values in a Java window function.
+
+The `UserConfigFunction` function logs the string `"The word of the day is verdure"` every time the function is invoked (which means every time a message arrives). The user config of `word-of-the-day` is changed **only** when the function is updated with a new config value via 
+multiple ways, such as the command line tool or REST API.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+import org.slf4j.Logger;
+
+import java.util.Optional;
+
+public class UserConfigWindowFunction implements WindowFunction<String, String> {
+    @Override
+    public String process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        Optional<Object> whatToWrite = context.getUserConfigValue("WhatToWrite");
+        if (whatToWrite.get() != null) {
+            return (String)whatToWrite.get();
+        } else {
+            return "Not a nice way";
+        }
+    }
+
+}
+```
+
+If no value is provided, you can access the entire user config map or set a default value.
+
+```java
+// Get the whole config map
+Map<String, String> allConfigs = context.getUserConfigMap();
+
+// Get value or resort to default
+String wotd = context.getUserConfigValueOrDefault("word-of-the-day", "perspicacious");
+```
+
+## Routing
+
+You can use the `context.publish()` interface to publish as many results as you want.
+
+This example shows that the `PublishFunction` class uses the built-in function in the context to publish messages to the `publishTopic` in a Java function.
+
+```java
+public class PublishWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        String publishTopic = (String) context.getUserConfigValueOrDefault("publish-topic", "publishtopic");
+        String output = String.format("%s!", input);
+        context.publish(publishTopic, output);
+
+        return null;
+    }
+
+}
+```
+
+## State storage
+
+Pulsar window functions use [Apache BookKeeper](https://bookkeeper.apache.org) as a state storage interface. Apache Pulsar installation (including the standalone installation) includes the deployment of BookKeeper bookies.
+
+Apache Pulsar integrates with Apache BookKeeper `table service` to store the `state` for functions. For example, the `WordCount` function can store its `counters` state into BookKeeper table service via Pulsar Functions state APIs.
+
+States are key-value pairs, where the key is a string and the value is arbitrary binary data—counters are stored as 64-bit big-endian binary values. Keys are scoped to an individual Pulsar Function and shared between instances of that function.
+
+Currently, Pulsar window functions expose Java API to access, update, and manage states. These APIs are available in the context object when you use Java SDK functions.
+
+| Java API| Description
+|---|---
+|`incrCounter`|Increases a built-in distributed counter referred by key.
+|`getCounter`|Gets the counter value for the key.
+|`putState`|Updates the state value for the key.
+
+You can use the following APIs to access, update, and manage states in Java window functions. 
+
+#### incrCounter
+
+The `incrCounter` API increases a built-in distributed counter referred by key.
+
+Applications use the `incrCounter` API to change the counter of a given `key` by the given `amount`. If the `key` does not exist, a new key is created.
+
+```java
+    /**
+     * Increment the builtin distributed counter referred by key
+     * @param key The name of the key
+     * @param amount The amount to be incremented
+     */
+    void incrCounter(String key, long amount);
+```
+
+#### getCounter
+
+The `getCounter` API gets the counter value for the key.
+
+Applications uses the `getCounter` API to retrieve the counter of a given `key` changed by the `incrCounter` API.
+
+```java
+    /**
+     * Retrieve the counter value for the key.
+     *
+     * @param key name of the key
+     * @return the amount of the counter value for this key
+     */
+    long getCounter(String key);
+```
+
+Except the `getCounter` API, Pulsar also exposes a general key/value API (`putState`) for functions to store general key/value state.
+
+#### putState
+
+The `putState` API updates the state value for the key.
+
+```java
+    /**
+     * Update the state value for the key.
+     *
+     * @param key name of the key
+     * @param value state value of the key
+     */
+    void putState(String key, ByteBuffer value);
+```
+
+This example demonstrates how applications store states in Pulsar window functions.
+
+The logic of the `WordCountWindowFunction` is simple and straightforward.
+
+1. The function first splits the received string into multiple words using regex `\\.`.
+
+2. For each `word`, the function increments the corresponding `counter` by 1 via `incrCounter(key, amount)`.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+
+import java.util.Arrays;
+
+public class WordCountWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        for (Record<String> input : inputs) {
+            Arrays.asList(input.getValue().split("\\.")).forEach(word -> context.incrCounter(word, 1));
+        }
+        return null;
+
+    }
+}
+```
+
diff --git a/site2/website/versioned_docs/version-2.6.0/window-functions-context.md b/site2/website/versioned_docs/version-2.6.0/window-functions-context.md
new file mode 100644
index 0000000..f4216b9
--- /dev/null
+++ b/site2/website/versioned_docs/version-2.6.0/window-functions-context.md
@@ -0,0 +1,529 @@
+---
+id: version-2.6.0-window-functions-context
+title: Window Functions Context
+sidebar_label: "Window Functions: Context"
+original_id: window-functions-context
+---
+
+Java SDK provides access to a **window context object** that can be used by a window function. This context object provides a wide variety of information and functionality for Pulsar window functions as below.
+
+- [Spec](#spec)
+
+  * Names of all input topics and the output topic associated with the function.
+  * Tenant and namespace associated with the function.
+  * Pulsar window function name, ID, and version.
+  * ID of the Pulsar function instance running the window function.
+  * Number of instances that invoke the window function.
+  * Built-in type or custom class name of the output schema.
+  
+- [Logger](#logger)
+  
+  * Logger object used by the window function, which can be used to create window function log messages.
+
+- [User config](#user-config)
+  
+  * Access to arbitrary user configuration values.
+
+- [Routing](#routing)
+  
+  * Routing is supported in Pulsar window functions. Pulsar window functions send messages to arbitrary topics as per the `publish` interface.
+
+- [Metrics](#metrics)
+  
+  * Interface for recording metrics.
+
+- [State storage](#state-storage)
+  
+  * Interface for storing and retrieving state in [state storage](#state-storage).
+
+## Spec
+
+Spec contains the basic information of a function.
+
+### Get input topics
+
+The `getInputTopics` method gets the **name list** of all input topics.
+
+This example demonstrates how to get the name list of all input topics in a Java window function.
+
+```java
+public class GetInputTopicsWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Collection<String> inputTopics = context.getInputTopics();
+        System.out.println(inputTopics);
+
+        return null;
+    }
+
+}
+```
+
+### Get output topic
+
+The `getOutputTopic` method gets the **name of a topic** to which the message is sent.
+
+This example demonstrates how to get the name of an output topic in a Java window function.
+
+```java
+public class GetOutputTopicWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String outputTopic = context.getOutputTopic();
+        System.out.println(outputTopic);
+
+        return null;
+    }
+}
+```
+
+### Get tenant
+
+The `getTenant` method gets the tenant name associated with the window function.
+
+This example demonstrates how to get the tenant name in a Java window function.
+
+```java
+public class GetTenantWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String tenant = context.getTenant();
+        System.out.println(tenant);
+
+        return null;
+    }
+
+}
+```
+
+### Get namespace
+
+The `getNamespace` method gets the namespace associated with the window function.
+
+This example demonstrates how to get the namespace in a Java window function.
+
+```java
+public class GetNamespaceWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String ns = context.getNamespace();
+        System.out.println(ns);
+
+        return null;
+    }
+
+}
+```
+
+### Get function name
+
+The `getFunctionName` method gets the window function name.
+
+This example demonstrates how to get the function name in a Java window function.
+
+```java
+public class GetNameOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionName = context.getFunctionName();
+        System.out.println(functionName);
+
+        return null;
+    }
+
+}
+```
+
+### Get function ID
+
+The `getFunctionId` method gets the window function ID.
+
+This example demonstrates how to get the function ID in a Java window function.
+
+```java
+public class GetFunctionIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionID = context.getFunctionId();
+        System.out.println(functionID);
+
+        return null;
+    }
+
+}
+```
+
+### Get function version
+
+The `getFunctionVersion` method gets the window function version.
+
+This example demonstrates how to get the function version of a Java window function.
+
+```java
+public class GetVersionOfWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String functionVersion = context.getFunctionVersion();
+        System.out.println(functionVersion);
+
+        return null;
+    }
+
+}
+```
+
+### Get instance ID
+
+The `getInstanceId` method gets the instance ID of a window function.
+
+This example demonstrates how to get the instance ID in a Java window function.
+
+```java
+public class GetInstanceIDWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int instanceId = context.getInstanceId();
+        System.out.println(instanceId);
+
+        return null;
+    }
+
+}
+```
+
+### Get num instances
+
+The `getNumInstances` method gets the number of instances that invoke the window function.
+
+This example demonstrates how to get the number of instances in a Java window function.
+
+```java
+public class GetNumInstancesWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        int numInstances = context.getNumInstances();
+        System.out.println(numInstances);
+
+        return null;
+    }
+
+}
+```
+
+### Get output schema type
+
+The `getOutputSchemaType` method gets the built-in type or custom class name of the output schema.
+
+This example demonstrates how to get the output schema type of a Java window function.
+
+```java
+public class GetOutputSchemaTypeWindowFunction implements WindowFunction<String, Void> {
+
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        String schemaType = context.getOutputSchemaType();
+        System.out.println(schemaType);
+
+        return null;
+    }
+}
+```
+
+## Logger
+
+Pulsar window functions using Java SDK has access to an [SLF4j](https://www.slf4j.org/) [`Logger`](https://www.slf4j.org/api/org/apache/log4j/Logger.html) object that can be used to produce logs at the chosen log level.
+
+This example logs either a `WARNING`-level or `INFO`-level log based on whether the incoming string contains the word `danger` or not in a Java function.
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+import org.slf4j.Logger;
+
+public class LoggingWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        Logger log = context.getLogger();
+        for (Record<String> record : inputs) {
+            log.info(record + "-window-log");
+        }
+        return null;
+    }
+
+}
+```
+
+If you need your function to produce logs, specify a log topic when creating or running the function. 
+
+```bash
+bin/pulsar-admin functions create \
+  --jar my-functions.jar \
+  --classname my.package.LoggingFunction \
+  --log-topic persistent://public/default/logging-function-logs \
+  # Other function configs
+```
+
+You can access all logs produced by `LoggingFunction` via the `persistent://public/default/logging-function-logs` topic.
+
+## Metrics
+
+Pulsar window functions can publish arbitrary metrics to the metrics interface which can be queried. 
+
+> **Note**
+>
+> If a Pulsar window function uses the language-native interface for Java, that function is not able to publish metrics and stats to Pulsar.
+
+You can record metrics using the context object on a per-key basis. 
+
+This example sets a metric for the `process-count` key and a different metric for the `elevens-count` key every time the function processes a message in a Java function. 
+
+```java
+import java.util.Collection;
+import org.apache.pulsar.functions.api.Record;
+import org.apache.pulsar.functions.api.WindowContext;
+import org.apache.pulsar.functions.api.WindowFunction;
+
+
+/**
+ * Example function that wants to keep track of
+ * the event time of each message sent.
+ */
+public class UserMetricWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+
+        for (Record<String> record : inputs) {
+            if (record.getEventTime().isPresent()) {
+                context.recordMetric("MessageEventTime", record.getEventTime().get().doubleValue());
+            }
+        }
+
+        return null;
+    }
+}
+```
+
+## User config
+
+When you run or update Pulsar Functions that are created using SDK, you can pass arbitrary key/value pairs to them with the `--user-config` flag. Key/value pairs **must** be specified as JSON. 
+
+This example passes a user configured key/value to a function.
+
+```bash
+bin/pulsar-admin functions create \
+  --name word-filter \
+ --user-config '{"forbidden-word":"rosebud"}' \
+  # Other function configs
+```
+
+### API
+You can use the following APIs to get user-defined information for window functions.
+#### getUserConfigMap
+
+`getUserConfigMap` API gets a map of all user-defined key/value configurations for the window function.
+
+
+```java
+/**
+     * Get a map of all user-defined key/value configs for the function.
+     *
+     * @return The full map of user-defined config values
+     */
+    Map<String, Object> getUserConfigMap();
+```
+
+
+#### getUserConfigValue
+
+The `getUserConfigValue` API gets a user-defined key/value.
+
+```java
+/**
+     * Get any user-defined key/value.
+     *
+     * @param key The key
+     * @return The Optional value specified by the user for that key.
+     */
+    Optional<Object> getUserConfigValue(String key);
+```
+
+#### getUserConfigValueOrDefault
+
+The `getUserConfigValueOrDefault` API gets a user-defined key/value or a default value if none is present.
+
+```java
+/**
+     * Get any user-defined key/value or a default value if none is present.
+     *
+     * @param key
+     * @param defaultValue
+     * @return Either the user config value associated with a given key or a supplied default value
+     */
+    Object getUserConfigValueOrDefault(String key, Object defaultValue);
+```
+
+This example demonstrates how to access key/value pairs provided to Pulsar window functions.
+
+Java SDK context object enables you to access key/value pairs provided to Pulsar window functions via the command line (as JSON). 
+
+>**Tip**
+>
+> For all key/value pairs passed to Java window functions, both the `key` and the `value` are `String`. To set the value to be a different type, you need to deserialize it from the `String` type.
+
+This example passes a key/value pair in a Java window function.
+
+```bash
+bin/pulsar-admin functions create \
+   --user-config '{"word-of-the-day":"verdure"}' \
+  # Other function configs
+ ```
+
+This example accesses values in a Java window function.
+
+The `UserConfigFunction` function logs the string `"The word of the day is verdure"` every time the function is invoked (which means every time a message arrives). The user config of `word-of-the-day` is changed **only** when the function is updated with a new config value via 
+multiple ways, such as the command line tool or REST API.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+import org.slf4j.Logger;
+
+import java.util.Optional;
+
+public class UserConfigWindowFunction implements WindowFunction<String, String> {
+    @Override
+    public String process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        Optional<Object> whatToWrite = context.getUserConfigValue("WhatToWrite");
+        if (whatToWrite.get() != null) {
+            return (String)whatToWrite.get();
+        } else {
+            return "Not a nice way";
+        }
+    }
+
+}
+```
+
+If no value is provided, you can access the entire user config map or set a default value.
+
+```java
+// Get the whole config map
+Map<String, String> allConfigs = context.getUserConfigMap();
+
+// Get value or resort to default
+String wotd = context.getUserConfigValueOrDefault("word-of-the-day", "perspicacious");
+```
+
+## Routing
+
+You can use the `context.publish()` interface to publish as many results as you want.
+
+This example shows that the `PublishFunction` class uses the built-in function in the context to publish messages to the `publishTopic` in a Java function.
+
+```java
+public class PublishWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> input, WindowContext context) throws Exception {
+        String publishTopic = (String) context.getUserConfigValueOrDefault("publish-topic", "publishtopic");
+        String output = String.format("%s!", input);
+        context.publish(publishTopic, output);
+
+        return null;
+    }
+
+}
+```
+
+## State storage
+
+Pulsar window functions use [Apache BookKeeper](https://bookkeeper.apache.org) as a state storage interface. Apache Pulsar installation (including the standalone installation) includes the deployment of BookKeeper bookies.
+
+Apache Pulsar integrates with Apache BookKeeper `table service` to store the `state` for functions. For example, the `WordCount` function can store its `counters` state into BookKeeper table service via Pulsar Functions state APIs.
+
+States are key-value pairs, where the key is a string and the value is arbitrary binary data—counters are stored as 64-bit big-endian binary values. Keys are scoped to an individual Pulsar Function and shared between instances of that function.
+
+Currently, Pulsar window functions expose Java API to access, update, and manage states. These APIs are available in the context object when you use Java SDK functions.
+
+| Java API| Description
+|---|---
+|`incrCounter`|Increases a built-in distributed counter referred by key.
+|`getCounter`|Gets the counter value for the key.
+|`putState`|Updates the state value for the key.
+
+You can use the following APIs to access, update, and manage states in Java window functions. 
+
+#### incrCounter
+
+The `incrCounter` API increases a built-in distributed counter referred by key.
+
+Applications use the `incrCounter` API to change the counter of a given `key` by the given `amount`. If the `key` does not exist, a new key is created.
+
+```java
+    /**
+     * Increment the builtin distributed counter referred by key
+     * @param key The name of the key
+     * @param amount The amount to be incremented
+     */
+    void incrCounter(String key, long amount);
+```
+
+#### getCounter
+
+The `getCounter` API gets the counter value for the key.
+
+Applications uses the `getCounter` API to retrieve the counter of a given `key` changed by the `incrCounter` API.
+
+```java
+    /**
+     * Retrieve the counter value for the key.
+     *
+     * @param key name of the key
+     * @return the amount of the counter value for this key
+     */
+    long getCounter(String key);
+```
+
+Except the `getCounter` API, Pulsar also exposes a general key/value API (`putState`) for functions to store general key/value state.
+
+#### putState
+
+The `putState` API updates the state value for the key.
+
+```java
+    /**
+     * Update the state value for the key.
+     *
+     * @param key name of the key
+     * @param value state value of the key
+     */
+    void putState(String key, ByteBuffer value);
+```
+
+This example demonstrates how applications store states in Pulsar window functions.
+
+The logic of the `WordCountWindowFunction` is simple and straightforward.
+
+1. The function first splits the received string into multiple words using regex `\\.`.
+
+2. For each `word`, the function increments the corresponding `counter` by 1 via `incrCounter(key, amount)`.
+
+```java
+import org.apache.pulsar.functions.api.Context;
+import org.apache.pulsar.functions.api.Function;
+
+import java.util.Arrays;
+
+public class WordCountWindowFunction implements WindowFunction<String, Void> {
+    @Override
+    public Void process(Collection<Record<String>> inputs, WindowContext context) throws Exception {
+        for (Record<String> input : inputs) {
+            Arrays.asList(input.getValue().split("\\.")).forEach(word -> context.incrCounter(word, 1));
+        }
+        return null;
+
+    }
+}
+```
+
diff --git a/site2/website/versioned_sidebars/version-2.3.0-sidebars.json b/site2/website/versioned_sidebars/version-2.3.0-sidebars.json
index 5a66aad..4da977c 100644
--- a/site2/website/versioned_sidebars/version-2.3.0-sidebars.json
+++ b/site2/website/versioned_sidebars/version-2.3.0-sidebars.json
@@ -25,7 +25,8 @@
       "version-2.3.0-functions-deploying",
       "version-2.3.0-functions-guarantees",
       "version-2.3.0-functions-state",
-      "version-2.3.0-functions-metrics"
+      "version-2.3.0-functions-metrics",
+      "version-2.3.0-window-functions-context"
     ],
     "Pulsar IO": [
       "version-2.3.0-io-overview",
diff --git a/site2/website/versioned_sidebars/version-2.3.1-sidebars.json b/site2/website/versioned_sidebars/version-2.3.1-sidebars.json
index b732733..cd37319 100644
--- a/site2/website/versioned_sidebars/version-2.3.1-sidebars.json
+++ b/site2/website/versioned_sidebars/version-2.3.1-sidebars.json
@@ -25,7 +25,8 @@
       "version-2.3.1-functions-deploying",
       "version-2.3.1-functions-guarantees",
       "version-2.3.1-functions-state",
-      "version-2.3.1-functions-metrics"
+      "version-2.3.1-functions-metrics",
+      "version-2.3.1-window-functions-context"
     ],
     "Pulsar IO": [
       "version-2.3.1-io-overview",
diff --git a/site2/website/versioned_sidebars/version-2.3.2-sidebars.json b/site2/website/versioned_sidebars/version-2.3.2-sidebars.json
index f221ae3..16731e3 100644
--- a/site2/website/versioned_sidebars/version-2.3.2-sidebars.json
+++ b/site2/website/versioned_sidebars/version-2.3.2-sidebars.json
@@ -26,7 +26,8 @@
       "version-2.3.2-functions-guarantees",
       "version-2.3.2-functions-state",
       "version-2.3.2-functions-metrics",
-      "version-2.3.2-functions-worker"
+      "version-2.3.2-functions-worker",
+      "version-2.3.2-window-functions-context"
     ],
     "Pulsar IO": [
       "version-2.3.2-io-overview",
diff --git a/site2/website/versioned_sidebars/version-2.4.0-sidebars.json b/site2/website/versioned_sidebars/version-2.4.0-sidebars.json
index a6af729..93cef5a 100644
--- a/site2/website/versioned_sidebars/version-2.4.0-sidebars.json
+++ b/site2/website/versioned_sidebars/version-2.4.0-sidebars.json
@@ -28,7 +28,8 @@
       "version-2.4.0-functions-metrics",
       "version-2.4.0-functions-worker",
       "version-2.4.0-functions-runtime",
-      "version-2.4.0-functions-debugging"
+      "version-2.4.0-functions-debugging",
+      "version-2.4.0-window-functions-context"
     ],
     "Pulsar IO": [
       "version-2.4.0-io-overview",
diff --git a/site2/website/versioned_sidebars/version-2.4.1-sidebars.json b/site2/website/versioned_sidebars/version-2.4.1-sidebars.json
index c53d0fb..9fc7ff7 100644
--- a/site2/website/versioned_sidebars/version-2.4.1-sidebars.json
+++ b/site2/website/versioned_sidebars/version-2.4.1-sidebars.json
@@ -35,7 +35,8 @@
       "version-2.4.1-functions-monitor",
       "version-2.4.1-functions-secure",
       "version-2.4.1-functions-troubleshoot",
-      "version-2.4.1-functions-cli"
+      "version-2.4.1-functions-cli",
+      "version-2.4.1-window-functions-context"
     ],
     "Pulsar IO": [
       "version-2.4.1-io-overview",
diff --git a/site2/website/versioned_sidebars/version-2.4.2-sidebars.json b/site2/website/versioned_sidebars/version-2.4.2-sidebars.json
index e82a731..c119706 100644
--- a/site2/website/versioned_sidebars/version-2.4.2-sidebars.json
+++ b/site2/website/versioned_sidebars/version-2.4.2-sidebars.json
@@ -35,7 +35,8 @@
       "version-2.4.2-functions-monitor",
       "version-2.4.2-functions-secure",
       "version-2.4.2-functions-troubleshoot",
-      "version-2.4.2-functions-cli"
+      "version-2.4.2-functions-cli",
+      "version-2.4.2-window-functions-context"
     ],
     "Pulsar IO": [
       "version-2.4.2-io-overview",
diff --git a/site2/website/versioned_sidebars/version-2.5.0-sidebars.json b/site2/website/versioned_sidebars/version-2.5.0-sidebars.json
index 5270e22..dd98dc1 100644
--- a/site2/website/versioned_sidebars/version-2.5.0-sidebars.json
+++ b/site2/website/versioned_sidebars/version-2.5.0-sidebars.json
@@ -32,7 +32,8 @@
       "version-2.5.0-functions-develop",
       "version-2.5.0-functions-debug",
       "version-2.5.0-functions-deploy",
-      "version-2.5.0-functions-cli"
+      "version-2.5.0-functions-cli",
+      "version-2.5.0-window-functions-context"
     ],
     "Pulsar IO": [
       "version-2.5.0-io-overview",
diff --git a/site2/website/versioned_sidebars/version-2.5.1-sidebars.json b/site2/website/versioned_sidebars/version-2.5.1-sidebars.json
index e0348e1..64fbb99 100644
--- a/site2/website/versioned_sidebars/version-2.5.1-sidebars.json
+++ b/site2/website/versioned_sidebars/version-2.5.1-sidebars.json
@@ -31,7 +31,8 @@
       "version-2.5.1-functions-develop",
       "version-2.5.1-functions-debug",
       "version-2.5.1-functions-deploy",
-      "version-2.5.1-functions-cli"
+      "version-2.5.1-functions-cli",
+      "version-2.5.1-window-functions-context"
     ],
     "Pulsar IO": [
       "version-2.5.1-io-overview",
diff --git a/site2/website/versioned_sidebars/version-2.5.2-sidebars.json b/site2/website/versioned_sidebars/version-2.5.2-sidebars.json
index e97135e..c2456cc 100644
--- a/site2/website/versioned_sidebars/version-2.5.2-sidebars.json
+++ b/site2/website/versioned_sidebars/version-2.5.2-sidebars.json
@@ -31,7 +31,8 @@
       "version-2.5.2-functions-develop",
       "version-2.5.2-functions-debug",
       "version-2.5.2-functions-deploy",
-      "version-2.5.2-functions-cli"
+      "version-2.5.2-functions-cli",
+      "version-2.5.2-window-functions-context"
     ],
     "Pulsar IO": [
       "version-2.5.2-io-overview",
diff --git a/site2/website/versioned_sidebars/version-2.6.0-sidebars.json b/site2/website/versioned_sidebars/version-2.6.0-sidebars.json
new file mode 100644
index 0000000..6cd23e7
--- /dev/null
+++ b/site2/website/versioned_sidebars/version-2.6.0-sidebars.json
@@ -0,0 +1,153 @@
+{
+  "version-2.6.0-docs": {
+    "Get started": [
+      "version-2.6.0-pulsar-2.0",
+      "version-2.6.0-standalone",
+      "version-2.6.0-standalone-docker",
+      "version-2.6.0-kubernetes-helm",
+      "version-2.6.0-client-libraries"
+    ],
+    "Concepts and Architecture": [
+      "version-2.6.0-concepts-overview",
+      "version-2.6.0-concepts-messaging",
+      "version-2.6.0-concepts-architecture-overview",
+      "version-2.6.0-concepts-clients",
+      "version-2.6.0-concepts-replication",
+      "version-2.6.0-concepts-multi-tenancy",
+      "version-2.6.0-concepts-authentication",
+      "version-2.6.0-concepts-topic-compaction",
+      "version-2.6.0-concepts-tiered-storage"
+    ],
+    "Pulsar Schema": [
+      "version-2.6.0-schema-get-started",
+      "version-2.6.0-schema-understand",
+      "version-2.6.0-schema-evolution-compatibility",
+      "version-2.6.0-schema-manage"
+    ],
+    "Pulsar Functions": [
+      "version-2.6.0-functions-overview",
+      "version-2.6.0-functions-worker",
+      "version-2.6.0-functions-runtime",
+      "version-2.6.0-functions-develop",
+      "version-2.6.0-functions-debug",
+      "version-2.6.0-functions-deploy",
+      "version-2.6.0-functions-cli",
+      "version-2.6.0-window-functions-context"
+    ],
+    "Pulsar IO": [
+      "version-2.6.0-io-overview",
+      "version-2.6.0-io-quickstart",
+      "version-2.6.0-io-use",
+      "version-2.6.0-io-debug",
+      "version-2.6.0-io-connectors",
+      "version-2.6.0-io-cdc",
+      "version-2.6.0-io-develop",
+      "version-2.6.0-io-cli"
+    ],
+    "Pulsar SQL": [
+      "version-2.6.0-sql-overview",
+      "version-2.6.0-sql-getting-started",
+      "version-2.6.0-sql-deployment-configurations",
+      "version-2.6.0-sql-rest-api"
+    ],
+    "Kubernetes (Helm)": [
+      "version-2.6.0-helm-overview",
+      "version-2.6.0-helm-prepare",
+      "version-2.6.0-helm-install",
+      "version-2.6.0-helm-deploy",
+      "version-2.6.0-helm-upgrade",
+      "version-2.6.0-helm-tools"
+    ],
+    "Deployment": [
+      "version-2.6.0-deploy-aws",
+      "version-2.6.0-deploy-kubernetes",
+      "version-2.6.0-deploy-bare-metal",
+      "version-2.6.0-deploy-bare-metal-multi-cluster",
+      "version-2.6.0-deploy-dcos",
+      "version-2.6.0-deploy-monitoring"
+    ],
+    "Administration": [
+      "version-2.6.0-administration-zk-bk",
+      "version-2.6.0-administration-geo",
+      "version-2.6.0-administration-pulsar-manager",
+      "version-2.6.0-administration-stats",
+      "version-2.6.0-administration-load-balance",
+      "version-2.6.0-administration-proxy",
+      "version-2.6.0-administration-upgrade"
+    ],
+    "Security": [
+      "version-2.6.0-security-overview",
+      "version-2.6.0-security-tls-transport",
+      "version-2.6.0-security-tls-authentication",
+      "version-2.6.0-security-tls-keystore",
+      "version-2.6.0-security-jwt",
+      "version-2.6.0-security-athenz",
+      "version-2.6.0-security-kerberos",
+      "version-2.6.0-security-authorization",
+      "version-2.6.0-security-encryption",
+      "version-2.6.0-security-extending",
+      "version-2.6.0-security-bouncy-castle"
+    ],
+    "Performance": [
+      "version-2.6.0-performance-pulsar-perf"
+    ],
+    "Client libraries": [
+      "version-2.6.0-client-libraries-java",
+      "version-2.6.0-client-libraries-go",
+      "version-2.6.0-client-libraries-python",
+      "version-2.6.0-client-libraries-cpp",
+      "version-2.6.0-client-libraries-node",
+      "version-2.6.0-client-libraries-websocket",
+      "version-2.6.0-client-libraries-dotnet"
+    ],
+    "Admin API": [
+      "version-2.6.0-admin-api-overview",
+      "version-2.6.0-admin-api-clusters",
+      "version-2.6.0-admin-api-tenants",
+      "version-2.6.0-admin-api-brokers",
+      "version-2.6.0-admin-api-namespaces",
+      "version-2.6.0-admin-api-permissions",
+      "version-2.6.0-admin-api-persistent-topics",
+      "version-2.6.0-admin-api-non-persistent-topics",
+      "version-2.6.0-admin-api-partitioned-topics",
+      "version-2.6.0-admin-api-non-partitioned-topics",
+      "version-2.6.0-admin-api-schemas",
+      "version-2.6.0-admin-api-functions"
+    ],
+    "Adaptors": [
+      "version-2.6.0-adaptors-kafka",
+      "version-2.6.0-adaptors-spark",
+      "version-2.6.0-adaptors-storm"
+    ],
+    "Cookbooks": [
+      "version-2.6.0-cookbooks-tiered-storage",
+      "version-2.6.0-cookbooks-compaction",
+      "version-2.6.0-cookbooks-deduplication",
+      "version-2.6.0-cookbooks-non-persistent",
+      "version-2.6.0-cookbooks-partitioned",
+      "version-2.6.0-cookbooks-retention-expiry",
+      "version-2.6.0-cookbooks-encryption",
+      "version-2.6.0-cookbooks-message-queue",
+      "version-2.6.0-cookbooks-bookkeepermetadata"
+    ],
+    "Development": [
+      "version-2.6.0-develop-tools",
+      "version-2.6.0-develop-binary-protocol",
+      "version-2.6.0-develop-schema",
+      "version-2.6.0-develop-load-manager",
+      "version-2.6.0-develop-cpp"
+    ],
+    "Reference": [
+      "version-2.6.0-reference-terminology",
+      "version-2.6.0-reference-cli-tools",
+      "version-2.6.0-reference-configuration",
+      "version-2.6.0-reference-metrics"
+    ]
+  },
+  "version-2.6.0-docs-other": {
+    "First Category": [
+      "version-2.6.0-doc4",
+      "version-2.6.0-doc5"
+    ]
+  }
+}