**Source URL:** https://general.veevavault.dev/clinical/custom-pages/guides/developing-server-code.md

# Developing Server Code

To develop Custom Page server code with the Vault Java SDK, implement the `PageController` interface. This server code can send and receive data from the Custom Page client code in Vault. Learn more in the [Javadocs](https://repo.veevavault.com/).

All implementations of `PageController` must be decorated with `@PageControllerInfo` and `@ExecuteAs` annotations.

To deploy your Java server code, use the [Vault Java SDK Maven plugin](https://github.com/veeva/vaultjavasdk-maven-plugin). Learn more about deploying Vault Java SDK code in the [SDK documentation](/vault-sdk/getting-started/deploy-code).

## @ExecuteAs Annotation {#ExecuteAs_Annotation}

A `PageController` must use `@ExecuteAs(ExecuteAsUser.REQUEST_OWNER)` to execute as the user at the keyboard. This means all user permissions are respected when reading data to display to the user or when performing operations.

## onLoad() {#onLoad}

The `onLoad()` method executes when a user accesses the URL for the Custom Page in the browser.

The code you provide in this method can perform validation or return data to the client. This method can return data as JSON or a [User-Defined Model](#User_Defined_Models).

In the client code, [retrieve this data](/custom-pages/guides/data-management/#Loading_Server_Data) using the `data` parameter from the `definePage()` function.

## onEvent() {#onEvent}

The `onEvent()` method executes when the client code [sends an event](/custom-pages/guides/data-management/#Sending_Events) to the server code using the `sendEvent()` function.

From the `PageEventContext`, you can retrieve the name of the event and, optionally, any data passed from the client.

Write code here to process the event and, optionally, return data to the client. Data can be returned as JSON or a [User-Defined Model](#User_Defined_Models).

## Returning Errors {#Returning_Errors}

You can construct and return errors to the client when handling the `onLoad()` and `onEvent()` methods. Vault displays Page Load errors to the user. The client code should handle Page Event errors.

## Using User-Defined Models {#User_Defined_Models}

Instead of using a `JsonObject` to work with data on the server, `PageController` can work directly with a `UserDefinedModel` (UDM) to [send and receive data](/custom-pages/guides/data-management) to the client.

Both `onLoad()` and `onEvent()` can return data as a UDM.

`onLoad()`:

```
return context.newLoadResponseBuilder()
            .withData(loadResponseData, HelloWorldLoadResponse.class)
            .build();

```

`onEvent()`:

```
return context.newEventResponseBuilder()
            .withData(loadResponseData, HelloWorldEventResponse.class)
            .build();

```

The `onEvent()` method can receive data from the client as a UDM:

```
public PageEventResponse onEvent(PageEventContext context) {
    HelloWorldEvent eventData = context.getData(HelloWorldEvent.class);
    // ...
}

```

## Generating URLs to Vault Locations {#Generating_URLs}

You can generate URLs to Custom Pages using a `PageUrlRequest` from `UrlService`. You can also use `UrlService` to generate URLs to documents, object record list views, and object record detail views. Use [client navigation functions](/custom-pages/guides/data-management/#Controlling_Navigation) to navigate between Custom Pages and your generated URLs.

Add your custom URLs to the `JsonObject` response using `#setValue()`. On the client side, you can retrieve them using the `data` parameter. For example, if you add `url` to the response with a custom URL value, the client code can access it using `data.url`.

The following example creates URLs to Custom Pages, including a base URL, a subpage URL, and a list page URL with a `sortBy` query parameter. This also adds a URLs array to `urls` in the response so the client code can access it.

```
@ExecuteAs(ExecuteAsUser.REQUEST_OWNER)
@PageControllerInfo
public class IndexPageController implements PageController {
    @Override
    public PageLoadResponse onLoad(PageLoadContext context) {
        UrlService urlService = ServiceLocator.locate(UrlService.class);
        JsonService jsonService = ServiceLocator.locate(JsonService.class);

        List<String> urls = urlService.batchGetPageUrls(
            urlService.newBatchPageUrlsRequestBuilder()
                .withRequests(
                    VaultCollections.asList(
                        urlService.newPageUrlRequestBuilder()
                            .withPageName("mypage__c")
                            .build(),
                        urlService.newPageUrlRequestBuilder()
                            .withPageName("mypage__c")
                            .withPathInfo("sub-page")
                            .build(),
                        urlService.newPageUrlRequestBuilder()
                            .withPageName("listpage__c")
                            .withQueryParameter("sortBy", VaultCollections.asList("lastName"))
                            .build()
                    )
                )
                .build()
        ).getResultStream()
            .map(result -> result.getUrl().orElse(null))
            .filter(str -> str != null)
            .collect(VaultCollectors.toList());

        JsonArrayBuilder jsonUrls = jsonService.newJsonArrayBuilder();
        urls.forEach(url -> jsonUrls.add(url));

        JsonObject jsonData = jsonService.newJsonObjectBuilder()
            .setValue("urls", jsonUrls.build())
            .build();

        return context.newLoadResponseBuilder().withData(jsonData).build();
    }
}

```


---

**Previous:** [Developing Client Code](/clinical/custom-pages/guides/developing-client-code)  
**Next:** [Managing Data Flow](/clinical/custom-pages/guides/data-management)