API

The Coco Platform currently provides APIs for the following language:

Whilst the API is customised to fit in naturally with each language, there are some common principles that are language independent. This section outlines these general principles, whilst the language-specific documentation is contained in the above sections.

Implementation

The API for each of the above languages is implemented using a thin wrapper over the top of gRPC which communicates with a separate server process called coco-platform-server running on the same host. Whilst the fact that the API internally uses gRPC to communicate with a remote server process should not be visible to users of the API, there are several important points to consider:

  • When an override of one of the virtual classes is executed (e.g. on DiagnosticConsumer), it will be executed on one of the gRPC threads, rather than one of the normal application threads.

  • Most objects are actually just thin wrappers around a server-side object. For example, the lifetime of the ProjectTreeNode nodes returned by the Session object is determined by the lifetime of the Session object. If the Session object is garbage-collected before the ProjectTreeNode nodes are no longer required, then the API will crash. In general, the following classes should be treated as owning memory of all objects that are returned by any of their methods:

  • Listeners (e.g. DiagnosticConsumer or SessionListener) are not retained by the receiving object even when using methods such as addDiagnosticsConsumer. This means that when the garbage collector next runs, the listener will be collected, meaning that further events will be silently dropped. For example, consider the following:

    APIClient client = ...;
    StandaloneContext context = new StandaloneContext(client);
    MyDiagnosticLogger listener = new MyDiagnosticLogger(client);
    context.addDiagnosticsConsumer(listener);
    // no further references to listener are made
    context.loadModule("File.coco");
    

    If the garbage collector runs whilst loadModule is executing, then listener will be garbage collected, meaning that diagnostics will be silently dropped.

    To avoid this, when calling methods such as addDiagnosticsConsumer always ensure to retain a reference to the listener for as long as the listener is relevant.

Licensing

Usage of the API requires a license in the same way as other Coco Platform tools. Under normal usage the API will share the same licenses as the other Coco Platform tools, meaning that if a user has already signed into, for example, Eclipse, then they will not need to do anything in order to use the API.

Warning

It is vital that you check if the user has a valid license before attempting to construct any of the other API classes. Failure to do so will result in the application terminating abruptly. For example, the following code illustrates how the Java API can be used to check the license status:

UserInfo userInfo = new UserInfo(apiClient);
LicenseResponse response = userInfo.hasLicense(Arrays.asList(ProductFeature.CocoPlatformBase));
if (response.getLicensed()) {
  // Ok: a valid license has been found
} else {
  // Not ok: do not continue to use the API.
  System.out.println("Failed to acquire license: " + response.getNonLicensedReason());
}

General Advice

The API provides two main ways of loading Coco files, the Context API and the Session API, which have different strengths and weaknesses. This section gives an overview of these two different methods in order to help determine which one is most appropriate for a given use case.

The Session API, as documented in Session, provides a high-level API that is ideally suited for implementing IDE-like features. The Session API allows a user to add several folders to a single object, and is capable of asynchronously loading the files in the background whilst also asynchronously verifying and generating code. It also monitors the filesystem for any relevant changes, and will automatically reload relevant projects when changes are detected. It also automatically handles Coco packages (as specified by Coco.toml files).

In contrast, the Context API StandaloneContext provides a lower-level API that is better suited to applications that generate Coco and fully manage all coco files, and their lifecycle. In contrast to the Session API, all methods are synchronous and the API will not automatically reload anything. In fact, the StandaloneContext does not support reloading at all: instead a new StandaloneContext should be created to handle the new version of the file.