How to Extend Ossie with New Vendor-Specific Attributes and Extensions
Ossie supports extending its vendor-agnostic core model through a custom extensions mechanism that stores proprietary metadata as JSON within standardized objects, enabling seamless bidirectional conversion via dedicated import/export converters.
Apache Ossie is designed as a vendor-neutral semantic modeling framework, yet it provides a structured extension pipeline for integrating proprietary attributes without sacrificing interoperability. Understanding the process for extending Ossie with new vendor-specific attributes and extensions allows developers to bridge Ossie's standardized representations with platform-specific implementations while maintaining round-trip fidelity.
Define a Stable Vendor Identifier
Choose a unique, free-form string (e.g., MYVENDOR) to identify your organization across all extension blocks. According to the core specification in core-spec/spec.md【/cache/repos/github.com/apache/ossie/main/core-spec/spec.md#L20-L34】, this identifier serves as the namespace for your custom metadata and must remain stable to ensure compatible parsing across converter versions.
Design the Vendor-Specific JSON Schema
Determine which fields your vendor implementation requires—such as connection parameters, table options, or security policies. The extension data is stored as a JSON string within the data property. Reference schemas for existing vendors like Snowflake, Salesforce, and DBT are documented in core-spec/spec.md【/cache/repos/github.com/apache/ossie/main/core-spec/spec.md#L90-L108】 to guide your structure.
Embed Extensions in the Ossie Model
Insert your vendor block under the appropriate hierarchy level: semantic_model, datasets, relationships, fields, or metrics. The YAML structure follows a consistent pattern across all levels.
datasets:
- name: sales
source: analytics.public.sales
fields:
- name: revenue
expression:
dialects:
- dialect: ANSI_SQL
expression: revenue
custom_extensions:
- vendor_name: MYVENDOR
data: '{"partition_key":"region","retention_days":30}'
Implement Converter Pairs
Bidirectional conversion requires implementing both export and import logic using Ossie's CustomExtensionHandler utilities.
Export Converter Implementation
During export, extract extensions where vendor_name matches your identifier and deserialize the JSON into your vendor's native objects. The generic extraction logic resides in CustomExtensionHandler.restoreCustomExtensionsAtLevel【/cache/repos/github.com/apache/ossie/main/converters/salesforce/src/main/java/org/apache/ossie/converter/CustomExtensionHandler.java#L58-L78】, which traverses arrays and matches items by identifier.
private void applyMyVendorExtensions(OsiDataset dataset, Map<String, Object> ossieItem) {
List<CustomExtension> extensions = parseCustomExtensions(ossieItem);
extensions.stream()
.filter(ext -> "MYVENDOR".equals(ext.getVendorName()))
.findFirst()
.ifPresent(ext -> {
MyVendorConfig cfg = jsonMapper.readValue(ext.getData(), MyVendorConfig.class);
// map cfg fields to the vendor model
dataset.setPartitionKey(cfg.getPartitionKey());
dataset.setRetentionDays(cfg.getRetentionDays());
});
}
Import Converter Implementation
During import, serialize your vendor configuration into JSON and wrap it in a CustomExtension object. The symmetric storage logic is implemented in CustomExtensionHandler.storeUnmappedProperties【/cache/repos/github.com/apache/ossie/main/converters/salesforce/src/main/java/org/apache/ossie/converter/CustomExtensionHandler.java#L55-L84】.
private void storeMyVendorExtensions(Map<String, Object> ossieItem, MyVendorDataset vendorDs) {
MyVendorConfig cfg = new MyVendorConfig(vendorDs.getPartitionKey(), vendorDs.getRetentionDays());
String json = jsonMapper.writeValueAsString(cfg);
CustomExtension ext = new CustomExtension();
ext.setVendorName("MYVENDOR");
ext.setData(json);
List<CustomExtension> list = parseCustomExtensions(ossieItem);
list.add(ext);
ossieItem.put("custom_extensions", list);
}
The Polaris converter demonstrates parsing patterns in OsiModelParser.java【/cache/repos/github.com/apache/ossie/main/converters/polaris/src/main/java/org/apache/ossie/converter/polaris/OsiModelParser.java#L62-L76】, showing how extensions are extracted from raw YAML into Java objects.
Validate and Document Your Extension
Update the Custom Extensions table in core-spec/spec.md【/cache/repos/github.com/apache/ossie/main/core-spec/spec.md#L34-L48】 to register your vendor name and description. Document the mapping workflow in converters/README.md【/cache/repos/github.com/apache/ossie/main/converters/README.md#L90-L102】 following the hub-and-spoke pattern described in lines 24-42.
Validate your implementation using the JSON schema in core-spec/osi-schema.json【/cache/repos/github.com/apache/ossie/main/core-spec/osi-schema.json】 and the validation script validation/validate.py. Create round-trip test cases using the examples/tpcds_semantic_model.yaml reference model to ensure custom_extensions blocks remain intact through conversion cycles.
Summary
- Vendor identifiers must be unique strings defined in
core-spec/spec.mdto prevent collisions. - Extension data is stored as JSON strings within
custom_extensionsarrays at any model level (datasets, fields, metrics, etc.). - Bidirectional converters rely on
CustomExtensionHandlermethodsrestoreCustomExtensionsAtLevelandstoreUnmappedPropertiesto handle extraction and serialization. - Validation requires testing against
osi-schema.jsonand verifying round-trip fidelity using the TPC-DS example model.
Frequently Asked Questions
Can multiple vendors extend the same Ossie model simultaneously?
Yes. The custom_extensions property is an array that can contain multiple vendor blocks. Each extension is keyed by its vendor_name, allowing Ossie models to carry proprietary metadata from several platforms simultaneously without conflict.
Where should custom_extensions be placed in the model hierarchy?
Extensions can be attached at five levels: semantic_model, datasets, relationships, fields, or metrics. Place extensions at the level corresponding to the granularity of your vendor data—dataset-level configurations belong under datasets, while column-specific attributes belong under fields within those datasets.
How does Ossie ensure round-trip fidelity for vendor data?
The extension mechanism stores vendor data as opaque JSON strings that pass through the core model unchanged. Converter implementations using CustomExtensionHandler methods ensure that data extracted during export is serialized identically during import, preserving values through restoreCustomExtensionsAtLevel and storeUnmappedProperties operations.
What validation is required before submitting a new vendor extension?
Extensions must validate against the JSON schema defined in core-spec/osi-schema.json using validation/validate.py. Additionally, implementers should create test cases that round-trip a model through their converter, asserting that the custom_extensions block in examples/tpcds_semantic_model.yaml remains unchanged after export and re-import.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →