Skip to content

Entry point & builder

The GGCommons object is your component’s runtime. You build it once at startup from the standard CLI args, and it wires every subsystem — config, messaging, metrics, heartbeat, health, and the opt-in credentials/parameters/streaming — behind one handle that you hold for the component’s lifetime. You reach each subsystem through a typed accessor, and you tear the runtime down with a language-appropriate lifecycle mechanism.

The runtime is always constructed through a fluent builder. Rust and TypeScript expose only the builder; Python additionally keeps a public constructor; Java additionally keeps deprecated direct constructors for back-compat (see Deprecated Java constructors). There is no init() facade in any language.

The builder takes the component name, the raw CLI args, optional app-specific CLI options, and an optional receiveOwnMessages flag, then produces the runtime.

com.mbreissi.ggcommons.GGCommonsBuilder
static GGCommonsBuilder create(String componentName);
GGCommonsBuilder withArgs(String[] args); // already-stripped app args (argv minus program)
GGCommonsBuilder withAppOptions(org.apache.commons.cli.Options appOptions);
GGCommonsBuilder receiveOwnMessages(boolean receiveOwnMessages); // default true
GGCommons build(); // throws IllegalStateException if componentName is null

A minimal startup in each language. Pass the full component name (the same name used in your recipe), the CLI args, and call build.

import com.mbreissi.ggcommons.GGCommons;
import com.mbreissi.ggcommons.GGCommonsBuilder;
public static void main(String[] args) {
GGCommons gg = GGCommonsBuilder.create("com.mbreissi.greengrass.JavaComponentSkeleton")
.withArgs(args)
.build();
var config = gg.getConfigManager();
var messaging = gg.getMessaging();
var metrics = gg.getMetrics();
// Do NOT register your own shutdown hook — the library wires SIGTERM/SIGINT to a graceful,
// idempotent shutdown() itself. A second hook just double-runs teardown.
// ... business logic ...
}

The runtime exposes one accessor per subsystem. The always-on accessors (config, messaging, metrics) return the concrete service. The opt-in accessors (streams, credentials, parameters) follow the opt-in return contract below.

// com.mbreissi.ggcommons.GGCommons — accessors
ConfigManager getConfigManager(); // concrete; throws if not initialized
MessagingClient getMessaging(); // concrete instance
MetricEmitter getMetrics(); // concrete instance
StreamService getStreams(); // null when no `streaming` config section
CredentialService getCredentials(); // null when no `credentials` section
ParameterService getParameters(); // null when no `parameters` section

There is no getConfig() accessor in Java — config is reached via getConfigManager().

When no messaging transport is wired, the messaging accessor behaves differently per language:

  • Java / Python return the concrete handle regardless (Java a MessagingClient instance, Python the MessagingClient class).
  • Rust returns Err(GgError::Messaging) — handle it with ? or a match.
  • TypeScript throws GgError.messaging(...) — guard with try/catch if messaging is optional.

The newer subsystems — streaming, credentials, parameters — are opt-in. The accessor yields a usable service only when the matching config section is present (and, in Rust, the matching cargo feature is enabled). Otherwise it returns an “absent” value whose exact form is language-specific.

Subsystem Java Python Rust TypeScript
streams null None Arc<dyn StreamService> (empty, never None) undefined
credentials null None Option<Arc<...>>None undefined
parameters null None Option<Arc<...>>None undefined

Two Rust-specific points to internalize:

  1. streams() is not Option. It always returns an Arc<dyn StreamService>; when there is no streaming config section the service is simply empty. So Rust callers check streams().stream_names() for emptiness rather than testing for None. (credentials() and parameters() are Option.)
  2. The opt-in accessors are feature-gated. streams() requires feature = "streaming", credentials() requires feature = "credentials", and parameters() requires feature = "parameters". The features are off by default, so without the feature the method does not even exist (it will not compile). In Java, Python, and TypeScript the accessor always exists and returns the null/None/undefined sentinel.
StreamService streams = gg.getStreams();
if (streams != null) {
// streaming is configured
}
CredentialService creds = gg.getCredentials(); // null when no `credentials` section

Components report readiness through setReady. This drives the health endpoint’s readyz signal (see Health). The flag defaults to ready at construction.

void setReady(boolean ready); // defaults to true

Java exposes only the setter publicly; the corresponding getters (isReadyz(), messagingConnected()) are package-private.

The shutdown story differs fundamentally per language, but one rule is shared everywhere: the library installs its own signal handlers — do not register your own.

void shutdown(); // idempotent (AtomicBoolean compareAndSet)

The library installs a JVM shutdown hook on SIGTERM and SIGINT that runs a graceful teardown. Calling shutdown() yourself is allowed and idempotent; it also deregisters the hook. Do not add your own Runtime.getRuntime().addShutdownHook(...) — that double-runs teardown.

Java exposes a static helper to parse the standard CLI contract without constructing a runtime — useful for tools and tests that need the resolved platform/transport/thing values.

static ParsedCommandLine processArgs(String componentName, String[] args, Options appOptions);
// ParsedCommandLine — public fields:
// CommandLine commandLine
// String[] configArgs
// Platform platform
// Transport transport
// String standaloneConfigPath
// String thingName

Java keeps three deprecated direct constructors for backward compatibility. They are still functional but superseded by the builder — use GGCommonsBuilder.create(...) for new code.

@Deprecated GGCommons(String componentName, String[] args);
@Deprecated GGCommons(String componentName, String[] args, Options appOptions);
@Deprecated GGCommons(String componentName, String[] args, Options appOptions, boolean receiveOwnMessages);

These delegate to a package-private init(...); there is no public init() facade for callers.

Concept Java Python Rust TypeScript
Runtime type GGCommons GGCommons GgCommons GGCommons
Builder type GGCommonsBuilder GGCommonsBuilder GgCommonsBuilder GGCommonsBuilder
Start a builder create(name) create(name) new(name) new GGCommonsBuilder(name)
Set args withArgs(args) with_args(args) args(...) (incl. program name) args(...) (sliced)
App CLI options withAppOptions(...) with_app_options(...) — (n/a) — (n/a)
Build build() build() build().await await build()
Config accessor getConfigManager() get_config_manager() config() config()
Messaging accessor getMessaging() get_messaging() messaging() (Result) messaging() (throws)
Metrics accessor getMetrics() get_metrics() metrics() metrics()
Opt-in absent value null None Option None (streams() empty service) undefined
Readiness setter setReady(b) set_ready(b) set_ready(b) setReady(b)
Teardown shutdown() + JVM hook shutdown() + context mgr RAII Drop (no method) close()
Signals wired SIGTERM + SIGINT SIGTERM only watcher flips readiness only SIGTERM + SIGINT
Direct construction deprecated ctors public ctor builder-only builder-only