---
title: Node class
description: The Node class can access and modify the persisted state shared between the nodes within a tree, and can request input by using callbacks. The class also defines the possible exit paths from the node.
component: pingam
version: 8.1
page_id: pingam:auth-nodes:core-class
canonical_url: https://docs.pingidentity.com/pingam/8.1/auth-nodes/core-class.html
keywords: ["Extensibility", "Nodes &amp; Trees", "Scripts"]
---

# Node class

The `Node` class can access and modify the persisted state shared between the nodes within a tree, and can request input by using callbacks. The class also defines the possible exit paths from the node.

In Java terms, an authentication node is a class that implements the `Node` interface, `org.forgerock.openam.auth.node.api.Node`.

The `UsernameCollectorNodeV2` class shows the steps to implement the Node interface:

```java
package org.forgerock.openam.auth.nodes;

import static java.util.Objects.requireNonNull;
import static org.forgerock.openam.auth.node.api.Action.send;
import static org.forgerock.openam.auth.node.api.SharedStateConstants.USERNAME;

import java.util.ResourceBundle;

import javax.inject.Inject;
import javax.security.auth.callback.NameCallback;

import org.forgerock.openam.annotations.sm.Attribute;
import org.forgerock.openam.auth.node.api.Action;
import org.forgerock.openam.auth.node.api.InputState;
import org.forgerock.openam.auth.node.api.Node;
import org.forgerock.openam.auth.node.api.OutputState;
import org.forgerock.openam.auth.node.api.SingleOutcomeNode;
import org.forgerock.openam.auth.node.api.TreeContext;
import org.forgerock.openam.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.assistedinject.Assisted;

/
 * A node that collects a username from the user using a name callback.
 *
 * <p>Allows setting of a customizable, localizable prompt and a default value retrieved from shared state</p>
 *
 * <p>Places the result in the shared state as 'username'.</p>
 /
@Node.Metadata(outcomeProvider = SingleOutcomeNode.OutcomeProvider.class,              1
        configClass = UsernameCollectorNodeV2.Config.class,
        tags = {"basic authn", "basic authentication"})
@Node.VersionMetadata(name = "UsernameCollectorNode", version = 2)                     2
public class UsernameCollectorNodeV2 extends SingleOutcomeNode {                       3

    private final Config config;                                                       4

    @Inject                                                                            5
    UsernameCollectorNodeV2(@Assisted Config config) {
        this.config = config;
    }
    /
     * Configuration for the username collector node V2.
     */
    public interface Config {                                                          6
        /*
         * If true, will prepopulate the username field with a value from shared state.
         *
         * @return Whether to prepopulate the username input field with a value from shared state
         */
        @Attribute(order = 100)
        default boolean prepopulate() {
            return false;
        }
    }

    private static final String BUNDLE = UsernameCollectorNodeV2.class.getName();
    private final Logger logger = LoggerFactory.getLogger(UsernameCollectorNodeV2.class);

    @Override                                                                          7
    public Action process(TreeContext context) {
        logger.debug("UsernameCollectorNode started");
        var nameCallback = context.getCallback(NameCallback.class);
        if (nameCallback.isPresent() && StringUtils.isNotEmpty(nameCallback.get().getName())) {
            context.getStateFor(this).putShared(USERNAME, nameCallback.get().getName());
            return goToNext().build();
        }

        return collectUsername(context);
    }

    private Action collectUsername(TreeContext context) {
        logger.debug("collecting username");
        ResourceBundle bundle = context.request.locales.getBundleInPreferredLocale(BUNDLE, getClass().getClassLoader());
        var nameCallback = new NameCallback(bundle.getString("callback.username"));
        var nodeState = context.getStateFor(this);
        if (config.prepopulate() && nodeState.isDefined(USERNAME)) {
            nameCallback.setName(requireNonNull(nodeState.get(USERNAME)).asString());
        }
        return send(nameCallback).build();
    }

    @Override
    public OutputState[] getOutputs() {
        return new OutputState[]{
                new OutputState(USERNAME)
        };
    }

    @Override
    public InputState[] getInputs() {
        return new InputState[]{
                new InputState(USERNAME)
        };
    }
}
```

| Step                                           | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             | Further information                                                                                                                                                                                                                                                                                                                    |
| ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1 Apply the `@Node.Metadata` annotation        | The `Metadata` annotation specifies the outcome provider, configuration class, and optionally, the configuration validator, extensions and tags.Use an existing outcome provider such as `SingleOutcomeNode.OutcomeProvider` or `AbstractDecisionNode.OutcomeProvider`, or create a custom provider and reference the class from the annotation.                                                                                                                                                                                                                                        | [Metadata annotation](core-metadata.html)                                                                                                                                                                                                                                                                                              |
| 2 Apply the `@Node.VersionMetadata` annotation | Create a versioned node.The `VersionMetadata` annotation specifies the name, version, and optionally, the upgrader class.                                                                                                                                                                                                                                                                                                                                                                                                                                                               | [VersionMetadata annotation](versionmetadata.html)                                                                                                                                                                                                                                                                                     |
| 3 Implement the `Node` interface               | Extend one of the following abstract classes to implement the `Node` interface:- `SingleOutcomeNode`

  For nodes with a single exit path. For example, [Modify Auth Level node](https://docs.pingidentity.com/auth-node-ref/8.1/modify-auth-level.html).

- `AbstractDecisionNode`

  For nodes with a boolean-type exit path (true/false, allow/deny). For example, [Data Store Decision node](https://docs.pingidentity.com/auth-node-ref/8.1/data-store-decision.html).Alternatively, write your own implementation of the `OutcomeProvider` interface to define custom exit paths. | Javadoc:- [Node](../_attachments/apidocs/org/forgerock/openam/auth/node/api/Node.html) interface

- [SingleOutcomeNode](../_attachments/apidocs/org/forgerock/openam/auth/node/api/SingleOutcomeNode.html) class

- [AbstractDecisionNode](../_attachments/apidocs/org/forgerock/openam/auth/node/api/AbstractDecisionNode.html) class |
| 4 Define private constants and methods         | *Optional*                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |                                                                                                                                                                                                                                                                                                                                        |
| 5 Inject dependencies                          | Inject objects using Guice as this makes it easier to unit test your node.This example specifies `config` as a parameter. You can also include supported AM classes, instances of third-party dependencies, or your own types.                                                                                                                                                                                                                                                                                                                                                          | [Inject objects into a node instance](core-inject.html)                                                                                                                                                                                                                                                                                |
| 6 Implement the `Config` interface             | The `Config` interface defines the configuration data for a node.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       | [Config interface](core-config.html)                                                                                                                                                                                                                                                                                                   |
| 7 Override the `process` method                | The `process` method is where you store and retrieve state if required.It takes a `TreeContext` parameter that you can use to access the request, callbacks, shared state and other input.The method returns an `Action` object. This can be a response or callback to the user, an update of state, or a choice of outcome. The `Action` object encapsulates changes to state and flow control.The choice of outcome in a simple decision node is `true` or `false`, resulting in the authentication tree flow moving from the current node to a node at the relevant connection.      | [Action class](core-action.html)                                                                                                                                                                                                                                                                                                       |
