Skip to content

Scala SDK

Repo JavaDocs Release Development

Obtain the SDK

For Scala, you can reuse the existing Java SDK as-is. It is available on Maven Central, ready to be included in your project:

build.sbt
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
name := "Main"
version := "1.0"
scalaVersion := "2.13.14"

lazy val main = project
  .in(file("."))
  .settings(
    name := "Main",
    libraryDependencies ++= Seq(
      "com.atlan" % "atlan-java" % "1.13.0", // (1)
      "com.typesafe.scala-logging" %% "scala-logging" % "3.9.5" // (2)
    )
  )
  1. Include the latest version of the Java SDK in your project as a dependency (replace the version number with the latest version indicated in the badges above).
  2. The Java SDK uses slf4j for logging purposes. You can include the scala-logging utility as a simple binding mechanism to send any logging information out to your console (standard out).

Configure the SDK

Set two values on the static Atlan class:

  • Atlan.setBaseUrl() should be given your Atlan URL (for example, https://tenant.atlan.com)
  • Atlan.setApiToken() should be given your Atlan API token , for authentication (don't forget to assign one or more personas to the API token to give access to existing assets!)

That's it — once these are set, you can start using your SDK to make live calls against your Atlan instance! 🎉

Set the base URL first

Since version 0.9.0 of the Java SDK, you must call setBaseUrl() before calling setApiToken().

Here's an example of setting these based on environment variables:

AtlanLiveTest.scala
import com.atlan.Atlan

object Main extends App {
    Atlan.setBaseUrl(System.getenv("ATLAN_BASE_URL"))
    Atlan.setApiToken(System.getenv("ATLAN_API_KEY"))
}

What's next?

Delve into more detailed examples:

Error-handling

The SDK defines checked exceptions for the following categories of error:

Exception Description
ApiConnectionException Errors when the SDK is unable to connect to the API, for example due to a lack of network access or timeouts.
AuthenticationException Errors when the API token configured for the SDK is invalid or expired.
ConflictException Errors when there is some conflict with an existing asset and the operation cannot be completed as a result.
InvalidRequestException Errors when the request sent to Atlan does not match its expectations. If you are using the built-in methods like toCreate() and toUpdate() this exception should be treated as a bug in the SDK. (These operations take responsibility for avoiding this error.)
LogicException Errors where some assumption made in the SDK's code is proven incorrect. If ever raised, they should be reported as bugs against the SDK.
NotFoundException Errors when the requested resource or asset does not exist in Atlan.
PermissionException Errors when the API token used by the SDK does not have permission to access a resource or carry out an operation on a specific asset.
RateLimitException Errors when the Atlan server is being overwhelmed by requests.

A given API call could fail due to all of the errors above. So these all extend a generic AtlanException checked exception, and all API operations throw AtlanException.

Example

For example, when creating a connection there is an asynchronous process that grants permissions to the admins of that connection. So there can be a slight delay between creating the connection and being permitted to do any operations with the connection. During that delay, any attempt to interact with the connection will result in a PermissionException, even if your API token was used to create connection in the first place.

Another example you may occasionally hit is some network issue that causes your connection to Atlan to be interrupted. In these cases, an ApiConnectionException will be raised.

Don't worry, the SDK retries automatically

While these are useful to know for detecting issues, the SDK automatically retries on such problems.

Advanced configuration

Atlan is a distributed, cloud-native application, where network problems can arise. These advanced configuration options allow you to optimize how the SDK handles such ephemeral problems.

Logging

The SDK uses slf4j to be logging framework-agnostic. You can therefore configure your own preferred logging framework:

build.sbt
 9
10
11
12
13
14
15
    libraryDependencies ++= Seq(
      "com.atlan" % "atlan-java" % "1.12.10",
      "com.typesafe.scala-logging" %% "scala-logging" % "3.9.5",
      "org.apache.logging.log4j" % "log4j-core" % "2.22.0" % Runtime, // (1)
      "org.apache.logging.log4j" % "log4j-slf4j2-impl" % "2.22.0" % Runtime,
      "org.apache.logging.log4j" %% "log4j-api-scala" % "13.1.0"
    )
  1. Add log4j2 bindings.
src/main/resources/log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="ConsoleAppender" target="SYSTEM_OUT">
            <PatternLayout>
                <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
            </PatternLayout>
        </Console>
        <File name="FileAppender" fileName="tmp/debug.log" append="false">
            <PatternLayout>
                <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
            </PatternLayout>
        </File>
    </Appenders>
    <Loggers>
        <Root level="DEBUG">
            <AppenderRef ref="ConsoleAppender" level="INFO"/>
            <AppenderRef ref="FileAppender"/>
        </Root>
        <Logger name="com.atlan" level="DEBUG"/>
    </Loggers>
</Configuration>

Retries

The SDK handles automatically retrying your requests when it detects certain problems:

  • When an ApiConnectionException occurs that is caused by an underlying ConnectException or SocketTimeoutException.
  • When there is a 403 response indicating that permission for an operation is not (yet) available.
  • When there is a 500 response indicating that something went wrong on the server side.
More details on how they work

If any request encounters one of these problems, it will be retried. Before each retry, the SDK will apply a delay using:

  • An exponential backoff (starting from 500ms)
  • A jitter (in the range of 75-100% of the backoff delay)

Each retry will be at least 500ms, and at most 5s.

(Currently these values are not configurable.)

For each request that encounters any of these problems, only up to a maximum number of retries will be attempted. (This is set to 3 by default.)

You can configure the maximum number of retries globally using setMaxNetworkRetries() on a client. Set this to an integer:

Configure the maximum number of retries
val client = Atlan.getDefaultClient()
client.setMaxNetworkRetries(10)

Timeouts

The SDK will only wait so long for a response before assuming a network problem has occurred and the request should be timed out. By default, this is set to 80 seconds.

You can configure the maximum time the SDK will wait before timing out a request using setReadTimeout() on a client. Set this to an integer giving the number of milliseconds before timing out:

Configure the maximum time to wait before timing out
val client = Atlan.getDefaultClient()
client.setReadTimeout(120 * 1000) // (1)!
  1. Remember this must be given in milliseconds. This example sets the timeout to 2 minutes (120 seconds * 1000 milliseconds).

Multi-tenant connectivity

Since version 0.9.0, the Java SDK supports connecting to multiple tenants. When you use the Atlan.setBaseUrl() method you are actually setting a default client. This default client will be used as the fallback for any operations where you do not explicitly provide the client you want the method to use.

When you want to override that default client you can create and pass one to most operations:

Create a client
1
2
val client = Atlan.getClient("https://tenant.atlan.com") // (1)!
client.setApiToken("...")
  1. The getClient() factory method will return a client for the given base URL, creating a new client first if one does not already exist. You can also (optionally) provide a second argument to give a unique name to a client if you want to create multiple clients against a single tenant.
Use a specific client
 3
 4
 5
 6
 7
 8
 9
10
11
12
val term = GlossaryTerm.creator( // (1)
        "Example Term",
        "836830be-5a11-4094-8346-002e0320684f",
        null)
    .build()
client.assets.save(term) // (2)
client.assets.save(
    term,
    RequestOptions.from(client).maxNetworkRetries(10).build()) // (3)
term.save(client) // (4)
  1. Create an object as usual.
  2. You can access the operations for assets directly on the client, under client.assets. These will generally give you the most flexibility — they can handle multiple objects at a time and allow overrides.
  3. Every operation on the client itself has a variant with an (optional) final argument through which you can override settings like retry limits or timeouts for this single request. You can use the from(client) factory method to initialize the request options with all the settings of your client, and then you only need to chain on those you want to override for this particular request.
  4. Alternatively, you can pass the client to the operation on the object itself. (When no client is passed, it falls back to using the default client — which is also accessible through Atlan.getDefaultClient().)

Limit the number of clients to those you must have

Each client you create maintains its own independent copy of various caches. So the more clients you have, the more resources your code will consume. For this reason, we recommended limiting the number of clients you create to the bare minimum you require — ideally just a single client per tenant.

(And since in the majority of use cases you only need access to a single tenant, this means you can most likely just rely on the default client and the fallback behavior.)

Using a proxy

To use the Java SDK with a proxy, you need to send in some additional parameters when running any java ... command.

These are described in detail in the Java documentation , but are summarized here for simplicity:

  • https.proxyHost should be set to the hostname for your HTTPS proxy
  • https.proxyPort should be set to the port for your HTTPS proxy (default being 443)
Run command using an HTTPS proxy
1
java -Dhttps.proxyHost=hostname -Dhttps.proxyPort=8080 com.atlan.samples.SomeClassToRun
  • socksProxyHost should be set to the hostname for your SOCKS proxy
  • socksProxyPort should be set to the port for your SOCKS proxy (default being 1080)
Run command using a SOCKS proxy
1
java -DsocksProxyHost=hostname -DsocksProxyPort=8080 com.atlan.samples.SomeClassToRun

Providing credentials to the proxy

In either case, if you need to authenticate to your proxy, you will need to wrap whatever code you want to run to set up these credentials using something like the following:

Authenticate to proxy
1
2
3
4
val pa = PasswordAuthentication( // (1)
    "username", // (2)
    "password".toCharArray()) // (3)
Atlan.getDefaultClient().setProxyCredential(pa) // (4)
  1. You need to create a built-in Java PasswordAuthentication object.
  2. Provide your username as the first argument.
  3. ...and your password as the second argument, as a char[]. (Of course, you should not hard-code your password in your code itself, but rather pull it from elsewhere.)
  4. Then use setProxyCredential() to pass this PasswordAuthentication object to the Atlan client, before any of the rest of the code will execute.