wissel.net

Usability - Productivity - Business - The web - Singapore & Twins

Fun with {{Mustache}}

This article is part of a mini series. Read them all:

  1. Fun with {{Mustache}} and Notes Forms
  2. CKEditor and Mustache become friends
  3. Mustache and CKEditor - Round two
  4. Creating nginx configurations for Domino SSL
  5. {{Mustache}} Helper for Domino and XPages
  6. Mail Merge with XPages
  7. Command line mail merge

Creating nginx configurations for Domino SSL

Hero image for Creating nginx configurations for Domino SSL
Websites need to be secure, so the SHA-1 cipher is coming to an end. Despite best efforts, Domino is stuck with this outdated Cipher. While you can, on Windows, hide Domino behind IHS, I find nginx easier to tame.
Jesse explains how to configure nginx as the Domino proxy. So all is good, expecially since he also covered High availability.
But when you have a lot of sites, that's a lot of typing (and copy & paste from the Internet site documents). Mustache to the rescue! I've written about Mustache before and it suits the task quite nicely:
  1. Create one well working sample configuration
  2. Replace the site specific values with {{mustache}} variables
  3. Run it against all Internet site documents
The code I used (see below) generates just 4 variables:
  1. {{name}} The name of the site according to the configuration document. I use it here to configure the file name
  2. {{siteName}}The first web name, it will become the listen parameter
  3. {{allNames}} All web names, they will be listed as server_name
  4. {{settings}} all field values of the Internet site documents as concatenated strings. Using a dot notation they can be used directly. e.g. {{settings.SSLKeyFile}}. Using this approach you can do whatever is needed to generate your desired output
This is the initial template, based on Jesse's article:

server {
        listen {{siteName}}:443;
        server_name {{#allNames}} {{.}}{{/allNames}};
        client_max_body_size 100m;

        ssl on;
        # Original keyfile: {{settings.SSLKeyFile}}
        ssl_certificate      /etc/nginx/ssl/{{name}}.pem;
        ssl_certificate_key /etc/nginx/ssl/{{name}}.key;

        location / {
                proxy_read_timeout 240;
                proxy_pass http://localhost:8088;
                proxy_redirect off;
                proxy_buffering off;

                proxy_set_header        Host               $host;
                proxy_set_header        X-Forwarded-For    $proxy_add_x_forwarded_for;
                proxy_set_header        $WSRA              $remote_addr;
                proxy_set_header        $WSRH              $remote_addr;
                proxy_set_header        $WSSN              $host;
                proxy_set_header        $WSIS              True;
        }

}

The Java code takes in the file name of that template as parameter, so when you feel you rather use Apache or need a different output (e.g. a report), you are free to supply a different file here.The Java is quite simple and should be self explanatory. Since it is a one-time, you-know-what-you-are-doing utility, there is no real error handling:

package com.notessensei.nginxdomino;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;

import lotus.domino.Database;
import lotus.domino.Document;
import lotus.domino.NotesException;
import lotus.domino.NotesFactory;
import lotus.domino.NotesThread;
import lotus.domino.Session;
import lotus.domino.View;

import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;

public class ConfigGenerator {

    private static final String VIEW_NAME = "($InternetSites)";
    private static final String WEB_FORM  = "WebSite";

    private final File          outDir;
    private final String        dirFileName;
    private final String        templateFileName;

    public ConfigGenerator(String outputDir, String fileName, String templateFile) {
        this.outDir = new File(outputDir);
        this.dirFileName = fileName;
        this.templateFileName = templateFile;
        if (!outDir.exists()) {
            outDir.mkdirs();
        }
    }

    public static void main(String[] args) {
        if (args.length < 3) {
            System.err.println("Usage java -jar ngixdomino [outputdir] [path-to-local-pubnames] [path-to-template]");
            System.exit(1);
        }
        ConfigGenerator cg = new ConfigGenerator(args[0], args[1], args[2]);
        cg.generateDefaultConfigs();
        System.out.println("Done ..");
    }

    public void generateDefaultConfigs() {
        // Here we read from domino
        final Collection<InternetSite> internetSites = new ArrayList<InternetSite>();
        this.populateInternetSites(internetSites);
        if (internetSites.size() == 0) {
            System.err.println("Something went wrong, got no internet sites!");
            System.exit(2);
        }
        Mustache mustache = this.getDefaultTemplate();
        this.renderConfigs(mustache, internetSites);
    }

    private void renderConfigs(Mustache mustache, Collection<InternetSite> internetSites) {

        for (InternetSite is : internetSites) {
            String outfileName = this.outDir.getPath() + File.separator + is.getName();
            System.out.println("Creating " + outfileName);
            try {
                FileOutputStream out = new FileOutputStream(new File(outfileName));
                Writer pw = new PrintWriter(out);
                mustache.execute(pw, is);
                pw.flush();
                pw.close();
                out.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private Mustache getDefaultTemplate() {
        MustacheFactory mf = new DefaultMustacheFactory();
        return mf.compile(this.templateFileName);
    }

    private void populateInternetSites(Collection<InternetSite> internetSites) {
        Session s = null;
        Database nab = null;
        View v = null;
        Document doc = null;

        NotesThread.sinitThread();
        try {
            s = NotesFactory.createSession();
            nab = s.getDatabase("", this.dirFileName);
            v = nab.getView(VIEW_NAME);
            doc = v.getFirstDocument();
            while (doc != null) {
                Document nextDoc = v.getNextDocument(doc);
                this.addoneInternetSite(internetSites, doc);
                doc.recycle();
                doc = nextDoc;
            }
            Utils.shred(doc, v, nab);
        } catch (NotesException e) {
            e.printStackTrace();
        }
        NotesThread.stermThread();
    }

    private void addoneInternetSite(Collection<InternetSite> internetSites, Document doc) throws NotesException {
        // Is it an internet site?
        if (!doc.getItemValueString("Form").equals(WEB_FORM)) {
            return; // Not an internet site
        }
        InternetSite is = new InternetSite(doc);
        internetSites.add(is);
    }

}

package com.notessensei.nginxdomino;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

import lotus.domino.Document;
import lotus.domino.Item;
import lotus.domino.NotesException;

public class InternetSite {

    private static final String SITE_NAME_ITEM = "ISiteName";
    private static final String ALL_NAMES_ITEM = "ISiteAdrs";

    private final String name;
    private final ArrayList<String> allNames = new ArrayList<String>();
    private final Map<String, String> settings = new HashMap<String, String>();

    public InternetSite(Document doc) throws NotesException {
        this.name = doc.getItemValueString(SITE_NAME_ITEM);
        @SuppressWarnings("rawtypes")
        Vector v = doc.getItemValue(ALL_NAMES_ITEM);
        for (Object o : v) {
            this.allNames.add(o.toString());
        }
        for (Object o : doc.getItems()) {
            if (o instanceof Item) {
                Item i = (Item) o;
                this.settings.put(i.getName(), i.getValueString());
            }
        }
    }

    public String getName() {
        return this.name;
    }

    public String getSiteName() {
        return this.allNames.get(0);
    }

    public Collection<String> getAllNames() {
        return this.allNames;
    }

    public Map<String,String> getSettings() {
        return this.settings;
    }

}

As usual YMMV.

Posted by on 20 September 2014 1 comment categories: IBM Notesnginx

Add your comment…

Comments

  1. posted by Ray Davies on Wednesday 24 September 2014 AD:
    This is an awesome article. Thanks Stephan!

    Emoticon biggrin.gif