Tentackle Common — The Foundation Module¶
Overview and Motivation¶
The tentackle-common module is the root of the entire Tentackle stack. Its package-info sums it up in one
line — "Common classes for build- and runtime" — and that dual role is the key to understanding it. Unlike every
other module, tentackle-common is used in two completely different contexts:
- At runtime, by every Tentackle application, as the lowest-level utility and SPI layer.
- At build time, by the Tentackle Maven plugins and the Wurbelizer, which need the same annotations, naming rules, money/date types, and the service-discovery primitives while generating code and analyzing annotations.
Because it must work everywhere, tentackle-common is deliberately dependency-free: it requires only
java.sql and java.compiler from the JDK and nothing else from Tentackle. Everything else in the framework
depends, directly or transitively, on this module.
Its single most important responsibility is the Service and Configuration API — Tentackle's replacement for
java.util.ServiceLoader that powers dependency injection, component replacement, and build-time annotation
analysis throughout the framework. That subsystem is large enough to have its own document; this page gives the
whole-module picture and points to it.
See also: services.md — the in-depth guide to the
@Service/@MappedServiceannotations, theServiceFinder/ServiceFactory, build-time@Analyzeprocessing, theModuleHookmechanism, and OSGi.
Design principles¶
- Zero framework dependencies. Nothing in Tentackle sits below this module, so it cannot depend on anything in Tentackle. It leans only on the JDK.
- Build-time and runtime. Types here are shared by the running application and by the Maven plugins/wurblets
that build it, which guarantees that, e.g., a
BMoneyor a@ClassIdmeans the same thing in both worlds. - Annotation-driven, not reflection-at-startup. Component discovery is based on annotations analyzed at build
time and recorded under
META-INF, avoiding classpath scanning and minimizing startup cost. - Classpath and module-path. All mechanisms work identically in traditional classpath mode and in JPMS
modular (including jlink'd) mode, via the
ModuleHookindirection.
Key Concepts¶
Service and Configuration API¶
This is the heart of the module and is documented fully in services.md. In brief:
Service/ServiceName/MappedService— the annotations that register an implementation (a simple service inMETA-INF/services, or a mapped service inMETA-INF/mapped-servicesthat relates a property → class → value).ServiceFinder/DefaultServiceFinder/ServiceFinderKey— locate service configurations, preserving module-dependency order (the first URL belongs to the topmost module; the classpath comes last).ServiceFactory— creates services and finders; a richer replacement forServiceLoader(any configuration type, per-service classloaders, modular plus non-modular). It is itself loadable viaServiceLoaderand therefore replaceable.Analyze/AnnotationProcessor— the meta-annotation that ties an annotation to a build-timeAnalyzeHandler(named by string, so the application never depends on the handler at runtime).ModuleHook/ModuleInfo/ModuleOrdinal/ModuleSorter— determine and topologically sort the module hierarchy (needed for resource bundles and for jlink'd images where module dependencies are otherwise not discoverable).ClasspathFirst— override a module-path service from the classpath.RemoteMethod/RecordDTO— annotations consumed by wurblets/analysis to make handwritten methods remoting-capable and to mark records for code generation.
Database-aware data types¶
Tentackle ships its own value types whose defining feature is stable database/serialization semantics across
timezones and optional immutability. Most are usable directly as model attribute types (mapped by
tentackle-sql data types).
BMoney— a money value derived fromBigDecimalwith a fixed, unchangeable scale; stored as aDOUBLEvalue +INTEGERscale.DMoney— likeBMoney, but stored as aDECIMAL(scale 0) +INTEGERscale for exact decimal storage.Date— a date with database semantics: serialized asYYYYMMDDso it stays the same calendar date in every timezone (unlikejava.sql.Date, which serializes epochal time).Time— a time with database semantics.Timestamp— a timestamp with an optional UTC flag (the model's[UTC]option) that keeps it fixed to a timezone by convention rather than converting on serialization.Binary— stores a serializable object as a blob-like byte array using Java Object Serialization, but via binary-stream methods so it stays valid outside a transaction (unlike real blobs).TBinary— same asBinarybut uses the pluggableObjectSerializer(by default TRIP's serializer), so the object need not implementSerializable.AbstractBinaryis the shared base.I18NText— a multilingual string usable as a model attribute (org.tentackle.sql.datatypes.I18NTextType); implementsCharSequence/Comparablefor the current locale.Freezable— the interface behind the "frozen" (made-immutable) capability of the date/time and binary types. See freezable.md for why it exists and how it makes old-school mutable types likejava.util.Datesafe as entity attributes.
Object serialization¶
ObjectSerializer abstracts generic object
serialization; DefaultObjectSerializer is the
JOS-based default. This is the seam that lets TBinary (and other framework code) serialize via TRIP instead of
plain Java serialization when tentackle-core is present.
Security and configuration¶
Cryptor— a simple symmetric en/decryptor. An application provides its own@Service(Cryptor.class)subclass with a confidential salt/passphrase; it is used to encrypt passwords in memory, during client/server login, and inbackend.properties.EncryptedProperties— aPropertiesvariant where values starting with~are decrypted via theCryptor(with\escaping and optional case-insensitive keys). This is the configuration format used for backend connection settings.Settings— global framework settings.Constants— shared build- and runtime constants.Version— Tentackle version information.
Internationalization and resource bundles¶
Resource-bundle handling differs between classpath and modular mode, so the framework routes it through its own factory:
Bundle— annotation marking a class that corresponds to a resource bundle.BundleFactory/DefaultBundleFactory/BundleSupport— locate and create bundles via the module hooks.LocaleProvider— supplies the currentLocale.I18NText— the multilingual text value type (see above).CommonCommonBundle— the module's own message bundle.
Helper utilities¶
A set of final static-method helpers and small utilities used throughout build and runtime:
StringHelper— string manipulation helpers.StringNormalizer/DefaultStringNormalizer— reduce strings to a restricted character set (e.g., for normtext search); works for most Western languages by default.DateHelper— date/time helpers aroundjava.util.Date.FileHelper— file-handling helpers.ExceptionHelper— exception helpers.Compare— null-safeComparablecomparisons.ParameterString— parses/buildsname='value', …parameter strings (used in model options and elsewhere).NamingRules— class-naming conventions.StripMode— enum for string-stripping behavior.Path/PathFactory— a generic path abstraction and its factory.
External tools¶
ToolFinder— locates external executables.ToolRunner— runs external tools (used by build tooling, e.g., jlink/jpackage style invocations).
Exceptions¶
TentackleRuntimeException— the framework's base unchecked exception.InterruptedRuntimeException— wraps a checkedInterruptedExceptionand re-sets the thread's interrupted flag.
Package Layout¶
| Package | Contents |
|---|---|
org.tentackle.common |
Everything: the service/configuration API, the database-aware data types, object serialization, the Cryptor/EncryptedProperties security layer, i18n/bundle support, the helper utilities, external-tool support and the base exceptions. |
org.tentackle.common.service |
The Hook (ModuleHook) for this module. |
How It Fits Together¶
tentackle-common underpins the whole framework in two directions:
Build time Runtime
────────── ───────
tentackle-maven-plugin ┐ ┌ every Tentackle module
tentackle-sql-maven-… ├─ use ──►│ (core, session, sql, database,
Wurbelizer wurblets ┘ │ pdo, domain, persistence, fx, …)
│ │
└──────► tentackle-common ◄───┘
(annotations, ServiceFinder, money/date types,
naming rules, Cryptor, helpers — no deps)
- At build time, the Maven plugins read the
@Analyze-meta-annotated annotations (@Service,@ClassId,@TableName, …) from source, run theirAnalyzeHandlers, and emit configuration files underMETA-INF. The same money/date/naming types are available, so the generated code is consistent. - At runtime, application code obtains implementations through
ServiceFactory.createService(...)/ServiceFactory.getServiceFinder(), which read thoseMETA-INFfiles in module-dependency order — working in both classpath and modular mode thanks to theModuleHooks every module provides.
A minimal application only needs a dependency on tentackle-common plus the tentackle-maven-plugin to use the
service API; higher-level utilities (e.g., the reflection-based class mappers) additionally require
tentackle-core.
Module Dependencies¶
tentackle-common is the bottom of the stack:
- It requires transitive only
java.sqlandjava.compilerfrom the JDK — and nothing from Tentackle. - It uses
org.tentackle.common.ModuleHook(to discover other modules'META-INFcontributions) andorg.tentackle.common.ServiceFactory(so an application can replace the factory itself). - It opens
org.tentackle.commontoorg.tentackle.corefor TRIP serialization. - It provides its own
ModuleHook(org.tentackle.common.service.Hook). - Every other Tentackle module depends on it, directly or transitively.
Related Documentation¶
- Services / ServiceFinder — the in-depth guide to the service and configuration API summarized above.
- Freezable — why the date/time and binary value types are freezable, and how that protects entity attributes from aliasing mutation.
- Tentackle SQL — maps the data types here (
BMoney,DMoney,Date,Timestamp,I18NText, …) to database columns. - Session — uses
EncryptedProperties/Cryptorfor connection configuration and credentials. - PDO — the PDO pattern wired together by the service API.