Categories
Uncategorized

Mapping a servlet to /

An interesting problem cropped up today. We want to use a servlet for the home page in a Spring Web MVC project. Initially we had this in web.xml.

  <servlet>
    <servlet-name>foo</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>foo</servlet-name>
    <url-pattern>*.html</url-pattern>
  </servlet-mapping>

Now, we want to add in a handler specifically for /. How to do that? A bit of googling turned up this method.

  <servlet>
    <servlet-name>foo</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>foo</servlet-name>
    <url-pattern>*.html</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>foo</servlet-name>
    <url-pattern>/home</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>home</welcome-file>
  </welcome-file-list>

I’m not 100% sure why this works—the rules for mapping URLs to servlets are a little confusing to me. But it certainly seems to handle the situation correctly. My initial attempts to get this working managed to break everything by handling everything through the DispatcherServlet, even things like CSS. That was unacceptable.

Aha. Looking in the servlet spec shows why:

Web Application developers can define an ordered list of partial URIs called
welcome files in the Web application deployment descriptor.

I had thought that they were files, not URIs. That explains why it works nicely.

Of course, the solution above will attempt to look for “…/home” in any directory, even though I’ve only set it up to work for the root URL. I don’t think that’s much of a problem though.

Categories
Uncategorized

Writing XML in Java

Last night, I was looking at generating SAMS XML from Java objects. It made me realise two things:

  1. Java sucks badly at creating XML (by default).
  2. I should really be looking at XML Binding.

I’m interested in point 1. I’ve done it before, trying to write XML using DOM (as there doesn’t appear to be a builtin SAX writer). This is what I ended up with.

public abstract class AbstractXmlBuilder {
    protected void addXlinkHref(Element e, URI href) {
        e.setAttributeNS(Constants.XLINK_NS, "x:href", href.toString());
    }

    // See http://www.cafeconleche.org/books/xmljava/chapters/ch09s09.html
    // (JAXP Serialisation) for details on why all this palaver is necessary.
    protected String domToString(Document doc) {
        try {
            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer trans = factory.newTransformer();
            trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            DOMSource source = new DOMSource(doc);
            StringWriter writer = new StringWriter();
            StreamResult streamResult = new StreamResult(writer);
            trans.transform(source, streamResult);
            return writer.toString();
        } catch (TransformerConfigurationException e) {
            throw new RuntimeException(e);
        } catch (TransformerFactoryConfigurationError e) {
            throw new RuntimeException(e);
        } catch (TransformerException e) {
            throw new RuntimeException(e);
        }
    }

    protected Document newDocument(String namespaceURI, String qualifiedName) {
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setNamespaceAware(true);
            DocumentBuilder docBuilder = dbf.newDocumentBuilder();
            DOMImplementation impl = docBuilder.getDOMImplementation();
            return impl.createDocument(namespaceURI, qualifiedName, null);
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        }
    }

    protected Document newDocument() {
        Document doc = newDocument(Constants.MY_NS, "doc");
        Element root = doc.getDocumentElement();
        root.setPrefix("my");
        // Set up the usual namespaces.
        root.setAttribute("xmlns:x", Constants.XLINK_NS);
        return doc;
    }

    protected Element myElem(Document doc, String name) {
        return doc.createElementNS(Constants.MY_NS, name);
    }
}

This is intended to be subclassed to be useful, but even in the subclasses, it still relies on dozens of helper methods. e.g.

    private Element getAccIdElem(SessionCreateRequest s, Document doc) {
        Element accId = myElem(doc, "acc_id");
        addXlinkHref(accId, s.getAccountId());
        return accId;
    }

This is incredibly verbose, but I don’t think we can do better with just the JDK. What are the other options? I’ve been looking at XOM. This appears to have a nice API for writing XML:

    Element root = new Element("root");
    root.appendChild("Hello World!");
    Document doc = new Document(root);
    System.out.println(doc.toXML());

This is much, much simpler. We’re still building a up a DOM-like structure, but it’s simpler to use.

But XOM is still a fairly large dependency. This doesn’t particularly matter for what I’m doing. But there are alternatives. Whilst looking for libraries, I also stumbled across xmlwriter. This is much lower-level:

  Writer writer = new java.io.StringWriter();
  XmlWriter xw = new SimpleXmlWriter(writer);
  xw.writeXmlVersion();
  xw.writeComment("Example of XmlWriter running");
  xw.writeEntity("person");
  xw.writeAttribute("name", "fred");
  xw.writeAttribute("age", "12");
  xw.writeEntity("phone");
  xw.writeText("4254343");
  xw.endEntity();
  xw.writeComment("Examples of empty tags");
  xw.writeEntity("friends");
  xw.writeEmptyEntity("bob");
  xw.writeEmptyEntity("jim");
  xw.endEntity();
  xw.writeEntityWithText("foo","This is an example.");
  xw.endEntity();
  xw.close();
  System.err.println(writer.toString());

This is closer to genx, a C library that I like very much. It’s quite weird that “element” and “entity” appear to be confused, though. Plus there doesn’t appear to be any way to generate canonical XML.

For now, I think I’ll stick with XOM, but it’s good to know that there are alternatives to the heavyweight JDK options.

Categories
Uncategorized

Tomcat Logging in WTP

I’ve just been trying to enable debug logging for tomcat (don’t ask). Normally you do this by editing $CATALINA_HOME/conf/logging.properties and restarting.

Except I tried that in Eclipse (using WTP) and it didn’t work.

I tried copying it to the $CATALINA_BASE/conf directory instead1.

Still no joy.

I’ve just found the answer, after looking in the tomcat source. It turns out that tomcat’s alternative logging implementation (JULI) is enabled via a system property. This happens inside catalina.sh:

# Set juli LogManager if it is present
if [ -r "$CATALINA_BASE"/conf/logging.properties ]; then
  JAVA_OPTS="$JAVA_OPTS -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager"
  LOGGING_CONFIG="-Djava.util.logging.config.file=$CATALINA_BASE/conf/logging.properties"
fi

But Eclipse runs the Java code directly, without using catalina.sh. So the properties never gets set. You have to set them by hand in the “Run Configurations” dialog. Like this:

Setting system properties for tomcat in Eclipse

Of note there is that I’ve imported the logging.properties file into the Servers project of my workspace. It seemed liked a useful place to put it.

Of course, after realising that, I soon find the same information in the WTP FAQ: How do I enable the JULI logging in a Tomcat 5.5 Server instance?.

Anyway, now I might be able to debug that ClassLoader issue…

1 Inside Eclipse with WTP, that will be something like $WORKSPACE/.metadata/.plugins/org.eclipse.wst.server.core/tmp0.