Printing Letter to Tabloid Booklet

I spent too much time today investigating ways to convert four pages of a PDF on letter-sized paper (8.5″x11″) to a PDF with two pages of tabloid-sized paper (11″x17″). The goal is to print the tabloid pages duplex and fold the sheet in the middle to make a booklet. After several unsuccessful Google Web searches, I switched to Google Groups. Groups contained a highly enlightening post that informed readers the printing term for laying out multiple smaller pages on one larger page is called imposition.

Searching for “osx imposition software” was quite fruitful. I eventually tried the demo of BookLightning by metaobject, which sells for $49. I drag-n-dropped my 4 page PDF onto the applications and it immediately produced a new PDF with my desired layout. If I hadn’t caught a snippet of instructions on metaobject’s Web site, I’d have found the application as confusing as others have on VersionTracker. The application gets two-thumbs up from me, but I’m still pondering if the orientation of the second page at 180 degrees from the first will cause headaches on the duplex printers I use.

Understanding Inversion of Control

Cedric recently posted that he does not understand the value of Inversion of Control (abbreviated “IoC”, also called “Dependency Injection” by Martin Fowler).

I believe that development tools (languages, frameworks, libraries, and so on) are built for one of two reasons:
1) To solve a problem encountered by a particular developer or community.
2) For learning and experimenting.

The first case covers the creation of things like Object-Oriented programming, EJB, Hibernate, Aspect-Oriented programming, Spring, Echo, and the Ajax-related technologies. The second case explains the existence of so many dinky IM clients.

Based on these rules and my observations of community reactions to emerging technologies, I’ve concluded that developers don’t understand tools that solve problems outside of their experience. The value of a cup handle is non-obvious to a person who has never held a cup of hot liquid. To those people, the cup handle is a quaint new way to hold a cup, but they don’t “get” why it is better than holding the cup directly. To everyone who has held a cup of hot liquid directly, the value and use of the handle is immediately understood.

So rather than post yet another article explaining why IoC is a Good ThingTM, I will simply state that if you don’t get IoC, you haven’t needed IoC, and you’ll understand when the time comes.

More about Jetty with JamVM on NSLU2

Robert Lougher, maintainer of the JamVM virtual machine, posted a comment to an earlier entry of mine. Rob requested more information about the problem I experienced, so I poked around a little more and responded to him. I am posting the heart of that information here for the benefits of others.

The relevant details are:
- Jetty v5.1.2
- JamVM v1.2.4
- GNU Classpath 0.13

Running the command “java -jar start.jar” produces:

java.lang.NullPointerException
  at java.text.DecimalFormatSymbols.setCurrency (DecimalFormatSymbols.java:397)
  at java.text.DecimalFormatSymbols. (DecimalFormatSymbols.java:151)
  at java.text.NumberFormat.computeInstance (NumberFormat.java:327)
  at java.text.NumberFormat.getNumberInstance (NumberFormat.java:456)
  at java.text.NumberFormat.getInstance (NumberFormat.java:381)
  at java.text.SimpleDateFormat. (SimpleDateFormat.java:218)
  at java.text.SimpleDateFormat. (SimpleDateFormat.java:202)
  at org.mortbay.util.DateCache.setTimeZone (DateCache.java:126)
  at org.mortbay.util.DateCache. (DateCache.java:87)
  at org.mortbay.log.OutputStreamLogSink. (OutputStreamLogSink.java:59)
  at java.lang.reflect.Constructor.constructNative (Native Method)
  at java.lang.reflect.Constructor.newInstance (Constructor.java:265)
  at java.lang.Class.newInstance (Class.java:1146)
  at org.mortbay.log.LogImpl.defaultInit (LogImpl.java:190)
  at org.mortbay.log.LogImpl.message (LogImpl.java:415)
  at org.mortbay.log.LogImpl.message (LogImpl.java:399)
  at org.mortbay.log.LogImpl.info (LogImpl.java:332)
  at org.mortbay.util.FileResource. (FileResource.java:60)
  at org.mortbay.util.Resource.newResource (Resource.java:113)
  at org.mortbay.jetty.Server. (Server.java:78)
  at org.mortbay.jetty.Server.main (Server.java:432)
  at java.lang.reflect.Method.invokeNative (Native Method)
  at java.lang.reflect.Method.invoke (Method.java:355)
  at org.mortbay.start.Main.invokeMain (Main.java:151)
  at org.mortbay.start.Main.start (Main.java:480)
  at org.mortbay.start.Main.main (Main.java:94)
  at java.lang.reflect.Method.invokeNative (Native Method)
  at java.lang.reflect.Method.invoke (Method.java:355)
  at jamvm.java.lang.JarLauncher.main (JarLauncher.java:50)
1113542079746: INFO :Checking Resource aliases @ [main] org.mortbay.util.FileResource.(FileResource.java:60)
java.lang.reflect.InvocationTargetException
  at java.lang.reflect.Method.invokeNative (Native Method)
  at java.lang.reflect.Method.invoke (Method.java:355)
  at org.mortbay.start.Main.invokeMain (Main.java:151)
  at org.mortbay.start.Main.start (Main.java:480)
  at org.mortbay.start.Main.main (Main.java:94)
  at java.lang.reflect.Method.invokeNative (Native Method)
  at java.lang.reflect.Method.invoke (Method.java:355)
  at jamvm.java.lang.JarLauncher.main (JarLauncher.java:50)
Caused by: java.lang.ExceptionInInitializerError
  at org.apache.xerces.impl.dv.xs.SchemaDVFactoryImpl. (Unknown Source)
  at java.lang.reflect.Constructor.constructNative (Native Method)
  at java.lang.reflect.Constructor.newInstance (Constructor.java:265)
  at java.lang.Class.newInstance (Class.java:1146)
  at org.apache.xerces.util.ObjectFactory.newInstance (Unknown Source)
  at org.apache.xerces.impl.dv.SchemaDVFactory.getInstance (Unknown Source)
  at org.apache.xerces.impl.dv.SchemaDVFactory.getInstance (Unknown Source)
  at org.apache.xerces.impl.xs.SchemaGrammar$BuiltinSchemaGrammar. (Unknown Source)
  at org.apache.xerces.impl.xs.SchemaGrammar. (Unknown Source)
  at org.apache.xerces.impl.xs.XMLSchemaValidator. (Unknown Source)
  at org.apache.xerces.parsers.IntegratedParserConfiguration.configurePipeline (Unknown Source)
  at org.apache.xerces.parsers.DTDConfiguration.reset (Unknown Source)
  at org.apache.xerces.parsers.XML11Configuration.parse (Unknown Source)
  at org.apache.xerces.parsers.DTDConfiguration.parse (Unknown Source)
  at org.apache.xerces.parsers.XMLParser.parse (Unknown Source)
  at org.apache.xerces.parsers.AbstractSAXParser.parse (Unknown Source)
  at javax.xml.parsers.SAXParser.parse (SAXParser.java:273)
  at org.mortbay.xml.XmlParser.parse (XmlParser.java:165)
  at org.mortbay.xml.XmlParser.parse (XmlParser.java:181)
  at org.mortbay.xml.XmlConfiguration. (XmlConfiguration.java:122)
  at org.mortbay.jetty.Server. (Server.java:103)
  at org.mortbay.jetty.Server. (Server.java:78)
  at org.mortbay.jetty.Server.main (Server.java:432)
  at java.lang.reflect.Method.invokeNative (Native Method)
…7 more
Caused by: java.lang.RuntimeException: internal error
  at org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl.applyFacets1 (Unknown Source)
  at org.apache.xerces.impl.dv.xs.SchemaDVFactoryImpl.createBuiltInTypes (Unknown Source)
  at org.apache.xerces.impl.dv.xs.SchemaDVFactoryImpl. (Unknown Source)
  at org.apache.xerces.impl.dv.xs.SchemaDVFactoryImpl. (Unknown Source)
…30 more

However, launching the application “manually” using the following command got me further (the server listens on 8080 and provides a listing of the known webapps):

java -cp /opt/jetty-5.1.2/lib/org.mortbay.jetty.jar:/opt/jetty-5.1.2/lib/javax.servlet.jar:/opt/jetty-5.1.2/ext/jasper-runtime.jar:/opt/jetty-5.1.2/ext/jasper-compiler.jar:/opt/jetty-5.1.2/ext/xercesImpl.jar:/opt/jetty-5.1.2/ext/commons-logging.jar org.mortbay.jetty.Server

So the problem might be Jetty’s, not JamVM’s.