I like my method pointers with curry in Groovy

Invoking a method several times can easily be done in Java in a loop. But what if we have several methods that need to be executed several times? Since Java does not feature pointers to functions, we cannot pass functions around, and cannot create a generic method that takes a pointer to a method and executes it. This is where Groovy shines.

Suppose we want to check on the status of some external system or work. We want to check the status every half a second for a maximum of ten times in total.

// the generic type in Closure<Boolean> indicates its return type
boolean isOperationSuccessful(int numOfTries, Closure<Boolean> action) {
    Thread.sleep(500)
    for (i in 0..<numOfTries) {
        if (action()) {
            return true
        } else {
            Thread.sleep(500)
        }
    }
}

// we can pass closures...
def check = { int n -> new Random().nextInt(10) == n }
println isOperationSuccessful(10, check.curry(3))

// ... as well as methods
boolean isWorkDone(int id) {
    // check if particular external system identified by `id` is done
    return new Random().nextInt(2) == 1
}
// `.&` is the method pointer operator
println isOperationSuccessful(5, this.&isWorkDone.curry(1))

We can pass methods around by referencing them with the method pointer operator .&:

def pointerToUpper = 'hello world'.&toUpperCase
assert pointerToUpper() == 'HELLO WORLD'

By using Groovy’s take on currying, we can fix parameters of a closure (or method):

def power(double n, int exponent) { n ** exponent }
def squared = this.&power.rcurry(2)
assert squared(12) == 144

rcurry fixes the right-most argument of the method, curry the left-most. (And yes, there is also an index-based method: ncurry). Both return a new Closure that takes one less argument.

How to ignore an invalid SSL certificate in Java?

Sometimes during development it is useful to use a certificate whose CN (Common Name) does not match the host name in the URL, for example localhost. In these cases Java will throw a SSLHandshakeException. How can we easily disable certificate checking for localhost and other domains of our choosing?

Your own certificate checking

The easiest way is to create your own class that implements the interface HostnameVerifier:

WhitelistHostnameVerifier.java

package com.relentlesscoding.https;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import java.util.HashSet;
import java.util.Set;

// singleton
enum WhitelistHostnameVerifier implements HostnameVerifier {
    // these hosts get whitelisted
    INSTANCE("localhost", "sub.domain.com");

    private Set whitelist = new HashSet<>();
    private HostnameVerifier defaultHostnameVerifier =
            HttpsURLConnection.getDefaultHostnameVerifier();

    WhitelistHostnameVerifier(String... hostnames) {
        for (String hostname : hostnames) {
            whitelist.add(hostname);
        }
    }

    @Override
    public boolean verify(String host, SSLSession session) {
        if (whitelist.contains(host)) {
            return true;
        }
        // important: use default verifier for all other hosts
        return defaultHostnameVerifier.verify(host, session);
    }
}

Main.java

// use our HostnameVerifier for all future connections
HttpsURLConnection.setDefaultHostnameVerifier(
        WhitelistHostnameVerifier.INSTANCE);
final String url = "https://relentlesscoding.com";
HttpsURLConnection conn =
        (HttpsURLConnection) new URL(url).openConnection();
System.out.println(conn.getResponseCode());

HttpsURLConnection.DefaultHostnameVerifier#verify always returns false, so we might as well return false ourselves, but this way the code will keep working when the implementation of HttpsURLConnection changes.

Note: you can set the default HostnameVerifier globally by using the static method setDefaultHostnameVerifier, or you can set it per instance, using conn.setHostnameVerifier.

Problems with Let’s Encrypt certificates

One thing I found out while testing this, was that OpenJDK version 1.8.0_131 won’t correctly handle Let’s Encrypt certificates:

java.io.IOException: HTTPS hostname wrong: should be <relentlesscoding.com>

This is due to the fact that Let’s Encrypt certificates are not present in the Java installation. Upgrading to version 1.8.0_141 resolves this (for Oracle versions >= 8U101 or >= 7U111).

Whitelisting, NOT disabling certificate checking

The best approach here is whitelisting. This will keep the certificate checking in place for most sites, and will only disable it for pre-approved hosts. I saw quite a bit of examples online that disable certificate checking completely, by writing the verify method as follows:

public boolean verify(String hostname, SSLSession session) {
    return true;
}

This is not secure, as it completely ignores all invalid certificates.

Creating custom Intershop ISML functions with CustomTag

The problem

I wanted to capitalize a certain value from the pipeline dictionary in an ISML template. Intershop provides ISML functions of the kind ucase and lcase to transform a string to uppercase or lowercase respectively. When the value of the dictionary name Product:Name is AwesomeNotebook:

<isprint value="#ucase(Product:Name)#">

this will print AWESOMENOTEBOOK. Unfortunately, a similar function to capitalize a string is not provided by Intershop. Ideally, you would want to be able to implement your own methods, so that you could type:

<isprint value="#capitalize(Product:Name)#">

What about custom modules?

Intershop does provide the ability to create custom modules. These are basically just tags you can give whatever name you like, and you can provide an implementation in Java or ISML. The interface is defined in a modules.isml file. You could, for example, define a custom tag isprintdefault that prints a default value whenever the value passed to it is null or the empty string:

<isprintdefault default="(unknown)" value="#Product:Price">

This would print (unknown) every time Product:Price does not contain a value.

This solution, however, has two drawbacks:

  • For a Java implementation, this would come down to writing scriptlet. A few lines of scriptlet is fine ofcourse, but as the size of the code increases, it becomes harder and harder to maintain, because there is no compilation-time check and debugging is nearly impossible (say hello to a thousand print statements).
  • Also, it is cumbersome for implementing something like the capitalize function mentioned above, because you would have to provide the input to the custom module, put the result in the pipeline dictionary, and then use the pipeline dictionary name:
<iscapitalize dictname="capitalizedStr" input="#Product:Name#">
<isprint value="#capitalizedStr#">

Instead of just using the returned capitalized string directly:

<isprint value="#capitalize(Product:Name)#">

Solution: ISML Custom Tag

An ISML custom tag looks just like a custom module:

<ISUUID name="CategoryRenderEntityID">

(Incidently, this creates a UUID and stores it in the pipeline dictionary variable name CategoryRenderEntityID). According to the documentation, the difference between a custom tag and a custom module is that the former “provides a significant performace increase” compared to the latter.

Two purposes

Custom tags can be used for two purposes:

  • Performing a single operation, like we saw with the ISUUID custom tag above, where the tag performs a single action (creating a new UUID and putting it in the pipeline dictionary).
  • Inserting an instance of a helper or utilities class into the pipeline dictionary.

Creating an ISML Custom Tag

Say, we want to create an ISML Custom Tag named <ishelper>. First, we would define it in a modules.properties file, located at <cartridge>/staticfiles/cartridge/config/modules.properties:

ismodules.helper.class=custom_base.internal.modules.Helper
ismodules.helper.isStrict=false
ismodules.helper.parameters=alias
ismodules.helper.parameter.alias.type=java.lang.String
ismodules.helper.parameter.alias.isRequired=false

The class property should point to the implementing Java class. Since a pipeline dictionary is available to custom tags, we can define whether we want a clean, strict dictionary or not, much like we can do in pipelines. Parameters and return values can be defined by providing their name, type and whether or not they are mandatory.

So, the properties file above defines a custom tag <ishelper> (put a leading is to your lowercase class name), that has an optional attribute alias of type String. Other parameters can be added by using comma’s:

ismodules.helper.parameters=alias,more,params

Don’t forget to also add a type and whether the parameter is required or not. The type of the parameter can be any Java class, so you’re not limited to just strings.

The Java class with the implementing code must extend the abstract class CustomTag. It is required to override the method processOpenTag, which will be called every time the custom tag is encountered in the ISML template.

Now then, we can create “custom ISML functions” by adding an instance of our Helper class to the pipeline dictionary:

public class Helper extends CustomTag {
    @Override
    public void processOpenTag(PageContext paramPageContext,
                               ServletResponse paramServletResponse,
                               AbstractTemplate paramAbstractTemplate,
                               int paramInt)
            throws IOException, ServletException
    {
        PipelineDictionary dict = AbstractTemplate
                .getTemplateExecutionConfig()
                .getPipelineDictionary();
        String alias = dict.getOptional("alias", "Helper");
        dict.put(alias, new Helper());
    }
}

If we wanted a function capitalize in our templates, we could add such a method to our Java class:

public String getCapitalize(String str) {
    /* do groundbreaking stuff */
    return capitalizedStr;
}

Note that the method name should start with get in order for it to be available in the pipeline dictionary in our templates. We can now use the method as follows:

<isprint value="#Helper:Capitalize(Product:Name)#">

Don’t forget, however, to add the custom tag somewhere at the beginning of the template before using it:

<ishelper alias="MyCustomUtilsClass">
<!-- snip -->
<isloop iterator="MyProducts" alias="product">
    <isprint value="#MyCustomUtilsClass:Capitalize(product:Name)#"
</isloop>

(Note that the alias attribute is optional. If you leave it out, it will default to Helper: see the implementation above. This will be the alias of the class we’re using to invoke methods on:

<isprint value="#MyCustomUtilsClass:noArgMethod()#">

Remember that the name of the actual class that contains the custom tag is part of the tag name: ishelper.)

Alternative method of making a Java class available in the pipeline dictionary

Obviously, we do not have to rely on an ISML custom tag to put an instance of a Java class in the pipeline dictionary. We could just create a pipelet that does this, and put this pipelet in a pipeline that gets called a lot (a Prefix pipeline would be good). This would remove the need to put <ishelper> (or whatever we named the custom tag) at the top of our templates. But the helper class would only be available if the Prefix pipeline was called, so you would need to check that carefully. Putting the custom tag at the top of the template makes the import explicit and easily verifiable.

A word of caution

Custom tags are very handy, but they extend the internal CustomTag class. This means Intershop does not encourage using them in custom project development. In fact, you won’t find any information about them in the documentation.

Java stateful sessions or: how to properly send cookies with each redirect request

The problem

I needed to login to some webpage programmatically. It happened to be one of those pages where, when the login succeeds, the user is redirected to another page, and then to another (something along the lines of ‘Please login’ -> ‘You are successfully logged in’ -> ‘Admin panel’). So I needed to write something that would store the cookies that come along with each response, and send those cookies out with each subsequent request. With curl, I would have used:

$ curl --location --cookie-jar logincookie 'https://login.securepage.com'

So how can we mock this behavior in Java?

Java SE’s CookieHandler

A simple DuckDuckGo search will show Java SE’s own java.net.CookieHandler: pretty neat, a built-in solution! The CookieHandler, as the name suggests, will handle all your floating-point arithmetic. Just kidding, it will serve as the object where the HTTP protocol handler (used by objects such as URL) will go to to check for relevant cookies. CookieHandler is a global abstract class that will handle the state management of all requests.

CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(cookieManager);

CookieManager’s task is to decide which cookies to accept and which to reject. CookiePolicy.ACCEPT_ALL will accept all cookies. Other choices include CorkiePolicy.ACCEPT_NONE (no cookies will be accepted) and CookiePolicy.ACCEPT_ORIGINAL_SERVER (only cookies from the original server will be accepted).

If you want, you can also create a CookieManager with a specific CookieStore and specify exactly where your cookies will be stored. This is needed, for example, to create persistent cookies that can be restored after a JVM restart. By default, CookieManager will create an in-memory cookie store.

To install our own system-wide cookie handler, we invoke CookieHandler.setDefault and pass our CookieManager as an argument.

The tutorial on the Oracle website does a pretty decent job of explaining everything in more detail.

If this works for you, great! If not, keep on reading.

Apache HttpComponent Client to the rescue

Unfortunately, the steps above did not work for me as the server kept complaining that the session was invalid after the redirects. After reading somewhere on StackOverflow that Java SE’s version of the CookieStore was buggy, and me being on a deadline, I decided to turn my attention to Apache and their HttpComponent Client (version 4.5.3):

import org.apache.http.client.CookieStore;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
// ... other imports

class Downloader {
    private CookieStore cookieStore = new BasicCookieStore();

    private void doLogin() {
        // CookieSpecs.STANDARD is the RFC 6265 compliant policy
        RequestConfig requestConfig = RequestConfig
                .custom()
                .setCookieSpec(CookieSpecs.STANDARD)
                .build();

        // automatically follow redirects
        CloseableHttpClient client = HttpClients
                .custom()
                .setRedirectStrategy(new LaxRedirectStrategy())
                .setDefaultRequestConfig(requestConfig)
                .setDefaultCookieStore(cookieStore)
                .build();

        String addr = "https://login.securehost.com";
        HttpPost post = new HttpPost();

        // login and password as payload for POST request
        List<NameValuePair> urlParams = new ArrayList<>();
        urlParams.add(new BasicNameValuePair("login", "neftas"));
        urlParams.add(new BasicNameValuePair("password", "letmein"));
        post.setEntity(new UrlEncodedFormEntity(urlParams));

        HttpResponse response = client.execute(post);
        // ... and we are logged in!
    }
}

(To keep the code clean, I’ve not bothered with any exception handling.)

The RequestConfig serves to indicate what kind of cookie policy we want (there are several, unfortunately). If you just want things to work, you can start with CookieSpecs.STANDARD, which is compliant with “a more relaxed profile defined by RFC 6265”.

During the creation of the HttpClient, we specify that we want to follow all redirects (setRedirectStrategy(new LaxRedirectStrategy())), we pass the cookie policy we defined earlier in the RequestConfig, and lastly, we pass the cookie store.

Adding a file to the root of your Gradle distribution

A while ago, I needed to write a program that retrieved some information from the database by using SQL queries located in files. I wanted to add a file that would contain the settings of the app, like the port, SID, login and password for the database, but also the location of those queries. The problem was I couldn’t add those settings to a file in the standard src/groovy/resources folder, because when creating a distribution with Gradle ./gradlew distZip the file would be part of the jar, and thus it would be difficult to modify the contents. I was basically after a run-control file, a settings file in the root of my distribution, that I could easily change on each run (if necessary).

Gradle provides several ways to accomplish this:

  1. Add the file to src/dist and the file will be put in the root of the distribution after invoking ./gradlew installDist. Any folders you create will also be put in the distribution, so you can create src/dist/config, for example, to put your configuration in, and a folder config will be created in the distribution.
  2. Indicate to Gradle that you want a certain file or folder copied:

    applicationDistribution.from('config.properties') {
        into ''
    }
    
  3. Use the distribution plugin:

    apply plugin: 'distribution'
    
    distributions {
        main {
            contents {
                from {
                    'settings.groovy'
                }
            }
        }
    }