Delivery Framework 4

Redirects

This page explains how the webapp handles the different redirect-logics.

Implement the IRedirectBuilder for creating browser redirect (301) or return other HTTP-Code with browser or internal redirect

It is possible to create a redirect by providing a implementation of the interfaces com.subshell.sophora.delivery.api.seo.IRedirectBuilder in your web application. There should be at most one implementation of the interface in your web application. This implementations should be placed inside the function package, which is configured via the configuration key 'sophora.delivery.function.packageNames'. That implementation are afterwards automatically used by the sophora delivery, without any further configuration.

Before Delivery-Versions 2.2.25,  2.3.18,  2.4.9,  2.5.6,  2.6.0, the IRedirectBuilder interface only implemented one method: createRedirectUrl().
From the abovementioned Versions on, there is another Method called createRedirectResult(), and the old Method is deprecated.

String createRedirectUrl(SophoraUrl url, IContentMapContext context);
RedirectResult createRedirectResult(SophoraUrl url, IContentMapContext context)

RedirectResult and RedirectResult.Type

Creating a RedirectResult with one of the two constructors. If you create a RedirectResult only with the redirectUrl, this will be the default for a 301 browser redirect:

new RedirectResult(String redirectUrl)

new RedirectResult(int statusCode, String redirectUrl, Type type, Map<String, String> additionalHeaders)

There are 2 types of RedirectResults in IRedirectBuilder: Type {BROWSER_REDIRECT, INTERNAL_REDIRECT}

The Type.BROWSER_REDIRECT works as before, by default throws an HTTP code 301 and sets a location header which forwards to the specified URL.
It is visibly redirected to the new URL in the browser.

With the new Type INTERNAL_REDIRECT, the specified URL is run through the URLDecoderFilter again, and processed in the further filter chain as request URL.
For example, this can throw an HTTP code 410, a URL is generated to an error document and played under the unreachable URL.
The actual URL remains in the browser.

An example implementation

There is an example implementation in the sophora demosite, all sophora ids that are not in the system will be redirected with HTTP-Code 301 to "Berlin-City-of-Design100" or the alternate URL for that document. In this example, a solr query is made to the 'default' core. The only document in the search result ("Berlin-City-of-Design100") will be used for generate a redirect URL by context.createUrl(). The return value for createRedirectUrl() shouldn't include the site (eg "/demosite") inside the path. For unknown StructureNodes, the example generates a RedirectResult with HTTP-Code 410 and the RedirectResult.Type.INTERNAL_REDIRECT. For unknown StructureNodes, you have to check if the sophoraId equals "index". If the return value is null, no redirect will be executed.

public class DemositeRedirectBuilder implements IRedirectBuilder {

	private static final Logger log = LoggerFactory.getLogger(DemositeRedirectBuilder.class);

	private final String[] fields = { "*" };

	@Override
	public String createRedirectUrl(SophoraUrl url, IContentMapContext context) {

		if ("jsp".equals(url.getSuffix())) {
			return null;
		}
		SolrQuery solrQuery = new SolrQuery();

		solrQuery.setQuery("sophora_id_s:Berlin-City-of-Design100");
		solrQuery.setFields(fields);
		solrQuery.setRows(1);
		solrQuery.setStart(0);

		solrQuery.addSort("score", ORDER.desc);


		SolrResult solrResult = SolrClient.query("default", solrQuery);
		String redirectUrl = null;
		if (solrResult != null && !solrResult.getEntries().isEmpty()) {
			SolrDocument solrDocument = solrResult.getEntries().get(0);
			redirectUrl = context.createUrl(false, false, true, (String) solrDocument.getFieldValue("sophora_id_s"), (String) null, (String) null, (String) null, new HashMap<String, Object>(), new HashMap<String, Object>(), null, null);
			redirectUrl = "/" + StringUtils.substringAfter(redirectUrl.replaceFirst("/", ""), "/");
			log.info("Creating redirect url {} for sophora id {}", redirectUrl, url.getSophoraId());
		}

				return redirectUrl;
	}

	@Override
	public RedirectResult createRedirectResult(SophoraUrl url, IContentMapContext context) {
		if ("index".equals(url.getSophoraId())) {
			return new RedirectResult(410, createRedirectUrl(url, context), Type.INTERNAL_REDIRECT, null);
		}
		return new RedirectResult(createRedirectUrl(url, context));
	}
}

Creating redirects per templates.xml

Using the Sophora templates.xml mechanism, and what needs to be done in order to make redirects work in your project.

Overview

With redirects you can link directly to arbritrary URLs, JSP templates or Sophora documents. Redirects can also be used to map non-existent paths to existing ones.

The logic of redirects is defined in a JSP template, which needs to be mapped for the document type "sophora-nt:shortcut" in the templates.xml.

Exemplary handling of a redirect:

Redirect URL: youtsitename/redirect_01/index.html

  1. For this URL the "index.html" is applied. Since there is no structure node called "/yoursitename/redirect_01", the appropriate redirect entry is searched for.
  2. If such an entry exists, the node type is set to "sophora-nt:shortcut". (The name "shortcut" and "redirect" are interchangeable in this context.)
  3. The JSP template defined for the default type (/yoursitename/templates/shortcut.jsp) is used.
  4. The redirection and integration logic are managed by the JSP template.

The nodetype "sophora-nt:shortcut" and the Shortcut object

The node type "sophora-nt:shortcut" does not really exist as a document type in the repository. It is modeled that way to apply the templates.xml to handle the redirects. Therefore, "this" in the JSP becomes a Shortcut object (com.subshell.sophora.delivery.template.Shortcut).

In the JSP you have access to the following members of the Shortcut object (which is available under the variable "this"):

MemberFunction
String getExternalId()Returns the externalId this shortcut directs to, if any. Only applies when the shortcut is defined in the templates.xml, not in the Deskclient.
List getPathList()Returns the list of paths this shortcut is mapped to. This is needed by the sophora delivery to detect when a shortcut applies. There is no reason to access it in the JSP template.
String getSophoraId()Returns the sophoraId this shortcut directs to, if any. Only applies when the shortcut is defined in the templates.xml, not in the Deskclient.
SophoraUrl getSophoraUrl()Returns the SophoraUrl object of the shortcut. Only applies when the shortcut type is "MAPPING"
String getStaticUrl()Returns the static Url this shortcut directs to, if any. Only applies when the shortcut is defined in the templates.xml, not in the Deskclient.
String getStructurePath()Returns the structurePath this shortcut directs to, if any. Only applies when the shortcut is defined in the templates.xml, not in the Deskclient.
Type getType()Returns the type of the shortcut.
String getUrl()Returns the Url this shortcut directs to, if any.
String getUuid()Returns the Uuid this shortcut directs to, if any.
String getChannelUuid()Returns the Uuid of the channel if set; in case of the default channel null will be returned.

JSP Template for Redirects

If you want to use redirects and the following code/configuration examples don't already exist in your webapp, you can simply copy them from here.

Excerpt from the templates.xml:

<nodetypelist>
    ...
         <nodetype name="sophora-nt:shortcut">
         <templateset>
              <template type="default">/yoursitename/templates/shortcut.jsp</template>
             </templateset>
         </nodetype>
    ...
    </nodetypelist>

The jsp template with the redirect logic (which can be adapted to your needs if necessary):
File /yoursitename/templates/shortcut.jsp

<%@ page session="false"%>
<%@ taglib uri="http://www.subshell.com/sophora/jsp" prefix="sophora"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
 
<c:choose>
    <c:when test="${current.type == 'MAPPING' && !empty current.structurePath && !empty current.sophoraUrl.sophoraId}">
        <sophora:getStructureNodeByPath var="structureNode" path="${current.structurePath}" />
        <sophora:url structureNodeUuidForLabeling="${structureNode.uuid}" sophoraId="${current.sophoraUrl.sophoraId}" urlParams="${parameters}" suffix="${current.sophoraUrl.suffix}" labeled="true" forceLabeled="true" type="${current.sophoraUrl.templateName}" var="shortcutUrl" />
    </c:when>
    <c:when test="${!empty current.uuid}">
        <sophora:url uuid="${current.uuid}" var="shortcutUrl"/>
    </c:when>
    <c:when test="${!empty current.sophoraId}">
        <sophora:url sophoraId="${current.sophoraId}" var="shortcutUrl"/>
    </c:when>
    <c:when test="${!empty current.externalId}">
        <sophora:url externalId="${current.externalId}" var="shortcutUrl"/>
    </c:when>
    <c:when test="${!empty current.url}">
        <c:set var="shortcutUrl" value="${current.url}" />
    </c:when>
    <c:when test="${!empty current.staticUrl}">
        <sophora:staticUrl path="${current.staticUrl}" var="shortcutUrl" params="${urlParam}"/>
    </c:when>
</c:choose>
<c:choose>
    <c:when test="${current.type == 'SSI' && !empty shortcutUrl}">
        <sophora:ssi path="${shortcutUrl}"/>
    </c:when>
    <c:when test="${(current.type == 'METAREDIRECT' || current.type == 'MAPPING') && !empty shortcutUrl}">
        <?xml version="1.0" encoding="ISO-8859-1" ?>
        <html>
            <head>
                <meta http-equiv="refresh" content="0; URL=${shortcutUrl}">
            </head>
            <body>
            </body>
        </html>
    </c:when>
    <c:otherwise>
        <% response.sendError(404); %>
    </c:otherwise>
</c:choose>

Notes on redirects and query parameters in a custom URL codec

When a custom URL codec is used, the target URL of the redirect will be passed to the decode() method of the codec. Note that standard URL query parameters will be stripped from the URL, whereas Sophora-style URL parameters will be left intact. If you need to access the query parameters of the original URL in your custom codec, you can get the complete original URL from the current request:

  @Override
  public SophoraUrl decode(String url) {
        HttpServletRequest request = DeliveryUtils.getRequest();
        System.out.println(request.getRequestURI());
        System.out.println(request.getRequestURL());
        System.out.println(request.getQueryString());
        ...
  }

Last modified on 10/16/20

The content of this page is licensed under the CC BY 4.0 License. Code samples are licensed under the MIT License.

Icon