dot CMS

Migrating Your OSGi Plugins to dotEvergreen: Adapting to the New Index API

Migrating Your OSGi Plugins to dotEvergreen: Adapting to the New Index API

Share this article on:

dotCMS is continuously evolving to stay secure, modern, and maintainable. One of the most significant recent changes involves our migration away from Elasticsearch toward OpenSearch 3.0 as our index provider. This transition required deep refactoring inside our core, and if you maintain custom OSGi plugins that interact with the indexing layer, this post is for you.


Why Is This Happening?

Elasticsearch Has Reached End of Life

Elasticsearch 7.x — the version dotCMS historically shipped with — reached full end of life on January 15, 2026. With EOL comes a halt in security patches, leaving any system running it exposed to known vulnerabilities. Indeed, Elasticsearch 7.x carries multiple documented CVEs, including authentication bypass issues (Field-Level Security), memory disclosure bugs in the 7.10–7.13 range, and denial-of-service vulnerabilities via the Grok parser.

Beyond security, Elastic changed its licensing model in 2021, moving away from the open Apache 2.0 license to the Server Side Public License (SSPL) and its own proprietary Elastic License, neither of which are OSI-approved open-source licenses. This has long-term implications for any platform that bundles Elasticsearch as a core dependency.

The Move to OpenSearch 3.0

OpenSearch, the community-driven fork of Elasticsearch maintained under the Apache 2.0 license, released OpenSearch 3.0 in December 2025. It brings major performance improvements (up to 9.5× over earlier versions), modern ingestion capabilities, and gRPC support — making it the right foundation for dotCMS going forward.

This comes at the perfect time; we are currently in the process of deprecating our dependency on Java 11 in favor of Java 25. This modernization can be seen as a direct continuation of that one, which we discussed at length in a December blog post.

Paying Technical Debt While Modernizing

The migration to OpenSearch 3.0 is also an opportunity to pay down years of technical debt. Our core was tightly coupled to Elasticsearch-specific types — types that don't exist in OpenSearch or any other index provider. To support OpenSearch 3.0 (and potentially other providers in parallel), we introduced a provider-neutral domain layer for all indexing abstractions.

This is a compile-time change. If your plugin references the old Elasticsearch-specific classes directly, it will fail to load at runtime against dotEvergreen.


Is Your Plugin Affected?

Your plugin is affected if it imports any classes from the org.elasticsearch.* namespace or calls deprecated dotCMS APIs tied to Elasticsearch, such as APILocator.getESIndexAPI().

The first sign you will see — if you deploy an unmodified plugin — is a runtime crash like this:

Caused by: java.lang.NoSuchMethodError:
  'com.dotcms.content.elasticsearch.business.ESIndexAPI
   com.dotmarketing.business.APILocator.getESIndexAPI()'

This error means the method signature no longer exists. The class ESIndexAPI and the getESIndexAPI() accessor have been removed. This change was introduced starting with dotCMS version 26.03.06-02. We recommend always building against the latest available release.

The fix requires recompiling your plugin against the new dotCMS core API. Here is how to do that.


Step 1: Configure Your Maven Project

dotCMS core is built with Maven, and our artifacts are published to our Artifactory repository. While you can use other build tools, Maven is strongly recommended for OSGi plugin development as it integrates cleanly with the maven-bundle-plugin (Apache Felix) that generates the OSGi bundle manifest.

Minimum pom.xml skeleton

Below is a clean, ready-to-use skeleton for a dotCMS OSGi plugin project. Replace the groupId, artifactId, and bundle metadata with your own values.

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!-- ===== Project coordinates — adjust to your plugin ===== -->
    <groupId>com.example.dotcms.plugin</groupId>
    <artifactId>my-OSGi-plugin</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>bundle</packaging>

    <properties>
        <bundle.version>1.0.0</bundle.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>

        <!-- Always target the latest dotCMS release -->
        <dotcms-core.version>26.03.20-01</dotcms-core.version>
    </properties>

    <!-- ===== dotCMS Artifactory repository ===== -->
    <repositories>
        <repository>
            <id>dotcms-repo</id>
            <url>https://artifactory.dotcms.cloud/artifactory/libs-release</url>
        </repository>
    </repositories>

    <dependencies>
        <!-- dotCMS core — provided at runtime by the container, compile-only -->
        <dependency>
            <groupId>com.dotcms</groupId>
            <artifactId>dotcms-core</artifactId>
            <version>${dotcms-core.version}</version>
            <scope>provided</scope>
        </dependency>

        <!--
          Add your own compile/runtime dependencies here.
          Use scope=compile for libs that must be embedded in the bundle.
        -->
    </dependencies>

    <build>
        <plugins>
            <!-- OSGi bundle packaging via Apache Felix -->
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <version>5.1.9</version>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Bundle-Vendor>Your Company Name</Bundle-Vendor>
                        <Bundle-Name>My OSGi Plugin</Bundle-Name>
                        <Bundle-Version>${bundle.version}</Bundle-Version>
                        <Bundle-Description>Short description of what this plugin does</Bundle-Description>
                        <Bundle-Activator>com.example.dotcms.plugin.Activator</Bundle-Activator>
                        <Export-Package>com.example.dotcms.plugin</Export-Package>
                        <Import-Package>*;resolution:=optional</Import-Package>
                        <!-- Embed all compile-scoped dependencies into the bundle JAR -->
                        <Embed-Dependency>*;scope=compile|runtime;inline=true</Embed-Dependency>
                        <Embed-Transitive>true</Embed-Transitive>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Note: dotcms-core must be declared with <scope>provided</scope>. It is available in the dotCMS runtime environment and must not be embedded inside your bundle JAR.

Build your plugin

mvn clean package


Step 2: Expect and Fix Compilation Errors

Once you update your dotcms-core.version to the latest release and run mvn compile, you will likely see errors like these:

[ERROR] COMPILATION ERROR :
[ERROR] .../Indexer.java:[102,49]
    incompatible types:
    com.dotcms.content.index.IndexAPI
    cannot be converted to
    com.dotcms.content.elasticsearch.business.ESIndexAPI

[ERROR] .../Indexer.java:[377,66]
    incompatible types:
    com.dotcms.content.index.domain.CreateIndexStatus
    cannot be converted to
    org.elasticsearch.client.indices.CreateIndexResponse

These are your migration checklist. Each compilation error pinpoints exactly where an Elasticsearch-specific type needs to be replaced with its dotCMS domain equivalent. This is by design; the compiler is your guide.


Step 3: Update Your Imports and Types

The New Namespace

All provider-neutral indexing abstractions now live under:

com.dotcms.content.index.domain

The class names were intentionally kept as close as possible to the originals, so mapping old types to new ones is straightforward. Here are the most common substitutions:

Before (Elasticsearch-specific)

After (dotCMS domain-neutral)

org.elasticsearch.client.indices.CreateIndexResponse

com.dotcms.content.index.domain.CreateIndexStatus

com.dotcms.content.elasticsearch.business.ESIndexAPI

com.dotcms.content.index.IndexAPI

APILocator.getESIndexAPI()

APILocator.getIndexAPI()

Example: Updating an Index Operation

Before:

import org.elasticsearch.client.indices.CreateIndexResponse;
import com.dotcms.content.elasticsearch.business.ESIndexAPI;

// ...

ESIndexAPI indexAPI = APILocator.getESIndexAPI();
CreateIndexResponse response = indexAPI.createIndex(indexName, settings);

if (response.isAcknowledged()) {
    // index was created
}

After:

import com.dotcms.content.index.domain.CreateIndexStatus;
import com.dotcms.content.index.IndexAPI;

// ...

IndexAPI indexAPI = APILocator.getIndexAPI();
CreateIndexStatus status = indexAPI.createIndex(indexName, settings);

if (status.isAcknowledged()) {
    // index was created
}

The method semantics remain the same; only the types change.


Step 4: Test Against dotEvergreen

After resolving all compilation errors, deploy your rebuilt bundle to a dotEvergreen instance and verify:

  1. The plugin activates without errors in the OSGi console.

  2. All indexing-related functionality behaves as expected.

  3. No NoSuchMethodError or ClassNotFoundException appears in the logs.


A Note From the dotCMS Team

We want to be transparent: This is a breaking change that we are introducing, and we understand it creates work on your end. We don't take that lightly.

This refactoring is part of a necessary and long-overdue effort to modernize dotCMS's core, remove dependencies on end-of-life software, and build a more secure and sustainable platform for everyone. We know that "necessary" doesn't make it painless, and we genuinely appreciate your patience and understanding as we work through this transition together.

We are committed to making the migration path as clear as possible — and we are here to help every step of the way.


What Has Already Changed

The following classes have had their method signatures updated as of 26.03.06-02:

  • com.dotcms.content.elasticsearch.business.ESMappingAPIImpl

  • com.dotmarketing.portlets.contentlet.business.ContentletFactory

  • com.dotcms.content.elasticsearch.business.ContentletIndexAPI


What's Coming Next

The refactoring is ongoing. The following classes are expected to have signature changes in upcoming releases; we recommend keeping an eye on the release notes if your plugin interacts with any of them:

  • ESIndexAPI

  • ESContentFactoryImpl

  • ESMappingAPIImpl

  • ContentletIndexAPIImpl

  • ReindexThread

  • PermissionBitFactoryImpl

  • ESSearchAPIImpl

  • ESSiteSearchAPI

  • ESContentletAPIImpl

  • ContentTypeAPIImpl

  • ClusterUtil

  • ESContentletScrollImpl

This list will be updated as changes are confirmed. When in doubt, compile early and compile often against the latest dotCMS release; the compiler will tell you exactly what needs attention.


Summary

What changed

Where

Since version

APILocator.getESIndexAPI() removed

com.dotmarketing.business.APILocator

26.03.06-02

ESIndexAPI removed

com.dotcms.content.elasticsearch.business

26.03.06-02

New IndexAPI introduced

com.dotcms.content.index

26.03.06-02

New domain objects

com.dotcms.content.index.domain

26.03.06-02

The bottom line: Update your dotcms-core dependency version, compile, follow the compiler errors, replace each Elasticsearch-specific type with its com.dotcms.content.index.domain equivalent, and you are done.

If you run into issues or have questions about specific API mappings, reach out to dotCMS Support — we're here to help.


dotCMS Engineering Team

Recommended Reading
  • Migrating Your OSGi Plugins to dotEvergreen: Adapting to the New Index API
    24 Mar 26
    Technical Guides

    Migrating Your OSGi Plugins to dotEvergreen: Adapting to the New Index API

    An update on infrastructural changes, information on a breaking change introduced that may affect some plugins, and a migration guide for those affected.

    Fabrizzio

    Fabrizzio Araya

    Software Engineer

  • What Is Rich Text? How It Works in a Headless CMS
    23 Mar 26
    Content Management

    What Is Rich Text? How It Works in a Headless CMS

    What is rich text, and how does it differ from Rich Text Format (.rtf)? Learn how rich text works in content management systems, how headless CMS platforms store it as structured data, and why the format matters for omnichannel delivery.

    Fatima

    Fatima Nasir Tareen

    Marketing Specialist

  • Structured Content for GEO: How dotCMS Powers AI-Ready Digital Experiences
    21 Mar 26
    AI in CMS

    Structured Content for GEO: How dotCMS Powers AI-Ready Digital Experiences

    Discover how dotCMS revolutionizes AI-driven digital experiences with structured content for Generative Engine Optimization (GEO). Learn how our enterprise solution enhances AI visibility, enabling large language models to accurately process and cite machine-readable data. Dive into best practices for creating AI-ready content and explore the benefits of a headless CMS model. Optimize your content for AI discovery and experience seamless omnichannel delivery. Contact us to leverage dotCMS for your AI-powered search needs.

    Fatima

    Fatima Nasir Tareen

    Marketing Specialist

  • AI Content Governance for Content Teams: A Practical Framework
    9 Mar 26
    AI in CMS

    AI Content Governance for Content Teams: A Practical Framework

    Learn why AI content governance is essential for content teams. Discover how to protect brand consistency, reduce legal risk, and manage AI across dozens of sites with dotCMS’s built-in governance tools.

    Fatima

    Fatima Nasir Tareen

    Marketing Specialist

Explore dotCMS for your organization

image

dotCMS Named a Major Player

In the IDC MarketScape: Worldwide AI-Enabled Headless CMS 2025 Vendor Assessment

image

Explore an interactive tour

See how dotCMS empowers technical and content teams at compliance-led organizations.

image

Schedule a custom demo

Schedule a custom demo with one of our experts and discover the capabilities of dotCMS for your business.