Using Perl to munge an X.509 certificate

I wanted to do something fairly quick with X.509 certificates. My scribbled requirements were: connect to a server and grab the public certificate and then expose the X.509 fields programmatically. As an old Perl hacker-at-heart I headed over to CPAN and grabbed a copy of Net::SSLeay. It seems to be the de facto module for this work and is recommended by O’Reilly’s excellent book on OpenSSL that I happened to be reading. Furthermore there was a yum installer for CentOs. Happy days!

After a bit of fiddling I’d hacked the test ssl client that comes with the bundle to do the job. There were a couple of gotchas. Firstly I was getting some core dumps. I never really got to the bottom of these. I thought this might be that the yum installer didn’t do a good job (because later installs required the openssl-dev package, but yum didn’t complain). Anyway I got around the core dumps by removing the nested calls from my code. Perhaps those warnings about OpenSSL not playing nicely with threads have some weight after all? Anyway, by this time my code was starting to get a bit messy and I had hit another problem.

This isn’t to do with Net::SSLeay directly but the fact that Socket requires you to run as root. I can see this made sense at some earlier point in history when being root was a Big Thing. But now everyone has a couple of VMs kicking around and what’s the point in making user accounts? It was a bit annoying because I actually couldn’t run as root in my target environment. Seems a lot of kafuffle when all I wanted to do was make a standard https connection to places like https://www.google.com. Not so extra-ordinary! The only work around I’ve found so far is to pipe through openssl s_client and this works fine, if a bit 1970s. Please comment with any better suggestions.

The next bit was to start grappling with the certificate themselves. I did consider Sam Vilain’s OO Net::SSLeay as it looks like an improved interface and this was my main gripe with Net::SSLeay. (I should say that I got a nice reply from the author of Net::SSLeay). But I was worried that it was still Net::SSLeay underneath and by then Dan Sully’s Crypt::OpenSSL::X509 had caught my eye. It’s a really nice API. Everything just seems to be where you’d expect it. So I got stuck in and all was well for a while. Turns out this module has problems too. Mainly it stops dead on certificates that it doesn’t understand. For example https://google.co.in/ has a stonker of a certificate with several hundred X509 v3 extensions. Dan’s module just fails to cope, no warning and no nice reply from Dan. The other problem is that it isn’t finished.

Drawing of a multi-headed Hydra.

At this point I was thinking about starting again in Java ..

The other problem with Dan’s module is that the ASN.1 notation that underpins the X.509 standard is a horrible multi-layered thing. When Dan’s module get’s past the first layer it starts throwing-up gobble-de-gook. You see, not everything is a string in the world of X.509. I mean this:

X509v3 Subject Key Identifier
53:32:D1:B3:CF:7F:FA:E0:F1:A0:5D:85:4E:92:D2:9E:45:1D:B4:4F

became that.

X509v3 Subject Key Identifier
..S2........].N...E..O

There is an X.509 module as part of Crypt::SSLeay but it’s deprecated and the module is only maintained for protocol support of the amazing LWP (it puts the s in https). This is a shame because had I been able to grab the certificate from an LWP session then two birds might have been left to die. I also found this sslclient which looked perfect. But it failed the install.

Right now I’m working with Crypt::X509 by Alexander Jung. It seems to be a bit obsessed with LDAP and wants to consume your certificates in the binary DER format. I guess this is an LDAP thing because everything else I’ve seen is PEM. But it is dependent on Convert::ASN1 so I’m hopeful that it knows what to do with all those ASN.1 layers that are hidden in the guts of a certificate. I’ll let you know how it goes. Here’s that stonker.


Certificate:
Data:
Version: 3 (0x2)
Serial Number:
47:4f:4f:50:01:70
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=US, O=Google Inc, CN=Google Internet Authority
Validity
Not Before: Aug 16 11:37:16 2012 GMT
Not After : Jun 7 19:43:27 2013 GMT
Subject: C=US, ST=California, O=Google Inc, CN=google.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:b5:4e:3d:07:0f:f0:57:3a:aa:68:57:9d:1a:9b:
1b:dc:55:2f:aa:28:02:00:35:3a:3a:3b:17:00:2e:
ac:17:2d:49:f5:b2:f7:4f:d7:93:6c:84:ed:9a:d1:
a0:e0:81:64:7b:4f:67:78:bf:52:ba:d3:4c:d1:c2:
7e:67:16:fd:7f:62:f7:88:86:1b:ea:1c:38:2a:e8:
58:d2:04:11:45:67:50:73:30:49:64:6a:79:de:e3:
af:4d:8b:37:1f:ca:ca:13:dd:9e:76:7e:03:54:bf:
50:c0:bb:6f:d9:4d:34:8b:66:7e:fd:b3:43:21:c7:
4c:dc:86:ae:c4:53:b0:fa:db
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Subject Key Identifier:
FD:DE:A8:2D:76:DB:A4:74:C1:62:D9:D3:4B:AD:AB:8B:DD:89:7D:78
X509v3 Authority Key Identifier:
keyid:BF:C0:30:EB:F5:43:11:3E:67:BA:9E:91:FB:FC:6A:DA:E3:6B:12:24

X509v3 CRL Distribution Points:

Full Name:
URI:http://www.gstatic.com/GoogleInternetAuthority/GoogleInternetAuthority.crl

Authority Information Access:
CA Issuers - URI:http://www.gstatic.com/GoogleInternetAuthority/GoogleInternetAuthority.crt

X509v3 Subject Alternative Name:
DNS:google.com, DNS:*.google.com, DNS:*.youtube.com, DNS:youtube.com, DNS:*.youtube-nocookie.com, DNS:youtu.be, DNS:*.ytimg.com, DNS:*.android.com, DNS:android.com, DNS:*.googlecommerce.com, DNS:googlecommerce.com, DNS:*.url.google.com, DNS:*.urchin.com, DNS:urchin.com, DNS:*.google-analytics.com, DNS:google-analytics.com, DNS:*.cloud.google.com, DNS:goo.gl, DNS:g.co, DNS:*.gstatic.com, DNS:*.google.ac, DNS:*.google.ad, DNS:*.google.ae, DNS:*.google.af, DNS:*.google.ag, DNS:*.google.am, DNS:*.google.as, DNS:*.google.at, DNS:*.google.az, DNS:*.google.ba, DNS:*.google.be, DNS:*.google.bf, DNS:*.google.bg, DNS:*.google.bi, DNS:*.google.bj, DNS:*.google.bs, DNS:*.google.by, DNS:*.google.ca, DNS:*.google.cat, DNS:*.google.cc, DNS:*.google.cd, DNS:*.google.cf, DNS:*.google.cg, DNS:*.google.ch, DNS:*.google.ci, DNS:*.google.cl, DNS:*.google.cm, DNS:*.google.cn, DNS:*.google.co.ao, DNS:*.google.co.bw, DNS:*.google.co.ck, DNS:*.google.co.cr, DNS:*.google.co.hu, DNS:*.google.co.id, DNS:*.google.co.il, DNS:*.google.co.im, DNS:*.google.co.in, DNS:*.google.co.je, DNS:*.google.co.jp, DNS:*.google.co.ke, DNS:*.google.co.kr, DNS:*.google.co.ls, DNS:*.google.co.ma, DNS:*.google.co.mz, DNS:*.google.co.nz, DNS:*.google.co.th, DNS:*.google.co.tz, DNS:*.google.co.ug, DNS:*.google.co.uk, DNS:*.google.co.uz, DNS:*.google.co.ve, DNS:*.google.co.vi, DNS:*.google.co.za, DNS:*.google.co.zm, DNS:*.google.co.zw, DNS:*.google.com.af, DNS:*.google.com.ag, DNS:*.google.com.ai, DNS:*.google.com.ar, DNS:*.google.com.au, DNS:*.google.com.bd, DNS:*.google.com.bh, DNS:*.google.com.bn, DNS:*.google.com.bo, DNS:*.google.com.br, DNS:*.google.com.by, DNS:*.google.com.bz, DNS:*.google.com.cn, DNS:*.google.com.co, DNS:*.google.com.cu, DNS:*.google.com.cy, DNS:*.google.com.do, DNS:*.google.com.ec, DNS:*.google.com.eg, DNS:*.google.com.et, DNS:*.google.com.fj, DNS:*.google.com.ge, DNS:*.google.com.gh, DNS:*.google.com.gi, DNS:*.google.com.gr, DNS:*.google.com.gt, DNS:*.google.com.hk, DNS:*.google.com.iq, DNS:*.google.com.jm, DNS:*.google.com.jo, DNS:*.google.com.kh, DNS:*.google.com.kw, DNS:*.google.com.lb, DNS:*.google.com.ly, DNS:*.google.com.mt, DNS:*.google.com.mx, DNS:*.google.com.my, DNS:*.google.com.na, DNS:*.google.com.nf, DNS:*.google.com.ng, DNS:*.google.com.ni, DNS:*.google.com.np, DNS:*.google.com.nr, DNS:*.google.com.om, DNS:*.google.com.pa, DNS:*.google.com.pe, DNS:*.google.com.ph, DNS:*.google.com.pk, DNS:*.google.com.pl, DNS:*.google.com.pr, DNS:*.google.com.py, DNS:*.google.com.qa, DNS:*.google.com.ru, DNS:*.google.com.sa, DNS:*.google.com.sb, DNS:*.google.com.sg, DNS:*.google.com.sl, DNS:*.google.com.sv, DNS:*.google.com.tj, DNS:*.google.com.tn, DNS:*.google.com.tr, DNS:*.google.com.tw, DNS:*.google.com.ua, DNS:*.google.com.uy, DNS:*.google.com.vc, DNS:*.google.com.ve, DNS:*.google.com.vn, DNS:*.google.cv, DNS:*.google.cz, DNS:*.google.de, DNS:*.google.dj, DNS:*.google.dk, DNS:*.google.dm, DNS:*.google.dz, DNS:*.google.ee, DNS:*.google.es, DNS:*.google.fi, DNS:*.google.fm, DNS:*.google.fr, DNS:*.google.ga, DNS:*.google.ge, DNS:*.google.gg, DNS:*.google.gl, DNS:*.google.gm, DNS:*.google.gp, DNS:*.google.gr, DNS:*.google.gy, DNS:*.google.hk, DNS:*.google.hn, DNS:*.google.hr, DNS:*.google.ht, DNS:*.google.hu, DNS:*.google.ie, DNS:*.google.im, DNS:*.google.info, DNS:*.google.iq, DNS:*.google.is, DNS:*.google.it, DNS:*.google.it.ao, DNS:*.google.je, DNS:*.google.jo, DNS:*.google.jobs, DNS:*.google.jp, DNS:*.google.kg, DNS:*.google.ki, DNS:*.google.kz, DNS:*.google.la, DNS:*.google.li, DNS:*.google.lk, DNS:*.google.lt, DNS:*.google.lu, DNS:*.google.lv, DNS:*.google.md, DNS:*.google.me, DNS:*.google.mg, DNS:*.google.mk, DNS:*.google.ml, DNS:*.google.mn, DNS:*.google.ms, DNS:*.google.mu, DNS:*.google.mv, DNS:*.google.mw, DNS:*.google.ne, DNS:*.google.ne.jp, DNS:*.google.net, DNS:*.google.nl, DNS:*.google.no, DNS:*.google.nr, DNS:*.google.nu, DNS:*.google.off.ai, DNS:*.google.pk, DNS:*.google.pl, DNS:*.google.pn, DNS:*.google.ps, DNS:*.google.pt, DNS:*.google.ro, DNS:*.google.rs, DNS:*.google.ru, DNS:*.google.rw, DNS:*.google.sc, DNS:*.google.se, DNS:*.google.sh, DNS:*.google.si, DNS:*.google.sk, DNS:*.google.sm, DNS:*.google.sn, DNS:*.google.so, DNS:*.google.st, DNS:*.google.td, DNS:*.google.tg, DNS:*.google.tk, DNS:*.google.tl, DNS:*.google.tm, DNS:*.google.tn, DNS:*.google.to, DNS:*.google.tp, DNS:*.google.tt, DNS:*.google.us, DNS:*.google.uz, DNS:*.google.vg, DNS:*.google.vu, DNS:*.google.ws, DNS:google.ac, DNS:google.ad, DNS:google.ae, DNS:google.af, DNS:google.ag, DNS:google.am, DNS:google.as, DNS:google.at, DNS:google.az, DNS:google.ba, DNS:google.be, DNS:google.bf, DNS:google.bg, DNS:google.bi, DNS:google.bj, DNS:google.bs, DNS:google.by, DNS:google.ca, DNS:google.cat, DNS:google.cc, DNS:google.cd, DNS:google.cf, DNS:google.cg, DNS:google.ch, DNS:google.ci, DNS:google.cl, DNS:google.cm, DNS:google.cn, DNS:google.co.ao, DNS:google.co.bw, DNS:google.co.ck, DNS:google.co.cr, DNS:google.co.hu, DNS:google.co.id, DNS:google.co.il, DNS:google.co.im, DNS:google.co.in, DNS:google.co.je, DNS:google.co.jp, DNS:google.co.ke, DNS:google.co.kr, DNS:google.co.ls, DNS:google.co.ma, DNS:google.co.mz, DNS:google.co.nz, DNS:google.co.th, DNS:google.co.tz, DNS:google.co.ug, DNS:google.co.uk, DNS:google.co.uz, DNS:google.co.ve, DNS:google.co.vi, DNS:google.co.za, DNS:google.co.zm, DNS:google.co.zw, DNS:google.com.af, DNS:google.com.ag, DNS:google.com.ai, DNS:google.com.ar, DNS:google.com.au, DNS:google.com.bd, DNS:google.com.bh, DNS:google.com.bn, DNS:google.com.bo, DNS:google.com.br, DNS:google.com.by, DNS:google.com.bz, DNS:google.com.cn, DNS:google.com.co, DNS:google.com.cu, DNS:google.com.cy, DNS:google.com.do, DNS:google.com.ec, DNS:google.com.eg, DNS:google.com.et, DNS:google.com.fj, DNS:google.com.ge, DNS:google.com.gh, DNS:google.com.gi, DNS:google.com.gr, DNS:google.com.gt, DNS:google.com.hk, DNS:google.com.iq, DNS:google.com.jm, DNS:google.com.jo, DNS:google.com.kh, DNS:google.com.kw, DNS:google.com.lb, DNS:google.com.ly, DNS:google.com.mt, DNS:google.com.mx, DNS:google.com.my, DNS:google.com.na, DNS:google.com.nf, DNS:google.com.ng, DNS:google.com.ni, DNS:google.com.np, DNS:google.com.nr, DNS:google.com.om, DNS:google.com.pa, DNS:google.com.pe, DNS:google.com.ph, DNS:google.com.pk, DNS:google.com.pl, DNS:google.com.pr, DNS:google.com.py, DNS:google.com.qa, DNS:google.com.ru, DNS:google.com.sa, DNS:google.com.sb, DNS:google.com.sg, DNS:google.com.sl, DNS:google.com.sv, DNS:google.com.tj, DNS:google.com.tn, DNS:google.com.tr, DNS:google.com.tw, DNS:google.com.ua, DNS:google.com.uy, DNS:google.com.vc, DNS:google.com.ve, DNS:google.com.vn, DNS:google.cv, DNS:google.cz, DNS:google.de, DNS:google.dj, DNS:google.dk, DNS:google.dm, DNS:google.dz, DNS:google.ee, DNS:google.es, DNS:google.fi, DNS:google.fm, DNS:google.fr, DNS:google.ga, DNS:google.ge, DNS:google.gg, DNS:google.gl, DNS:google.gm, DNS:google.gp, DNS:google.gr, DNS:google.gy, DNS:google.hk, DNS:google.hn, DNS:google.hr, DNS:google.ht, DNS:google.hu, DNS:google.ie, DNS:google.im, DNS:google.info, DNS:google.iq, DNS:google.is, DNS:google.it, DNS:google.it.ao, DNS:google.je, DNS:google.jo, DNS:google.jobs, DNS:google.jp, DNS:google.kg, DNS:google.ki, DNS:google.kz, DNS:google.la, DNS:google.li, DNS:google.lk, DNS:google.lt, DNS:google.lu, DNS:google.lv, DNS:google.md, DNS:google.me, DNS:google.mg, DNS:google.mk, DNS:google.ml, DNS:google.mn, DNS:google.ms, DNS:google.mu, DNS:google.mv, DNS:google.mw, DNS:google.ne, DNS:google.ne.jp, DNS:google.net, DNS:google.nl, DNS:google.no, DNS:google.nr, DNS:google.nu, DNS:google.off.ai, DNS:google.pk, DNS:google.pl, DNS:google.pn, DNS:google.ps, DNS:google.pt, DNS:google.ro, DNS:google.rs, DNS:google.ru, DNS:google.rw, DNS:google.sc, DNS:google.se, DNS:google.sh, DNS:google.si, DNS:google.sk, DNS:google.sm, DNS:google.sn, DNS:google.so, DNS:google.st, DNS:google.td, DNS:google.tg, DNS:google.tk, DNS:google.tl, DNS:google.tm, DNS:google.tn, DNS:google.to, DNS:google.tp, DNS:google.tt, DNS:google.us, DNS:google.uz, DNS:google.vg, DNS:google.vu, DNS:google.ws, DNS:*.googleapis.cn
Signature Algorithm: sha1WithRSAEncryption
c0:a8:27:9e:20:b8:c5:de:9a:32:0a:4f:e3:8b:9b:10:8b:06:
73:31:ac:91:75:68:dd:d5:1a:eb:23:86:77:2e:78:49:99:9b:
84:4e:40:0b:50:08:c5:81:21:f2:a6:55:a1:40:27:2f:5f:93:
c5:0d:0a:51:ff:49:29:4e:2d:80:c6:5e:a5:bb:ca:df:cb:39:
29:0c:ca:28:18:a7:1c:c3:43:ff:2e:22:a8:df:41:91:7c:c4:
ba:7c:63:ce:d8:71:46:73:d7:6b:d3:12:a1:93:c0:8d:44:ce:
25:da:c1:53:05:76:d7:c8:05:c3:2f:62:95:07:36:a2:04:ee:
b4:15

Using GeoRss

I started using Marc’s GeoRss module as part of a webapp that needed to send geometries to an OpenLayers (JavaScript) client. Here are the steps I took to get GeoRss working.

* Read the documentation at http://georss.geonames.org/

* Used the following maven command to setup a basic project.

[sourcecode language=”bash”]
#!/bin/bash

PROJECT=twotrack

mvn archetype:generate \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-profiles \
-Dversion=1.0.0-SNAPSHOT \
-DartifactId=$PROJECT-georss \
-DgroupId=net.fnarg.$PROJECT
[/sourcecode]

* Added GeoRss dependencies to the maven generated pom.xml

[sourcecode language=”xml”]
<dependency>
<groupId>rome</groupId>
<artifactId>rome</artifactId>
<version>0.9</version>
</dependency>
<dependency>
<groupId>org.geonames</groupId>
<artifactId>georss-rome</artifactId>
<version>0.9.8</version>
</dependency>
[/sourcecode]

* Grabbed the jars for Eclipse

[sourcecode language=”xml”]
mvn eclipse:eclipse
[/sourcecode]

* Extended Marc’s examples by wrapping some setters and getters for Spring

[sourcecode lanuage=”java”]
package net.fnarg.twotrack;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import com.sun.syndication.io.XmlReader;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.SyndFeedOutput;

import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndEntryImpl;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.synd.SyndFeedImpl;

import com.sun.syndication.feed.module.georss.GeoRSSUtils;
import com.sun.syndication.feed.module.georss.GeoRSSModule;
import com.sun.syndication.feed.module.georss.W3CGeoModuleImpl;
import com.sun.syndication.feed.module.georss.geometries.Position;

public class GeoRssFeed {
private SyndFeed feed;

public GeoRssFeed() {
feed = new SyndFeedImpl();
}

public GeoRssFeed(String url) throws Exception {
feed = new SyndFeedImpl();
this.setEntries(url);
}

public String getFeed() throws Exception {
return new SyndFeedOutput().outputString(feed);
}

public void setFeed() throws Exception {
feed.setFeedType("rss_2.0");
feed.setTitle("Two Track");
feed.setDescription("A tool for modelling toy train tracks");
feed.setLink("http://www.fnarg.net/twotrack/");
}

public void setEntries(String url) throws Exception {
SyndFeedInput input = new SyndFeedInput();
feed = input.build(new XmlReader(new URL(url)));
}

public List<SyndEntry> getEntries() {
return feed.getEntries();
}

public void setEntries(List<Position> positions) {
List<SyndEntry> entries = new ArrayList<SyndEntry>();
for (Position p : positions) {
SyndEntry entry = new SyndEntryImpl();
GeoRSSModule geoRSSModule = new W3CGeoModuleImpl();
geoRSSModule.setPosition(p);
entry.getModules().add(geoRSSModule);
entries.add(entry);
}
feed.setEntries(entries);
}
}
[/sourcecode]

* Wrote a test class to verify inputs/outputs

[sourcecode language=”java”]
package net.fnarg.twotrack;

import java.util.ArrayList;
import java.util.List;

import com.sun.syndication.feed.module.georss.GeoRSSModule;
import com.sun.syndication.feed.module.georss.GeoRSSUtils;
import com.sun.syndication.feed.module.georss.geometries.Position;
import com.sun.syndication.feed.synd.SyndEntry;

public class TestGeoRssReadWriter {

private static GeoRssFeed geoRssFeed;

/**
* Tester for the GeoRssFeed class
* @author gavin
*/
public static void main(String[] args) throws Exception {
// load XML file into memory
geoRssFeed = new GeoRssFeed("http://www.openlayers.org/dev/examples/xml/track1.xml");
// get and display the geometries
List<SyndEntry> entries = geoRssFeed.getEntries();
for (SyndEntry entry : entries) {
GeoRSSModule geoRSSModule = GeoRSSUtils.getGeoRSS(entry);
System.out.println(entry.getTitle() + " : lat="
+ geoRSSModule.getPosition().getLatitude() + ",lng="
+ geoRSSModule.getPosition().getLongitude() + ", desc="
+ entry.getDescription().getValue() + "; time="
+ entry.getPublishedDate());
}
// set mandatory XML fields with our Two Track headers
geoRssFeed.setFeed();
// output
System.out.println(geoRssFeed.getFeed());
// update the feed
Position p1 = new Position(54.2, 12.4);
Position p2 = new Position(55.2, 13.4);
List<Position> newEntries = new ArrayList<Position>();
newEntries.add(p1);
newEntries.add(p2);
// replace the geometries
geoRssFeed.setEntries(newEntries);
// check new output
System.out.println(geoRssFeed.getFeed());
}
}
[/sourcecode]

Maven refusing to compile Spring project due to annotations

The fix for the following issue is here http://maven.40175.n5.nabble.com/Maven-refusing-to-compile-Spring-project-due-to-annotations-tp4309204p4309211.html. Duh!


I’m running Eclipse and Maven on a Mac. Here’s my version of Maven

[sourcecode language=”bash”]
$ mvn -version
Apache Maven 2.2.1 (r801777; 2009-08-06 20:16:01+0100)
Java version: 1.6.0_22
Java home: /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
Default locale: en_US, platform encoding: MacRoman
OS name: "mac os x" version: "10.5.8" arch: "x86_64" Family: "mac"
[/sourcecode]

What I’m trying to do is use Maven to compile my Spring project (it builds fine in Eclipse) so I can deploy the war to a Tomcat. I setup my pom.xml (see below) and asked mvn to create the package. The build failed with the following error:

[sourcecode]
Compilation failure
/path/to/WelcomeController.java:[7,1] annotations are not supported in -source 1.3
(use -source 5 or higher to enable annotations)
@Controller
[/sourcecode]

Doing mvn compile gives the same error. Google showed me that this was a known problem with Maven with the fix explained here:

http://maven.apache.org/plugins/maven-compiler-plugin/howto.html

I can’t see why the fix isn’t working for me. In desparation I followed these instructions:

http://pwong-tipsandtricks.blogspot.com/2009/02/install-and-test-maven-on-centos-52.html and put a fresh maven on my Linux box. The build failed with the same error, so it seems that my pom.xml is the culprit. But how? Here’s the pom.

[sourcecode language=”xml”]
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.fnarg.twotrack</groupId>
<artifactId>twotrack-webapp</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>Twotrack Webapp</name>
<url>http://maven.apache.org</url>

<properties>
<spring.version>3.0.5.RELEASE</spring.version>
<appName>twotrack</appName>
<tomcatPackageName>apache-tomcat-twotrack</tomcatPackageName>
<runas.username>twotrack</runas.username>
<runas.group>twotrack</runas.group>
</properties>

<repositories>
<repository>
<id>com.springsource.repository.bundles.release</id>
<name>SpringSource Enterprise Bundle Repository – SpringSource Bundle
Releases</name>
<url>http://repository.springsource.com/maven/bundles/milestone</url>
</repository>
<repository>
<id>com.springsource.repository.bundles.external</id>
<name>SpringSource Enterprise Bundle Repository – External Bundle
Releases</name>
<url>http://repository.springsource.com/maven/bundles/external</url>
</repository>
</repositories>

<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>el-api</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>com.springsource.org.apache.taglibs.standard</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
<finalName>twotrack</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/webapp</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
[/sourcecode]

Install Apache and make a web page

To make a web page you need both a web server and a text editor. The webserver we’re going to use is Apache. There are lots of choices for a text editor but many web developers use Text Pad.

  • Install Text Pad from here
  • http://www.textpad.com/

  • Apache is bit more complicated
  • The full instructions are here, but they are fairly detailed.
    http://httpd.apache.org/docs/2.1/platform/windows.html

  • These are probably a friendlier place to start.
  • http://webdesign.about.com/cs/apache/a/aainstapachewin.htm

    We’re going to run Apache on localhost. This is a special name for a computer that let’s us access our own machine as if it were a server. On localhost Apache can only send pages to one computer, but that’s ok because it’s all we need for development.

  • Install Apache as above, then type
  • http://localhost/ in your browser

    Once our website is built the files will be transferred to another Apache that will serve the page onto the Internet.

    How to set up a new Eclipse project in net.fnarg package

    [sourcecode language=”bash”]
    mvn -o archetype:generate -DartifactId=classes-objects -DgroupId=net.fnarg.javatut
    [/sourcecode]

    I accepted the archetype defaults offered by generate

    [sourcecode language=”bash”]
    cd classes-objects/
    mvn -o eclipse:clean eclipse:eclipse
    [/sourcecode]

    Eclipse > New > Java Project
    Use default location

    Eclipse > Preferences > Java > Build Path > Classpath Variables
    New > M2_REPO = $WORKSPACE/mvn/repo

    Maven creates this structure.

    src/main/java
      net/fnarg/javatut
        class-objects/*.java
    src/test/java
      net/fnarg/javatut
        class-objects/*.java
    

    This project has no dependencies other than JUnit.
    Update the pom.xml JUnit is version 4.6

    Eclipse > File > Import > File system

    note in Eclipse on Mac using a minus like ‘this-that’ gives an error in the package name.

    Getting a bit better at blogging

    My written thoughts are scattered all over the place. Here are my user
    stories:

    As I blogger I want to
    – keep ideas/thoughts in the cloud, i.e. distributed
    – have a single process/store for Work, Family and Music
    – continue to use Vim as the editor
    – have the blog running on my own domain at fnarg.net

    By blog I mean something that is text and written by me.
    This diagram shows the activities that go into making a me blog.

    blog activity diagram

    *Putting it into practise*

    So I found this plugin for Vim called Blogit that doesn’t quite fit all my use-cases but it does look good.
    I tried to install Blogit:

    http://www.lamolabs.org/blog/2083/managing-wordpress-posts-with-vim/
    but the Mac Vim doesn’t come with Python.
    Ok so I’ll use the Linux Vim but that has this bug:


    Error detected while processing .vim/plugin/blogit.vim:
    line 1781:
    Traceback (most recent call last):
    File "", line 9, in ?
    ImportError: cannot import name CalledProcessError
    Press ENTER or type command to continue

    So I think I should upgrade Vim 7.0 to Vim 7.2

    Download the Vim 7.2 source and now I have this other error. And like the poster to Vim support I have a term library ):


    # locate libterm
    /lib/libtermcap.so.2
    /lib/libtermcap.so.2.0.8

    So I went back to the use-case and started looking at the XMLRPC part.
    This did the trick. She’s a good ‘ol Perl!

    And now I’m going to try and use it for the first time. If you can read this
    then it probably worked (:

    Well it did, but the activity diagram got mangled, hmm ..

    I still find WordPress a complete pain to use as an editor, but at least this helped.
    http://en.support.wordpress.com/code/posting-source-code/