Search code examples
javaaemsling

Unable to get component of class 'interface org.apache.sling.rewriter.Transformer' with type 'linkrewriter'


I'm upgrading an AEM project from version 6.0 to 6.3 but I'm getting the error Unable to get component of class 'interface org.apache.sling.rewriter.Transformer' with type 'linkrewriter'.

My code

import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.cocoon.xml.sax.AbstractSAXPipe;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.rewriter.ProcessingComponentConfiguration;
import org.apache.sling.rewriter.ProcessingContext;
import org.apache.sling.rewriter.Transformer;
import org.apache.sling.rewriter.TransformerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import java.io.IOException;

@Slf4j
@Properties({
        @Property(
                name = "pipeline.type",
                value = "linkrewriter",
                propertyPrivate = true
        ),
        @Property(
                name = "webconsole.configurationFactory.nameHint",
                value = "Pipeline: {pipeline.type}"
        )
})
@Component(metatype = true,
        label = "Clientlib Link Rewriter Transformer"
)
@Service(value = TransformerFactory.class)
public class LinkRewriterTransformer extends AbstractSAXPipe implements Transformer, TransformerFactory {

    private SlingHttpServletRequest request;

    private static final String SRC_ATTR = "src";
    private static final String JS_ELEM = "script";
    private static final String HREF_ATTR = "href";
    private static final String CSS_ELEM = "link";
    private static final String IMG_ELEM = "img";
    private static final String ANCHOR_ELEM = "a";

    private static final String DAM_PATH = "/content/dam/my-application";
    private static final String CONTENT_PATH = "/content/my-application";
    private static final String ASSET_PATH = "/etc";

    @Override
    public void init(ProcessingContext context, ProcessingComponentConfiguration config) throws IOException {
        this.request = context.getRequest();
        log.info("Transforming request {}", request.getRequestURI());
    }

    @Override
    public void dispose() {
        // Required for implementing interface; no action needed
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
        AttributesImpl linkAttrs = new AttributesImpl(attrs);

        String attrName = "";

        if (JS_ELEM.equalsIgnoreCase(localName) || IMG_ELEM.equalsIgnoreCase(localName)) {
            attrName = SRC_ATTR;
        }
        else if (CSS_ELEM.equalsIgnoreCase(localName) || ANCHOR_ELEM.equalsIgnoreCase(localName)) {
            attrName = HREF_ATTR;
        }

        if (attrName.length() > 0) {
            for (int i = 0; i < linkAttrs.getLength(); i++) {
                String mappedPath = getMappedAttributeUrl(attrName, linkAttrs, i);
                if (!mappedPath.isEmpty()) {
                    linkAttrs.setValue(i, mappedPath);
                }
            }

        }

        super.startElement(uri, localName, qName, linkAttrs);
    }

    private boolean pathMatches(String pathInLink) {
        return pathInLink.startsWith(ASSET_PATH) || pathInLink.startsWith(DAM_PATH) || pathInLink.startsWith
                (CONTENT_PATH);
    }

    private String getMappedAttributeUrl(String attrName, AttributesImpl linkAttrs, int index) {
        if (attrName.equalsIgnoreCase(linkAttrs.getLocalName(index))) {
            String pathInLink = linkAttrs.getValue(index);
            if (!pathInLink.isEmpty() && pathMatches(pathInLink)) {
                String mappedPath = request.getResourceResolver().map(request, pathInLink);
                log.info("Transforming {} to {}", pathInLink, mappedPath);
                return mappedPath;
            }
        }
        return "";
    }

    @Override
    public Transformer createTransformer() {
        return new LinkRewriterTransformer();
    }
}

My config node placed in /apps/<application>/config/rewriter

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
  jcr:primaryType="nt:unstructured"
  contentTypes="[text/html]"
  enabled="{Boolean}true"
  generatorType="htmlparser"
  order="1"
  serializerType="htmlwriter"
  resourceTypes="[my-application/pages/base]"
  paths="[/content/my-application]"
  transformerTypes="[linkchecker,mobile,mobiledebug,contentsync,linkrewriter]">
  <transformer-mobile jcr:primaryType="nt:unstructured" component-optional="{Boolean}true"/>
  <transformer-mobiledebug jcr:primaryType="nt:unstructured" component-optional="{Boolean}true"/>
  <transformer-contentsync jcr:primaryType="nt:unstructured" component-optional="{Boolean}true"/>
</jcr:root>

Solution

  • Since AEM 6.3, the apache felix scr annotations are replaced with OSGI R6 annotations. The linkrewriter needs to be rewritten. Please use this reference link and write the rewriter again: https://helpx.adobe.com/experience-manager/using/aem63_link_rewriter.html

    This specific error above might be due to bundle not started. You may need to try with /system/console/depfinder to check if all required package dependencies are available. Earlier instance restart resolved this same error for me.