Sunday, October 10, 2010

Maven site and multi-module broken links on site:stage

Maven 2.2.1 default site plugin does a strange job of making parent to child links for a multimodule site report. When I have the parent reporting url set to a file:// url the links are broken after doing a site:stage. There is an easy workaround though. Make the reporting url a property in the parent pom.xml, say ${site.url} and from parent directory call

mvn clean site site:deploy -Dsite.url=file://`pwd`/target/deployed-site

This will deploy the site into target/deployed-site. Note that the url must be absolute, that's why I use `pwd` to insert the current directory (not for windoze of course). Put whatever url you like in site.url if the above does not suit.

Friday, April 16, 2010

IMDB Lookup from Nautilus in Ubuntu

This is how you implement a Lookup IMDB right click menu action for a movie file visible in Nautilus. It's really easy using Nautilus Actions!

First install nautilus-actions
sudo apt-get install nautilus-actions
Now create the script to launch the browser given a filename.
sudo wget -N -P /usr/bin http://moten-util.googlecode.com/svn/ubuntu/trunk/lookup-imdb/lookup-imdb sudo chmod 755 /usr/bin/lookup-imdb
Choose System - Preferences - Nautilus Actions Configuration - Add.
Set values in Action tab as below
Label: Lookup IMDB
Path: lookup-imdb
Parameters: %b
Logout and back in again and you should be ready to go.

Note: if you find that your default browser is not being opened by the x-www-browser command then select your default browser by
sudo update-alternatives --config x-www-browser
As of 5 May 2013 this works fine in Ubuntu 12.04 with Unity.

Friday, January 29, 2010

Guice 2.0: Mixing injected and non-injected parameters

Have been using Guice for a couple of years now after a friend at Google put me on to it. Guice 2.0 is great too, one thing it makes easier is mixing injector controlled parameters and non-injector controlled parameters into a constructor (I think constructor injection is way more solid than field/method injection when you can).

The feature is called AssistedInject, here is an example:

public class PersonLocator() {
@Inject
public PersonLocator(GeneralLocator locator, @Assisted String name) {
...
}
}

To instantiate PersonLocator using the injector you need to create a PersonLocatorFactory:

public interface PersonLocatorFactory {
PersonLocator create(String name);
}

Put a binding into the injector module:

bind(PersonLocatorFactory.class).toProvider(
FactoryProvider.newFactory(PersonLocatorFactory.class, PersonLocator.class));

Then to instantiate PersonLocator use an injected PersonLocatorFactory:

public PersonHunter {
@Inject
public PersonHunter(PersonLocatorFactory personLocatorFactory, String name){
PersonLocator personLocator = personLocatorFactory.create(name);
}
}

Thursday, September 24, 2009

Unmarshalling and validating xml without a namespace using JAXB

Unmarshalling and validating xml using jaxb where the xml does not have a namespace specified has driven me crazy for years now. I even did text insertion on the xml before unmarshalling as a workaround. Here's a good way of doing it that's great for xml without any namespace attributes (on the child elements too):

This code unmarshals the object into an org.jdom.Document object then recurses through the object setting namespaces. That object is then passed as a Source to the unmarshaller.

Note also that I did not have @XmlRootElement annotation on GCOM3DRequest so I asked the unmarshaller to unmarshal to that class explicitly.

Primary source for this was here.

package au.gov.amsa.er.nwm.scenario;

import java.io.IOException;
import java.io.InputStream;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Source;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.apache.log4j.Logger;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.jdom.transform.JDOMSource;
import org.xml.sax.SAXException;

import au.gov.amsa.nwm.gcom3drequest.GCOM3DRequest;
import au.gov.amsa.nwm.gcom3drequest.ObjectFactory;

public class RequestMarshaller {

private static Logger log = Logger.getLogger(RequestMarshaller.class);
private JAXBContext jc;
private Schema schema;

public RequestMarshaller() {
try {
jc = JAXBContext.newInstance(ObjectFactory.class.getPackage()
.getName());
} catch (JAXBException e) {
throw new RuntimeException(e);
}

loadSchema();

}

private void loadSchema() {
SchemaFactory sf = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
try {
schema = sf.newSchema(getClass().getResource(
"request/gcom3dRequest.xsd"));
} catch (SAXException e) {
throw new RuntimeException(e);
}
}

private Unmarshaller createUnmarshaller() {
Unmarshaller u;
try {
u = jc.createUnmarshaller();
// validate against the schema
u.setSchema(schema);
return u;
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}

private static Namespace DEFAULT_NS = Namespace
.getNamespace("http://www.amsa.gov.au/nwm/gcom3dRequest");

public GCOM3DRequest unmarshal(InputStream is) throws JAXBException {

try {
SAXBuilder sb = new SAXBuilder(false);
org.jdom.Document doc = sb.build(is);
setNamespace(doc.getRootElement(), DEFAULT_NS, true);

Source src = new JDOMSource(doc);
Unmarshaller u = createUnmarshaller();
u.setSchema(schema);
JAXBElement element = u.unmarshal(src,
GCOM3DRequest.class);
GCOM3DRequest gcom3d = element.getValue();
return gcom3d;
} catch (IOException e) {
throw new RuntimeException(e);
} catch (JDOMException e) {
throw new RuntimeException(e);
}
}

private static void setNamespace(Element elem, Namespace ns, boolean recurse) {
elem.setNamespace(ns);
if (recurse) {
for (Object o : elem.getChildren()) {
setNamespace((Element) o, ns, recurse);
}
}
}

public Marshaller createMarshaller() {
Marshaller m;
try {
m = jc.createMarshaller();
m.setSchema(schema);
return m;
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}

}

Monday, November 3, 2008

Create a WFS 1.1 service in java

I wanted to create an OGC Web Feature Service (version 1.1) from scratch in java. When I tried to use jdk6 xjc with the OpenGIS schemas I had lots of errors so I had to create a bindings file to resolve them. It all works fine now, here are the results of my labours:

Ant fragment:

<exec executable="${xjc}"
failonerror="true"
outputproperty="xjc.output"
errorproperty="xjc.error"
logerror="true">
<arg value="-extension">
<arg value="-verbose">
<arg value="-httpproxy">
<arg value="proxy:8080">
<arg value="-b">
<arg value="${opengis}/wfs/1.1.0/wfs-bindings.xml">
<arg value="-d">
<arg value="${generated}">
<arg value="${opengis}/wfs/1.1.0/wfs.xsd">
<arg value="${opengis}/cts/craft-feature.xsd">
<arg value="${opengis}/ows/1.0.0/owsExceptionReport.xsd">
</exec>


wfs-bindings.xml:

<bindings xmlns="http://java.sun.com/xml/ns/jaxb" version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<bindings schemaLocation="wfs.xsd" node="/xs:schema">
<globalBindings
underscoreBinding="asCharInWord"
/>
<schemaBindings>
<package name="net.opengis.schema.wfs"/>
</schemaBindings>
</bindings>
<bindings schemaLocation="../../gml/3.1.1/base/gml.xsd" node="/xs:schema">
<schemaBindings>
<package name="net.opengis.schema.gml"/>
</schemaBindings>
<bindings schemaLocation="../../gml/3.1.1/base/defaultStyle.xsd" node="/xs:schema/xs:element[@name='topologyStyle']">
<class name="topologyStyleLowerCase"/>
</bindings>
<bindings schemaLocation="../../gml/3.1.1/base/defaultStyle.xsd" node="/xs:schema/xs:element[@name='geometryStyle']">
<class name="geometryStyleLowerCase"/>
</bindings>
<bindings schemaLocation="../../gml/3.1.1/base/defaultStyle.xsd" node="/xs:schema/xs:element[@name='graphStyle']">
<class name="graphStyleLowerCase"/>
</bindings>
<bindings schemaLocation="../../gml/3.1.1/base/defaultStyle.xsd" node="/xs:schema/xs:element[@name='featureStyle']">
<class name="featureStyleLowerCase"/>
</bindings>
<bindings schemaLocation="../../gml/3.1.1/base/defaultStyle.xsd" node="/xs:schema/xs:element[@name='labelStyle']">
<class name="labelStyleLowerCase"/>
</bindings>
</bindings>
<bindings schemaLocation="../../filter/1.1.0/filter.xsd" node="/xs:schema">
<schemaBindings >
<package name="net.opengis.schema.filter" />
</schemaBindings>
</bindings>
<bindings schemaLocation="../../ows/1.0.0/owsAll.xsd" node="/xs:schema">
<schemaBindings>
<package name="net.opengis.schema.ows"/>
</schemaBindings>
</bindings>
</bindings>

Thursday, October 2, 2008

Starting a background thread in Tomcat

I have long running processes that repeatedly do something (like check a directory for new files or a database table for new records) then sleep for a while. These processes are deployed to Tomcat (giving me jsp interfaces for monitoring and any other requests).

Ideally the Tomcat container should manage this long running thread. i.e Tomcat should be aware of the background thread particularly for stopping a web application completely (stopping the background thread) but also for metrics gathering.

I implement long running threads as HttpServlets and start them in my ant build via the task which does an http get to the servlet url. We want the to return control to the build process and not wait for the long running thread to finish. The trick is to simply close the response output stream and continue. i.e.

public abstract class RunnableServlet extends HttpServlet {

private Runnable runnable;

public RunnableServlet(Runnable runnable) {
this.runnable = runnable;
}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String command = req.getParameter("command");

// continue with the task but with the container aware of this thread
if ("start".equals(command)) {
response.getOutputStream().write("started");
response.getOutputStream().close();
runnable.run();
}
}
}

By the way to use the above servlet extend it!
free hit counter

Friday, August 1, 2008

Homemade Digital TV Antenna

living in O'Connor, Canberra I should get good reception from Black Mtn tower but I haven't been able to suss it for a couple of years. Reception was very patchy and for my favourite station SBS was terrible. I just couldn't get my rabbit ears to work well so I made my own antenna. I used that strip tv antenna cable that costs about a dollar per metre from Bunnings and soldered it to a coaxial end.

In detail I cut a 1.8m piece of tv antenna cable and joined the paired wires on the cable together at the ends (so I end up still a 1.8m strip but it has little u turns at the ends). Then I broke one side of the strip and twisted in a bit of copper to then solder the two ends to the coax connector (one end to the centre prong and the other to the outer ring).

Worked ok but was still having some reception problems. Luckily I stumbled upon an article that suggested you make sure there are no sharp curves in your coax cable. When I smoothed that I had flawless reception!

So the deal is you can probably make your own antenna for maybe $10 including a length of coax.

If you have rabbit ears already smooth out the run of coax, no small radius curves. Worked for me.