akamaiesi

Simulating ESI's when working on localhost


I've started using ESI's in Akamai. They work perfectly fine when I've got a site running on int/test/stage/production environments which actually run through Akamai.

However, when we work locally on a PC, we tend to just use a simple jetty server and the site is not served using Akamai. This makes it a bit challenging to see if the work is correct without deploying our solution to Akamai.

Is there a way to simulate an ESI locally for development without using Akamai?


Solution

  • I could not find any official way of doing this, so I emulated a ESI on the server side as if it were an SSI, using an IF statement in our freemarker.

    I use spring, freemarker + java to do this solution:

    1) Create a macro that will decide to use the ESI or emulate it via SSI if running local (noescape may not be required, depends how you have set things up)

    <#macro esi url>
      <#if esiUrl?contains("localhost")>
        <#noescape>${ssiInclude(url)}</#noescape>
      <#else>
        <esi:include src="${esiUrl}/${url}" />
      </#if>
    </#macro>
    

    2) use the macro with the url <@html.esi url="my/url" />

    3) Exposed the SSI Include method in java/spring (you'll need to have setup some environment specific values for esiUrl and the sites base url)

    <bean id="freemarkerViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
        ......
        <property name="attributesMap" ref="staticAttributesMap"/>
    </bean>
    
    <util:map id="staticAttributesMap">
        <entry key="esiUrl" value="${esi.url}" />
    
        <!-- formatters -->
        <entry key="ssiInclude" >
            <bean class="com.channel4.bips.web.freemarker.SsiIncludeMethodModel">
                <property name="urlBase" value="${base.url}/"/>
            </bean>
        </entry>
    
    </util:map>
    

    4) The java to emulate a SSI in freemarker

    import freemarker.template.TemplateMethodModel;
    import freemarker.template.TemplateModelException;
    import org.apache.commons.lang.Validate;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.Reader;
    import java.net.URL;
    import java.util.List;
    
    public class SsiIncludeMethodModel implements TemplateMethodModel {
        private String urlBase;
    
        @Override
        public Object exec(List list) throws TemplateModelException {
            String uri = (String) list.get(0);
            Validate.notNull(uri);
            return readContents(urlBase + uri.trim());
        }
    
        public String readContents(String address) {
            StringBuilder contents = new StringBuilder(2048);
            BufferedReader br = null;
    
            try {
                URL url = new URL(address);
                br = new BufferedReader(new InputStreamReader(url.openStream()));
                String line;
                while ((line = br.readLine()) != null) {
                    contents.append(line);
                }
            } catch (IOException x) {
                x.printStackTrace();
                return "Error getting SSI data";
            } finally {
                close(br);
            }
    
            return contents.toString();
        }
    
        private static void close(Reader br) {
            try {
                if (br != null) {
                    br.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public void setUrlBase(String urlBase) {
            this.urlBase = urlBase;
        }
    }