Snake in Groovy

Series: Groovy, Ruby, BASIC, Dart, Elm, Python3+Qt5

I’m starting a series where I write the game Snake in lots of programming languages.

I almost always use writing Snake as my way in to understand a new language, so I’ll share my thoughts about each language as I go.

Slides: Snake in Groovy

If you want to, you can Support me on Patreon.

Programmatic equivalents of web.xml sections for Tomcat

Most documentation for J2EE configuration is based on having a web.xml file, but I want to configure my Tomcat programmatically. Here are some of the things I have found out.

Please use the comments below to correct what I got wrong, and mention equivalents for other parts of web.xml.

Getting started

<web-app ...

in code becomes something like:

import org.apache.catalina.Context;
import org.apache.catalina.startup.Tomcat;
...
Tomcat tomcat = new Tomcat();
Context context = tomcat.addContext( "", "WebContent" );

Adding a Servlet

<web-app ...
    <servlet>
        ...
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>com.example.MyServlet</servlet-class>
        ...
    </servlet>
    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/foo/*</url-pattern>
    </servlet-mapping>

in code becomes something like:

...
Class servletClass = MyServlet.class;
// MyServlet extends javax.servlet.http.HttpServlet 
String servletName = servletClass.getSimpleName(); // Or something else if you like
Tomcat.addServlet( context, servletName, servletClass.getName() );
context.addServletMapping( "/foo/*", servletName );

Adding a filter

<web-app ...
    <filter>
        <filter-name>MyFilter</filter-name>
        <filter-class>com.example.MyFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>MyFilter</filter-name>
        <url-pattern>/bar/*</url-pattern>
    </filter-mapping>

in code becomes something like:

...
import org.apache.catalina.deploy.FilterDef;
import org.apache.catalina.deploy.FilterMap;
...
Class filterClass = MyFilter.class;
// MyFilter implements javax.servlet.Filter
String filterName = filterClass.getSimpleName(); // Or something else if you like
FilterDef def = new FilterDef();
def.setFilterName( filterName );
context.addFilterDef( def );
FilterMap map = new FilterMap();
map.setFilterName( filterName );
map.addURLPattern( "/bar/*" );
context.addFilterMap( filterMap );

Adding a Listener

<web-app ...
    <listener>
    	<listener-class>com.example.MyContextListener</listener-class>
    </listener>

in code becomes something like:

...
context.addApplicationListener( MyContextListener.class.getName() );
// MyContextListener implements javax.servlet.ServletContextListener

This is for a ServletContextListener: it may be similar for other listeners, but I’m not sure.

JAX-RS (using Apache CXF) in embedded Tomcat example

I had serious trouble today firing up an embedded Tomcat server that serves up REST resources using JAX-RS via Apache CXF.

Here’s minimal example, hopefully saving you the same trouble:

src/HelloJaxRs.java:

import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.Context;
import org.apache.catalina.Wrapper;

public class HelloJaxRs
{
    public static void main( String[] args ) throws Exception
    {
        Tomcat tomcat = new Tomcat();
        Context context = tomcat.addContext( "/", "" );

        Wrapper servlet = context.createWrapper();
        servlet.setName( "jaxrs" );
        servlet.setServletClass(
            "org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet" );

        servlet.addInitParameter(
            "jaxrs.serviceClasses",
            Hello.class.getName()
        );

        servlet.setLoadOnStartup( 1 );
        context.addChild( servlet );
        context.addServletMapping( "/rest/*", "jaxrs" );

        tomcat.start();
        tomcat.getServer().await();
    }
}

src/Hello.java:

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;

@Path( "/hello/{name}" )
public class Hello
{
    @GET
    public String getThing( @PathParam( "name" ) String name )
    {
        return "Hello, " + name;
    }
}

build.xml:


<?xml version="1.0" encoding="UTF-8"?>
<project default="run">

    <target name="run" depends="compile">
        <mkdir dir="bin/tomcat.8080/webapps"/>
        <java
            classname="HelloJaxRs"
            fork="true"
            failonerror="true"
            dir="bin"
        >
            <classpath>
                <pathelement location="bin/"/>
                <fileset dir="lib"><include name="**/*.jar"/></fileset>
            </classpath>
        </java>
    </target>

    <target name="compile">
        <mkdir dir="bin"/>
        <javac srcdir="src" destdir="bin">
            <classpath>
                <fileset dir="lib"><include name="**/*.jar"/></fileset>
            </classpath>
            <compilerarg value="-Werror"/>
        </javac>
    </target>

</project>

To download the dependencies (or you can do something clever with Maven):

$ mkdir lib
$ cd lib
$ wget http://www.webhostingjams.com/mirror/apache/tomcat/tomcat-7/v7.0.57/bin/apache-tomcat-7.0.57.tar.gz
$ tar -xzf apache-tomcat-7.0.57.tar.gz
$ wget http://www.apache.org/dyn/closer.cgi?path=/cxf/3.0.3/apache-cxf-3.0.3.tar.gz
$ tar -xzf apache-cxf-3.0.3.tar.gz
$ cd ..

To run Tomcat:

$ ant

Then, in another terminal, you can see it’s working:

$ curl http://localhost:8080/rest/hello/andy
Hello, andy

Vim persistent buffer list combined with saved sessions

I like to use several saved Vim sessions to remember what files I was working on in a particular project.

I also like to have a list of buffers I have open on the left-hand side of the screen that is always visible and up-to-date.

Sometimes, the existence of a generated buffer like the list of buffers can confuse the session restore code, but I have found a way to make this work nicely using the Buffergator plugin and the built-in mksession command.

Here are the relevant snippets from my .vimrc.

I am a beginner: please comment if you see bugs or possible improvements.

" Prerequisites: install the Buffergator plugin


" Save session on exit, excluding problematic stuff like options

set sessionoptions=blank,buffers,curdir,tabpages,resize,winpos,winsize
au VimLeavePre * if v:this_session != '' | exec "mks! " . v:this_session | endif


" Open Buffergator when you press F5

nnoremap <F5> :BuffergatorOpen<CR>


" Various Buffergator options to make it persistent,
" and displayed how I like

let g:buffergator_autodismiss_on_select = 0
let g:buffergator_display_regime = "bufname"
let g:buffergator_sort_regime    = "filepath"
let g:buffergator_autoupdate = 1


" Suppress the error message about the Buffergator buffer
" when you restore a session

function! OpenBuffergatorIfItsBufferExists()
    if bufnr("[[buffergator-buffers]]") > ''
        BuffergatorOpen
        normal o
    endif
endfunction

autocmd VimEnter * call OpenBuffergatorIfItsBufferExists()

Now when I start vim with vim -S path/to/session.vim the session is restored and saved when I exit, with a persistent buffer list on the left, and no errors during the session restore.

Snowflake Christmas card web page on the Raspberry Pi

In this video I will show you how to make an electronic Christmas card for your friends or family using HTML and JavaScript, which means it will be a little web site that anyone can see by going to it in their Internet browser.

I’m doing this on the Raspberry Pi, but you can do the same thing on almost any computer that exists. All you need is a web browser (like Firefox or Internet Explorer) and a text editor (like Notepad or Gedit).

If this looks very difficult, try the video I made making a similar card using Scratch, which is a lot easier: Snowflake Christmas card in Scratch on the Raspberry Pi.

If you’d like to use the snowflake picture I drew, right-click this link and choose “Save link as…” or similar: snowflake.svg.

If you’d like to compare my code against yours, right-click this link and choose “Save link as…” or similar: snowflakes.html.

If you’d like to see what the finished product looks like, just left-click on snowflakes.html above, instead of right-clicking.