Core+ Java Client

Deephaven's Core+ Java client enables you to connect to Deephaven Enterprise workers, interact with Persistent Queries (PQs), execute code, and manage workflows. The Core+ client APIs are designed to work with the Deephaven Community engine, simplifying the processes the client handles.

Setup

Setup for the Core+ Java client is typically done through Gradle. For instructions, see Core+ Java client setup.

While there are multiple ways to set up the client with tools other than Gradle, this guide uses Gradle for its simplicity and interoperability.

Get started

After completing setup, you must configure Deephaven to load properties from your Deephaven server's URL. This typically uses port 8000 when your system is configured with Envoy or port 8123 without Envoy. You must set the properties URL before using any other Deephaven classes; otherwise, static fields in classes will fail to initialize.

final String serverUrl = "https://deephaven-host:8000";

// Tell the configuration library to load configuration from the specified URL
HttpUrlPropertyInputStreamLoader.setServerUrl(serverUrl);

There are two ways you can interact with data via the Core+ Java client:

  • client-barrage: Unlocks the full power of the ticking Deephaven engine through Deephaven's Barrage extension. Requires Java 11 or later.
  • client-flight: Provides the ability to get static snapshots of tables using the Apache Arrow Flight protocol. Requires Java 8 or later.

Next, create a session that loads the connection configuration from the URL. You can use either client-barrage or client-flight:

// Create the session factory for Barrage. This creates the connections to the server and downloads the
// configuration.
final DndSessionFactoryBarrage sessionFactory = new DndSessionFactoryBarrage(serverUrl + "/iris/connection.json");
// Create the session factory for Flight. This creates the connections to the server and downloads the
// configuration.
final DndSessionFactoryFlight sessionFactory = new DndSessionFactoryFlight(serverUrl + "/iris/connection.json");

Then, authenticate with the server using a username and password:

sessionFactory.password("user", "password");

Alternatively, you can use a private key for better security:

sessionFactory.privateKey("/path/to/key_base64.txt");

Now you can connect to an existing PQ. The session object provides basic methods for interacting with tables and also gives you access to the underlying SessionImpl for direct worker interaction.

final DndSessionBarrage session = sessionFactory.persistentQuery("MyTestQuery");

Alternatively, you could create a new temporary Persistent Query to host your worker:

final DndSessionBarrage session = sessionFactory.newWorker("ExampleTestWorker", 2, 600_000, 10_000);
final DndSessionFlight session = sessionFactory.persistentQuery("MyTestQuery");

Alternatively, you could create a new temporary Persistent Query to host your worker:

final DndSessionFlight session = sessionFactory.newWorker("ExampleTestWorker", 2, 600_000, 10_000);

For more precise control over Persistent Query options, you can create a configuration object builder directly:

final PersistentQueryConfigMessage.Builder builder = sessionFactory.createPersistentQueryConfig("ExampleTestWorker", 2, 600_000);

builder.addViewerGroups("MyViewers");
builder.addAdminGroups("SomeUser");
builder.addExtraJvmArguments("-DMy.Extra.Param=27");

session = sessionFactory.newWorker(builder.build(), 10_000);
The following examples are self-contained Java clients that connect to a running Persistent Query and table.

The Gradle setup instructions provided here include the required parameters to run the included examples. A Core+ Persistent Query should be running that creates a table (for example, with db.liveTable), and the Java files should be updated to use that PQ's name as well as a valid username/password or a keyfile.

Manipulate tables

You can run table operations and queries on either the server or the client. Depending on your needs, you can run queries directly on the server or distribute workloads across multiple clients. The Core+ Java client supports both approaches.

Manipulate tables on the server

To fetch and manipulate tables from the query, create a TableSpec object using one of the session's four root methods, then subscribe to it using the methods below.

MethodDescription
catalogTableA table containing the full catalog of available database tables.
scopeTableA named table in the query scope.
historicalTableA static historical table from the database.
liveTableA live table from the database.

For example:

// This is an example of a batch operation based on a table in the existing query's scope.
final TableSpec testTable1 = DndSession.scopeTable("TestTable").where("Value > 4");

The TableSpec does not send any data to the client. The following list includes just a few table operations that can be applied to a TableSpec:

The example above runs a where on the TestTable in the worker directly.

When the subscribeTo or snapshotOf methods are called, then the server performs the operations described in the TableSpec and returns the resultant data.

// This creates a ticking (Live) barrage subscription
final Table testTableSubscription = session.subscribeTo(testTable1);

// This creates a static barrage snapshot
final Table testTableSnapshot = session.snapshotOf(testTable1);

When streamOf is called, the server performs the operations described in the TableSpec and returns the resultant data as a FlightStream.

// This creates a FlightStream of the table
final FlightStream stream = session.streamOf(testTable1);

This snippet will produce a FlightStream, which is a static snapshot of the source table.

The client enables queries to be run on a remote server or locally within the client. For example, the Table is a client-side object obtained from a server. The client can apply many of the same operations.

Manipulate tables in the client

The Table is a client-side object that contains a copy of all data from the server. The Barrage protocol replicates consistent updates to the client. The engine runs locally within the client, allowing table operations like where, sort, or update to execute outside the server, distributing workloads across multiple machines.

Execute Scripts on the server

You can also execute script code blocks on the worker using the executeCode method:

// You can also execute arbitrary script code on the server. This one creates a variable we can fetch below
session.executeCode("pel = db.live_table(namespace=\"DbInternal\", table_name=\"ProcessEventLog\").where(\"Date=today()\").tail(2)");
final Table fromExCode = session.snapshotOf(DndSession.scopeTable("pel"));

Cleanup

Connections, sessions, and tables fetched from a Deephaven query all consume resources and must be properly closed when you finish using them. Every Table, Session, and SessionFactory has a close method that you should call when finished with each object.

Note

Barrage tables have additional state tracking that requires cleanup. When using the Barrage client, first close tables through the session before calling .close on the tables themselves.

session.closeTable(myTable);
myTable.close();

Access the full Deephaven Community API

If you want more sophisticated interactions with the query worker, you may retrieve the underlying SessionImpl from the session using the .session method.

See the Community Documentation for more details.