Multiple sitemapgenerators overlap | Community
Skip to main content
Level 2
June 14, 2025
Solved

Multiple sitemapgenerators overlap

  • June 14, 2025
  • 2 replies
  • 464 views

We have multiple sitemapgenerators in project some are extended with ResourceTreesitemapGenerator class and some implements SitemapGenerator class and service ranking is kept same for all generators. So I want to invoke a specific generator for a specific root path and but It was observed that the sitemapgenerator with lowest service id is invoked and being used for generating urls in sitemap files. Do I need to do some config to tackle that issue.

This post is no longer active and is closed to new replies. Need help? Start a new post to ask your question.
Best answer by SantoshSai

Hi @tanuj05,

When the same service ranking are registered, and OSGi will invoke the one with the lowest service.id by default, unless a better ranking or filtering mechanism is in place.

Since you're working with multiple generators - some extending ResourceTreeSitemapGenerator and others implementing SitemapGenerator directly - here's how you can correctly control which generator handles which root path.

Solution Overview

You should configure each SitemapGenerator to only apply to specific root paths using the sitemap.resourceTypes or sitemap.paths property. The Apache Sling Sitemap framework relies on this configuration to determine which generator to invoke.

1. Use paths property in your generator service

Each custom generator should explicitly declare the root path(s) it supports:

@Component(
  service = SitemapGenerator.class,
  property = {
    SitemapGeneratorConstants.PROPERTY_PATHS + "=/content/site-a"
  }
)
public class SiteASitemapGenerator implements SitemapGenerator {
    // implementation
}

Use /content/site-b for another generator, and so on.

2. Avoid relying solely on service.ranking

Since service.ranking is only used to resolve ties, and service.id is non-deterministic, it's better to delegate control based on path rather than hoping ranking resolves your issue.

3. Alternative - use a delegator generator

If logic is very dynamic, implement a delegating generator that routes requests based on the root path:

@Component(service = SitemapGenerator.class)
public class DelegatingSitemapGenerator implements SitemapGenerator {
    @Reference
    private List<SitemapGenerator> generators;

    @Override
    public void generate(Resource resource, SitemapGeneratorContext context) {
        for (SitemapGenerator generator : generators) {
            if (generator.appliesTo(resource)) {
                generator.generate(resource, context);
                return;
            }
        }
    }
}

Each generator can implement appliesTo() logic internally based on root path.

4. If you use ResourceTreeSitemapGenerator

That class is built for auto-generating URLs based on resource trees, and it uses resource types to decide what to include. Make sure to configure:

property = {
    "sitemap.resourceTypes=mysite/components/page",
    SitemapGeneratorConstants.PROPERTY_PATHS + "=/content/mysite"
} 

2 replies

SantoshSai
Community Advisor
SantoshSaiCommunity AdvisorAccepted solution
Community Advisor
June 15, 2025

Hi @tanuj05,

When the same service ranking are registered, and OSGi will invoke the one with the lowest service.id by default, unless a better ranking or filtering mechanism is in place.

Since you're working with multiple generators - some extending ResourceTreeSitemapGenerator and others implementing SitemapGenerator directly - here's how you can correctly control which generator handles which root path.

Solution Overview

You should configure each SitemapGenerator to only apply to specific root paths using the sitemap.resourceTypes or sitemap.paths property. The Apache Sling Sitemap framework relies on this configuration to determine which generator to invoke.

1. Use paths property in your generator service

Each custom generator should explicitly declare the root path(s) it supports:

@Component(
  service = SitemapGenerator.class,
  property = {
    SitemapGeneratorConstants.PROPERTY_PATHS + "=/content/site-a"
  }
)
public class SiteASitemapGenerator implements SitemapGenerator {
    // implementation
}

Use /content/site-b for another generator, and so on.

2. Avoid relying solely on service.ranking

Since service.ranking is only used to resolve ties, and service.id is non-deterministic, it's better to delegate control based on path rather than hoping ranking resolves your issue.

3. Alternative - use a delegator generator

If logic is very dynamic, implement a delegating generator that routes requests based on the root path:

@Component(service = SitemapGenerator.class)
public class DelegatingSitemapGenerator implements SitemapGenerator {
    @Reference
    private List<SitemapGenerator> generators;

    @Override
    public void generate(Resource resource, SitemapGeneratorContext context) {
        for (SitemapGenerator generator : generators) {
            if (generator.appliesTo(resource)) {
                generator.generate(resource, context);
                return;
            }
        }
    }
}

Each generator can implement appliesTo() logic internally based on root path.

4. If you use ResourceTreeSitemapGenerator

That class is built for auto-generating URLs based on resource trees, and it uses resource types to decide what to include. Make sure to configure:

property = {
    "sitemap.resourceTypes=mysite/components/page",
    SitemapGeneratorConstants.PROPERTY_PATHS + "=/content/mysite"
} 
Santosh Sai
AmitVishwakarma
Community Advisor
Community Advisor
June 16, 2025

Hi @tanuj05 ,

Try below steps:

1. Generator A - handles /content/site-a

package com.example.core.sitemap; import org.apache.sling.sitemap.generator.SitemapGenerator; import org.apache.sling.sitemap.generator.SitemapGeneratorContext; import org.apache.sling.api.resource.Resource; import org.osgi.service.component.annotations.Component; import static org.apache.sling.sitemap.SitemapGeneratorConstants.PROPERTY_PATHS; @Component( service = SitemapGenerator.class, property = { PROPERTY_PATHS + "=/content/site-a" } ) public class SiteASitemapGenerator implements SitemapGenerator { @Override public void generate(Resource resource, SitemapGeneratorContext context) { // Your logic to generate URLs for /content/site-a } }

2. Generator B - handles /content/site-b

@Component( service = SitemapGenerator.class, property = { PROPERTY_PATHS + "=/content/site-b" } ) public class SiteBSitemapGenerator implements SitemapGenerator { @Override public void generate(Resource resource, SitemapGeneratorContext context) { // Your logic to generate URLs for /content/site-b } }

Note:

NEVER rely on service.ranking or service.id for sitemap routing.

Sling Sitemap automatically invokes the generator based on the path match (sitemap.paths) if defined.

You can use multiple paths like:

property = { PROPERTY_PATHS + "=/content/site-a", PROPERTY_PATHS + "=/content/another-site" }


Regards,
Amit