Search code examples
groovyhippocms

How can generate URLs, within the Hippo groovy updater, for documents which have a sitemap entry?


Some question context

At the moment I am developing some redirect logic in a HippoCMS powered website, to create 301 redirects for URLs on the old website to their corresponding pages on the new website.

For the old website i only have access to a "title to URL" based index. No further access is possible. The Hippo documents in the new website are created with the exact same title as the old website. So a match should theoretically be possible.

The reason for the development approach is the fact that there are more then 7000 pages that need redirecting. Doing this manually (with the UrlRewriter plugin) would mean 40+ hours of mind numbing work.

Current development

I have created a Groovy updater script which SHOULD ;

  1. Traverse through all nodes
  2. For content nodes match the document title to the old index
    • When a match is present, retrieve the old URL
  3. The problems lies here: Retrieve the new URL
    • The document has a resolvable path in the sitemap
  4. Store as a new node in the urlrewriter plugin repository section

The code

import org.hippoecm.hst.configuration.hosting.Mount;
import org.hippoecm.hst.container.RequestContextProvider;
import org.hippoecm.hst.core.linking.HstLink;
import org.hippoecm.hst.core.linking.HstLinkCreator;
import org.hippoecm.hst.core.request.HstRequestContext;

class UpdaterTemplate extends BaseNodeUpdateVisitor {

    boolean doUpdate(Node node) {
        def HstRequestContext = RequestContextProvider.get();
        def mount = HstRequestContext.getMount();
        def linkCreator= temp.getHstLinkCreator();
        def link = linkCreator.create(node.path, mount);
        def url = link.toUrlForm(HstRequestContext);

        // Output the url
        log.debug(url);
    }
}

The code was based upon a hippo example page about rewriting links

The problem

I can not seem to be able to retrieve the URL for the new website. All other steps are working fine and i have the document JCR node on the new site. I only cannot generate an URL.

The first errors i got made clear that the CMS could not resolve some of the HST classes.

ERROR Cannot run updater: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
updater: 8: unable to resolve class org.hippoecm.hst.container.RequestContextProvider
 @ line 8, column 1.
   import org.hippoecm.hst.container.RequestContextProvider
   ^

1 error

This was easily fixed by updating my pom.xml. Only for the duration of development. Will be reset afterwards.

Then the real problem arose, the HstRequestContext is null.

ERROR Updating /content/documents/XYZXYZ failed - java.lang.NullPointerException: Cannot invoke method getMount() on null object

Of course this makes sense, since we do not have a real context. But still... how else should i generate the URLs, without a copy of the full sitemap logic.

Am i on a completely bogus path? Or am i missing something? Please help me out.


Solution

  • HST libraries/context is not available within CMS part (those two are separate apps, with different context/lifecycle). I think easiest would be to create an HST component instead of groovy script (you can use getPersistableSession(request) to write data to the repository), or make a HST REST service which you can call to resolve the links. One such a service already exists, but you'll need to authenticate it: http://127.0.0.1:8080/site/_cmsrest/documents/DOCUMENT_UUID/url/live

        private static final String CMSREST_CREDENTIALS_HEADER = "X-CMSREST-CREDENTIALS";
    private static final String CMSREST_CMSHOST_HEADER = "X-CMSREST-CMSHOST";
    private static final String CREDENTIAL_CIPHER_KEY = "ENC_DEC_KEY";
    
    
    
    public String getUrl(final String url) throws IOException {
        final CredentialCipher credentialCipher = CredentialCipher.getInstance();
        final String encryptedCredentials = credentialCipher.getEncryptedString(CREDENTIAL_CIPHER_KEY, new SimpleCredentials(user, password.toCharArray()));
        try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
            final HttpGet httpget = new HttpGet(url);
            httpget.setHeader(CMSREST_CREDENTIALS_HEADER, encryptedCredentials);
            httpget.setHeader(CMSREST_CMSHOST_HEADER, encryptedCredentials);
            log.info("Executing request {}", httpget.getRequestLine());
            final ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
                public String handleResponse(final HttpResponse response) throws IOException {
                    final int status = response.getStatusLine().getStatusCode();
                    if (status >= 200 && status < 300) {
                        final HttpEntity entity = response.getEntity();
                        return entity != null ? EntityUtils.toString(entity) : null;
                    } else {
                        log.error("Invalid status: {}", status);
                        return null;
                    }
                }
    
            };
            return httpclient.execute(httpget, responseHandler);
    
        }
    }
    

    Note: just replace DOCUMENT_UUID with your own uuid. This must be uuid of document handle.

    HTH