Best Practices for Organizing Multiple Datasets in an Apache Ossie Semantic Model

Store each dataset in the semanticDataObjects array within a single semantic_model entry, distinguish standard from shared datasets using table_type, and validate against the JSON schema before conversion to ensure lossless round-trip mapping with Salesforce.

Apache Ossie provides a semantic modeling framework that standardizes how datasets translate to Salesforce semantic data objects. When organizing multiple datasets within a single Ossie semantic model, adhering to the architectural constraints defined in DatasetMappingHandler.java ensures seamless bidirectional conversion and prevents data loss during synchronization.

Understanding the Semantic Model Structure

An Ossie semantic model is a top-level JSON object containing a semantic_model array. According to ConverterConstants.java, most implementations use a single entry in this array unless managing multi-tenant deployments.

Each entry contains a semanticDataObjects array where individual datasets reside. The DatasetMappingHandler treats each element in this array as a distinct dataset during conversion, mapping them to Salesforce semantic data objects.

Storing Multiple Datasets in the semanticDataObjects Array

The DatasetMappingHandler expects datasets under the key semanticDataObjects. This structure guarantees that the conversion engine can map each dataset to Salesforce and back without information loss.

When organizing multiple datasets:

  1. Create a single semantic_model entry for typical use cases.
  2. Populate the semanticDataObjects list with dataset definitions.
  3. Define dimensions using semanticDimensions and measurements using semanticMeasurements for each dataset.
import org.apache.ossie.util.DataStructureUtils;
import java.util.*;

Map<String, Object> semanticModel = new LinkedHashMap<>();

// Dataset 1: Customers
Map<String, Object> customers = new LinkedHashMap<>();
customers.put("apiName", "Customer");
customers.put("label", "Customer");
customers.put("table_type", "Standard");

List<Map<String, Object>> custDims = new ArrayList<>();
custDims.add(DataStructureUtils.mapOf(
        "apiName", "CustomerId",
        "label", "Customer ID",
        "semanticType", "string"));
customers.put("semanticDimensions", custDims);

List<Map<String, Object>> custMeas = new ArrayList<>();
custMeas.add(DataStructureUtils.mapOf(
        "apiName", "Revenue",
        "label", "Revenue",
        "semanticType", "decimal"));
customers.put("semanticMeasurements", custMeas);

// Dataset 2: Orders
Map<String, Object> orders = new LinkedHashMap<>();
orders.put("apiName", "Order");
orders.put("label", "Order");
orders.put("table_type", "Standard");

List<Map<String, Object>> orderDims = new ArrayList<>();
orderDims.add(DataStructureUtils.mapOf(
        "apiName", "OrderId",
        "label", "Order ID",
        "semanticType", "string"));
orders.put("semanticDimensions", orderDims);

List<Map<String, Object>> orderMeas = new ArrayList<>();
orderMeas.add(DataStructureUtils.mapOf(
        "apiName", "Amount",
        "label", "Amount",
        "semanticType", "decimal"));
orders.put("semanticMeasurements", orderMeas);

// Assembly
List<Map<String, Object>> dataObjects = Arrays.asList(customers, orders);
semanticModel.put("semanticDataObjects", dataObjects);

Map<String, Object> root = new LinkedHashMap<>();
root.put("semantic_model", Collections.singletonList(semanticModel));

Distinguishing Standard and Shared Datasets

Ossie differentiates between standard and shared (non-standard) datasets using the table_type field. Standard datasets carry table_type = "Standard" or rely on defaults applied by the applyDefaults method in DatasetMappingHandler.java.

Non-standard datasets require special handling. The converter stores these in the top-level custom_extensions field via the storeSharedEntitiesInCustomExtensions method. This separation allows the converter to apply Salesforce defaults only to standard datasets while preserving custom extensions for shared entities.

Handling Custom Extensions and Metadata

Properties that do not map to known Ossie fields belong in custom_extensions. The CustomExtensionHandler.java class manages these properties, moving unmapped keys into custom_extensions during conversion to prevent data loss and maintain extensibility.

Map<String, Object> customExt = new LinkedHashMap<>();
customExt.put("vendorTag", "VIP");

// Attach to dataset
customers.put("custom_extensions", customExt);

When converting back to Ossie, the handler automatically restores these extensions from the Salesforce representation.

Applying Platform Defaults After Mapping

After mapping datasets to the target structure, the applyDefaults method in DatasetMappingHandler.java injects required fields such as label and table_type when they are missing. This guarantees that the generated Salesforce model remains valid while keeping the Ossie definition concise.

Invoke this step after dataset mapping but before schema validation to ensure completeness.

Maintaining Clean Mapping Configurations

Use the MappingUtils.filterMappingsByPrefix utility to isolate mappings targeting specific dataset arrays. This approach keeps the conversion pipeline flat and simplifies maintenance when converting between datasets and semanticDataObjects.

For example, filter mappings with the prefix datasets to handle Ossie-to-Salesforce conversion, and use semanticDataObjects for the reverse direction.

Validating Against the JSON Schema

Before persisting or converting a semantic model, run SchemaValidator.validateSemanticModel against the salesforce-semantic-model-schema.json schema. This validation catches structural errors early and ensures compatibility with downstream connectors.

SchemaValidator.validateSemanticModel(root);

Validation should occur after applying defaults and before invoking the conversion pipeline.

When to Use Multiple semantic_model Entries

While the semantic_model array supports multiple entries, most Ossie tools assume a single top-level model. Reserve multiple entries for scenarios requiring independent models to coexist, such as multi-tenant deployments. Per ConverterConstants.SEMANTIC_MODEL, using a single entry avoids unnecessary complexity for standard use cases.

Complete Implementation Example

The following example demonstrates building a multi-dataset semantic model with validation and custom extensions:

import org.apache.ossie.converter.*;
import org.apache.ossie.util.*;
import org.apache.ossie.validator.SchemaValidator;
import java.util.*;

public class MultiDatasetModel {
    public static Map<String, Object> buildModel() {
        Map<String, Object> semanticModel = new LinkedHashMap<>();
        
        // Dataset 1: Customers with custom extension
        Map<String, Object> customers = new LinkedHashMap<>();
        customers.put("apiName", "Customer");
        customers.put("label", "Customer");
        customers.put("table_type", "Standard");
        
        Map<String, Object> custExt = new LinkedHashMap<>();
        custExt.put("dataSource", "CRM");
        customers.put("custom_extensions", custExt);
        
        List<Map<String, Object>> custDims = new ArrayList<>();
        custDims.add(DataStructureUtils.mapOf(
            "apiName", "CustomerId",
            "label", "Customer ID",
            "semanticType", "string"));
        customers.put("semanticDimensions", custDims);
        
        List<Map<String, Object>> custMeas = new ArrayList<>();
        custMeas.add(DataStructureUtils.mapOf(
            "apiName", "LifetimeValue",
            "label", "Lifetime Value",
            "semanticType", "decimal"));
        customers.put("semanticMeasurements", custMeas);
        
        // Dataset 2: Orders
        Map<String, Object> orders = new LinkedHashMap<>();
        orders.put("apiName", "Order");
        orders.put("label", "Order");
        orders.put("table_type", "Standard");
        
        List<Map<String, Object>> orderDims = new ArrayList<>();
        orderDims.add(DataStructureUtils.mapOf(
            "apiName", "OrderId",
            "label", "Order ID",
            "semanticType", "string"));
        orders.put("semanticDimensions", orderDims);
        
        List<Map<String, Object>> orderMeas = new ArrayList<>();
        orderMeas.add(DataStructureUtils.mapOf(
            "apiName", "TotalAmount",
            "label", "Total Amount",
            "semanticType", "decimal"));
        orders.put("semanticMeasurements", orderMeas);
        
        // Assembly
        List<Map<String, Object>> dataObjects = Arrays.asList(customers, orders);
        semanticModel.put("semanticDataObjects", dataObjects);
        
        Map<String, Object> root = new LinkedHashMap<>();
        root.put("semantic_model", Collections.singletonList(semanticModel));
        
        // Validation
        SchemaValidator.validateSemanticModel(root);
        
        return root;
    }
}

Summary

  • Store datasets in the semanticDataObjects array within a single semantic_model entry for standard use cases.
  • Differentiate standard datasets (table_type = "Standard") from shared entities using custom_extensions.
  • Place non-standard properties in custom_extensions to prevent data loss during conversion.
  • Apply Salesforce defaults via applyDefaults after mapping to ensure required fields are populated.
  • Use MappingUtils.filterMappingsByPrefix to maintain clean mapping configurations.
  • Validate models using SchemaValidator.validateSemanticModel before conversion.
  • Reserve multiple semantic_model entries for multi-tenant scenarios only.

Frequently Asked Questions

How many datasets can I store in one Ossie semantic model?

You can store multiple datasets within a single semantic model by adding them to the semanticDataObjects array. The DatasetMappingHandler processes each element as a separate dataset, allowing you to organize related entities like Customers and Orders within one model file.

What is the difference between standard and shared datasets in Ossie?

Standard datasets use table_type = "Standard" and receive automatic default values from the applyDefaults method. Shared (non-standard) datasets do not receive these defaults and are stored in custom_extensions via the storeSharedEntitiesInCustomExtensions method to preserve their unique configurations during Salesforce conversion.

Where should I store vendor-specific metadata that doesn't fit standard Ossie fields?

Place vendor-specific metadata in the custom_extensions field at the dataset level. The CustomExtensionHandler automatically manages these properties during bidirectional conversion, ensuring they persist when translating between Ossie and Salesforce formats without corrupting the standard schema.

When should I use multiple entries in the semantic_model array?

Use multiple semantic_model entries only for multi-tenant deployments or scenarios requiring completely independent models to coexist. Most Ossie tools assume a single entry per the ConverterConstants.SEMANTIC_MODEL definition, so multiple entries introduce unnecessary complexity for standard single-tenant use cases.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →