> ## Documentation Index
> Fetch the complete documentation index at: https://docs.startree.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Connecting to StarTree Cloud via Java

Pinot provides a native Java client to execute queries on the cluster. The client is tenant-aware, and able to direct queries to the correct broker.

### Prerequisite

You can use the client by installing and including `Maven` or `Gradle`.

For information on how to install Maven, visit [Installing Apache Maven](https://maven.apache.org/install.html).

#### Example of how to including the Maven dependency to use the client:

```
<dependency>
    <groupId>org.apache.pinot</groupId>
    <artifactId>pinot-java-client</artifactId>
    <version>1.0.0</version>
</dependency>
```

For information on how to install Gradle, visit [Gradle Build Tool Installation](https://gradle.org/install/).

#### Example of how to including the  Gradle dependency to use the client:

```
include 'org.apache.pinot:pinot-java-client:0.5.0'
```

### Usage

Here's an example of how to use the `pinot-java-client` to query Pinot.

```
import org.apache.pinot.client.Connection;
import org.apache.pinot.client.ConnectionFactory;
import org.apache.pinot.client.Request;
import org.apache.pinot.client.ResultSetGroup;
import org.apache.pinot.client.ResultSet;

/**
 * Demonstrates the use of the pinot-client to query Pinot from Java
 */
public class PinotClientExample {

  public static void main(String[] args) {

    // pinot connection
    String brokerURL = "https://pinot.<random-string>.cp.s7e.startree.cloud"; // this URL should be available with you
    String pinotClusterName = "PinotCluster";
    JsonAsyncHttpPinotClientTransportFactory factory = new JsonAsyncHttpPinotClientTransportFactory();
    Connection pinotConnection = ConnectionFactory.fromHostList(Collections.singletonList(brokerURL), factory.buildTransport());

    String query = "SELECT COUNT(*) FROM myTable GROUP BY foo";

    // set queryType=sql for querying the sql endpoint
    Request pinotClientRequest = new Request("sql", query);
    ResultSetGroup pinotResultSetGroup = pinotConnection.execute(pinotClientRequest);
    ResultSet resultTableResultSet = pinotResultSetGroup.getResultSet(0);

    int numRows = resultTableResultSet.getRowCount();
    int numColumns = resultTableResultSet.getColumnCount();
    String columnValue = resultTableResultSet.getString(0, 1);
    String columnName = resultTableResultSet.getColumnName(1);

    System.out.println("ColumnName: " + columnName + ", ColumnValue: " + columnValue);
  }
}
```

### Connection Factory

The client provides a `ConnectionFactory` class to create connections to a Pinot cluster. To create a connection, include a comma-separated list of the brokers in the cluster. For example,  `("broker-1:1234", "broker-2:1234", ...);`

```java theme={null}
Connection connection = ConnectionFactory.fromZookeeper
  ("some-zookeeper-server:2191/zookeeperPath");
Connection connection = ConnectionFactory.fromProperties("demo.properties");
Connection connection = ConnectionFactory.fromHostList(Collections.singletonList("https://pinot.<random-string>.cp.s7e.startree.cloud"), factory.buildTransport());
```

### Query methods

Query using one of the following methods:

* For blocking queries, use the following request format: `Connection.execute(org.apache.pinot.client.Request)`
* For asynchronous queries that return a future object, use the following request format: `Connection.executeAsync(org.apache.pinot.client.Request)`

```java theme={null}
ResultSetGroup resultSetGroup =
  connection.execute(new Request("sql", "select * from foo..."));
// OR
Future<ResultSetGroup> futureResultSetGroup =
  connection.executeAsync(new Request("sql", "select * from foo..."));
```

To escape query parameters, you can use the `PreparedStatement` (which isn't stored, so won't decrease the subsequent query performance).

```java theme={null}
PreparedStatement statement =
    connection.prepareStatement(new Request("sql", "select * from foo where a = ?"));
statement.setString(1, "bar");

ResultSetGroup resultSetGroup = statement.execute();
// OR
Future<ResultSetGroup> futureResultSetGroup = statement.executeAsync();
```

### Result set

Access results using various `get` methods on the first `ResultSet` with the `getResultSet(int)` method.

```java theme={null}
Request request = new Request("sql", "select foo, bar from baz where quux = 'quuux'");
ResultSetGroup resultSetGroup = connection.execute(request);
ResultSet resultSet = resultSetGroup.getResultSet(0);

for (int i = 0; i < resultSet.getRowCount(); ++i) {
  System.out.println("foo: " + resultSet.getString(i, 0));
  System.out.println("bar: " + resultSet.getInt(i, 1));
}
```

### Authentication

Pinot supports [basic HTTP authorization](https://docs.pinot.apache.org/operators/tutorials/authentication), which can be enabled for your
cluster using configuration. To support basic HTTP authorization in your client-side Java applications, make sure you are using
Pinot Java Client 0.10.0+ or building from the latest Pinot snapshot.
The following code snippet shows you how to connect to and query a Pinot cluster that has basic HTTP authorization enabled when using the Java client.

```java theme={null}
final String username = "admin";
final String password = "verysecret";

// Concatenate username and password and use base64 to encode the concatenated string
String plainCredentials = username + ":" + password;
String base64Credentials = new String(
    Base64.getEncoder().encode(plainCredentials.getBytes()));

String authorizationHeader = "Basic " + base64Credentials;

Map<String, String> headers = new HashMap();
headers.put("Authorization", authorizationHeader);
JsonAsyncHttpPinotClientTransportFactory factory =
    new JsonAsyncHttpPinotClientTransportFactory();
factory.setHeaders(headers);
PinotClientTransport clientTransport = factory
    .buildTransport();

Connection connection = ConnectionFactory.fromProperties(
        Collections.singletonList("localhost:8000"), clientTransport);
String query = "select count(*) FROM baseballStats limit 1";

ResultSetGroup rs = connection.execute(query);
System.out.println(rs);
connection.close();
```

### Configuring client time-out

The following timeouts can be set:

* brokerConnectTimeoutMs (default 2000)
* brokerReadTimeoutMs (default 60000)
* brokerHandshakeTimeoutMs (default 2000)
* controllerConnectTimeoutMs (default 2000)
* controllerReadTimeoutMs (default 60000)
* controllerHandshakeTimeoutMs (default 2000)

Timeouts for the Java connector can be added as a connection properties. The following example configures a very low timeout of 10ms:

```java theme={null}
Properties connectionProperties = new Properties();
connectionProperties.setProperty("controllerReadTimeoutMs", "10");
connectionProperties.setProperty("controllerHandshakeTimeoutMs", "10");
connectionProperties.setProperty("controllerConnectTimeoutMs", "10");
connectionProperties.setProperty("brokerReadTimeoutMs", "10");
connectionProperties.setProperty("brokerHandshakeTimeoutMs", "10");
connectionProperties.setProperty("brokerConnectTimeoutMs", "10");

// Register new Pinot JDBC driver
DriverManager.registerDriver(new PinotDriver());

// Get a client connection and set the connection timeouts
Connection connection = DriverManager.getConnection(DB_URL, connectionProperties);

// Test that your query successfully times out
Statement statement = connection.createStatement();
ResultSet rs = statement.executeQuery("SELECT count(*) FROM baseballStats LIMIT 1;");

while (rs.next()) {
    String result = rs.getString("count(*)");
    System.out.println(result);
}
```

## Obtaining Username and Password

You can cenerate an API token in the [Data Portal](/corecapabilities/security/manage-api-tokens#generating-an-api-token) or using the [REST API](/api-reference/introduction#authentication-%26-prerequisites). Then, [obtain the username and password from the service token](/corecapabilities/security/manage-api-tokens#extracting-username-and-password-from-a-startree-bearer-token)

Th username and password are used to authorize your API requests.

## Finding Your Broker URL

To find the correct Broker URL for your table in StarTree Cloud:

1. Access the Data Portal.
2. Click on **Tables**.
3. Select the specific table you want to query.
4. From the browser address bar, copy the URL to your Pinot cluster. For example, if the URL shown is `https://dp.1abcde6.cp.s7e.startree.cloud/tables`, then the Broker URL for the table will be `broker.pinot.1abcde6.cp.s7e.startree.cloud`.
