<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Root Beer</title>
  <subtitle>Chris Nokleberg&apos;s Fizzy Weblog</subtitle>
  <link href="http://sixlegs.com/blog/"/>
  <link rel="self" href="http://sixlegs.com/blog/atom.xml"/>
  <updated>2007-03-23T10:18:08-07:00</updated>
  <author>
    <name>Chris Nokleberg</name>
    <uri>http://sixlegs.com/</uri>
    <email>chris@sixlegs.com</email>
  </author> 
  <rights>Copyright (c) 2005, Chris Nokleberg</rights>
  <id>tag:sixlegs.com,2005:RootBeer</id>
  <entry>
    <title>Shrinking Jars with Jar Jar</title>
    <link href="http://sixlegs.com/blog/java/jarjar-keep.html"/>
    <id>tag:sixlegs.com,2005:/blog/jarjar-keep</id>
    <updated>2007-03-23T10:17:26-07:00</updated>
    <content type="xhtml" xml:lang="en">
      <div xmlns="http://www.w3.org/1999/xhtml"><p>After a few years of development I think <a href="http://tonicsystems.com/products/jarjar/">Jar Jar Links</a> is in the home stretch, up to version 1.0rc3 now.</p>

<p>Part of the problem was deciding how to handle manifest files in merged jars. Thankfully while I sat and did nothing the Ant team added a "filesetmanifest" attribute to the <a href="http://ant.apache.org/manual/CoreTasks/jar.html">Jar task</a> which for now should handle most needs (re-signing jars is a still a known issue).</p>

<p>Maven support also came up from time to time, so eventually I broke down and added a plugin. It is pretty simple but has almost all the features of the Ant task. Look for the "plugin" jar on the download page. I'm not sure if anyone has used this yet so feedback would be appreciated.</p>

<p>Finally, in the 11th hour I've added a new feature. Previously you could exclude certain classes from the resulting jar file using the "zap" rule. However, this was a course-grained and somewhat error-prone approach to shrinking your jar file. On some projects of mine I've avoided the use of "zap" and instead followed jarjar with <a href="http://proguard.sourceforge.net/">ProGuard</a>. While this can work well it is a heavyweight solution and configuring ProGuard can sometimes be a pain.</p>

<p>The solution is a new "keep" rule. You can have multiple keep rules and they each take a wildcard pattern which defines which classes must be retained in the final jar (the roots of the dependency tree). It then transitively computes all the dependencies and throws everything else away. Because jarjar already had a lot of dependency checking code built-in it was a relatively minor feature to add. Unlike ProGuard this only works on the class level, but for a lot of jarjar uses there will still be significant savings. For example, in the new <a href="http://code.google.com/p/google-guice/">Guice</a> project adding a single <code>&lt;keep pattern="com.google.**"/&gt;</code> rule reduced the jar size from 500K to 376K.</p>

<p>To give credit where it is due, this feature was partly inspired by Torsten Curdt's <a href="http://mojo.codehaus.org/minijar-maven-plugin/">minijar</a> project (which in turn has a repackaging feature which seems to have been inspired by jarjar?). I guess jarjar and minijar are pretty similar now, except for license differences and that minijar is Maven-specific. The more the merrier :)</p></div>
    </content>
    <category term="java" scheme="http://sixlegs.com/blog/"/>
  </entry>
  <entry>
    <title>TonicPoint</title>
    <link href="http://sixlegs.com/blog/java/tonicpoint.html"/>
    <id>tag:sixlegs.com,2005:/blog/tonicpoint</id>
    <updated>2006-12-08T03:13:58-08:00</updated>
    <content type="xhtml" xml:lang="en">
      <div xmlns="http://www.w3.org/1999/xhtml"><p><i><b>Update:</b> Over the last month or two I've probably given the same
in-person demo 20 times so I decided it would behoove me to
make a <a href="http://beta.tonicpoint.com/demo/" target="demo">screencast of the editor in action</a>
(Flash 8 required, sorry). It's a little rough but hopefully gets the message across.</i></p>

<p>For anyone who's curious what I've been up to the last six months,
there's finally something to point to: <a href="http://beta.tonicpoint.com/">http://beta.tonicpoint.com/</a>.
I know, it is just some screenshots, but there really is a site hidden underneath!</p>

<p>Most of the site was pulling together pieces of our existing
technology&#8212;PowerPoint file format I/O, PNG/PDF/SWF/SVG generation,
etc.  The biggest new piece of code is the
<a href="http://beta.tonicpoint.com/images/ss-edit.png">editor</a>. While it's not
intended to replace PowerPoint, it nonetheless should be a showcase for
how rich standards-based webapps really can be (it heavily uses SVG on
browsers that support it, and eventually VML on IE). There's a lot of
fodder for future posts here, so now I have no excuse not to blog. For
now I will just say that <a href="http://www.mochikit.com/">MochiKit</a>
<i>does</i> make JavaScript suck less, but suckiness is still greater than
zero.</p>

<p>I'll also take this time to plug the
<a href="http://aws.amazon.com">Amazon Web Services</a>. We're currently
using both S3 and EC2, which we expect will make it quite easy for us to
scale up as we need to. I hope companies with the infrastructure will
follow Amazon's lead&#8212;a competitive marketplace for storage and
computing services would be awesome. Perhaps overly optimistically we've
already structured our internal interfaces to allow us to easily switch
providers :)</p>

<p>p.s. I'll be at the <a href="http://www.office20con.com/">Office 2.0 Conference</a>
next week, drop me a line if you want to meet up.</p></div>
    </content>
    <category term="java" scheme="http://sixlegs.com/blog/"/>
  </entry>
  <entry>
    <title>Java and the Open Packaging Conventions</title>
    <link href="http://sixlegs.com/blog/java/java-opc.html"/>
    <id>tag:sixlegs.com,2005:/blog/java-opc</id>
    <updated>2006-11-30T13:38:55-08:00</updated>
    <content type="xhtml" xml:lang="en">
      <div xmlns="http://www.w3.org/1999/xhtml"><p>Over the last few months I've been investigating adding support for MS
Office 2007 file formats (aka <a href="http://en.wikipedia.org/wiki/Microsoft_Office_Open_XML">Office Open XML</a>) to our <a href="http://tonicsystems.com/">enterprise products</a>.
Now compared to supporting the binary file formats it is almost trivial,
but there is still a fair bit of code involved!</p>

<p>The first step is to support the underlying packaging format, which is
known as the Open Packaging Conventions. It is essentially a ZIP file
with some XML files which describe the relationships between the various
entries, their content types, etc. After playing with it a little while
it seems pretty thought out, although of course I am biased because of a
scarring exposure to OLE internals. The spec is available a number of
places but the version I prefer is Part 2 of the ECMA TC45 Final Draft,
<a href="http://www.ecma-international.org/memento/TC45.htm">available here</a>.</p>

<p>To manipulate OPC documents Microsoft provides the .NET
<a href="http://msdn2.microsoft.com/en-us/library/system.io.packaging.aspx">System.IO.Packaging</a> API. When I first looked around there was no Java
API so I created one for internal use, patterned after the .NET version.
In the meantime Julien Chable posted what looks like a complete
Java-based API along with an article describing its use on the
<a href="http://openxmldeveloper.org/articles/OpenXMLandJava.aspx">http://openxmldeveloper.org/</a>
site. I'm not sure if the code is open-source, though, because I can't find a license listed.
Another useful tool is <a href="http://diffopc.arstdesign.com/">diffopc</a>, which shows a graphical diff
between the contents of two ZIP files (it can also be used for other ZIP-based formats like <a href="http://en.wikipedia.org/wiki/OpenDocument">ODF</a>).</p>

<p>One shared drawback of Julien's and my library is that they cannot
update an existing document in-place. Instead, after you have made
changes, you need to write out a new file. The primary reason for
this (at least in my library) is that the Java ZIP APIs do not support it.
In fact it is currently the <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4129445">#20 most-requested enhancement</a> (see <a href="http://bugs.sun.com/bugdatabase/top25_rfes.do">the full list</a>).
If you feel like helping me out then adding a vote to this bug couldn't hurt :)</p>

<p>Ant also has some ZIP code but it is basically identical to the Java
API. However, it is ASL 2.0 and could be the basis for a more
full-featured library. There is also the <a href="https://truezip.dev.java.net/">TrueZIP</a> project, which is
<i>very</i> full-featured, almost to a fault&#x2014;it supports a bunch
of other non-ZIP formats and weighs in over 200K but still does not yet
support some necessary extensions (e.g. zip64). In the meantime I've decided to just stick with
the java.util.zip API and live with the limitations.</p>

<p>p.s. my Gmail spam folder is over 34000 now (&gt; 1000/day), a personal record&#x2014;hooray.</p></div>
    </content>
    <category term="java" scheme="http://sixlegs.com/blog/"/>
  </entry>
  <entry>
    <title>Making more objects mockable with Definalizer</title>
    <link href="http://sixlegs.com/blog/java/definalizer.html"/>
    <id>tag:sixlegs.com,2005:/blog/definalizer</id>
    <updated>2006-05-25T18:42:31-07:00</updated>
    <content type="xhtml" xml:lang="en">
      <div xmlns="http://www.w3.org/1999/xhtml"><p>After reading <a href="http://blogs.objectmentor.com/ArticleS.MichaelFeathers.ItsTimeToDeprecateFinal">this diatribe on the use of the final modifier</a>,
I decided to implement one of the commenters' suggestions: write a tool to strip them out.
Of course, by the time I was almost finished I stumbled across
<a href="http://blogs.sun.com/roller/page/xzajo/20060513">Xzajo's BCEL-based implementation</a>,
which was only posted a couple of weeks ago.</p>

<p>My implementation has a couple of advantages:</p>
<ul>
<li>It has no dependencies (<a href="http://asm.objectweb.org/">ASM</a> is <a href="http://jarjar.sf.net/">Jar Jar'd</a>).</li>
<li>It removes final modifiers from methods, too.</li>
</ul>

<p>Here is all the code:</p>
<pre>
package com.sixlegs.definalizer;

import java.lang.instrument.*;
import java.security.ProtectionDomain;
import org.objectweb.asm.*;
import static org.objectweb.asm.Opcodes.ACC_FINAL;

public class Main implements ClassFileTransformer
{
  public static void premain(String args, Instrumentation inst) {
    inst.addTransformer(new Main());
  }

  public byte[] transform(ClassLoader loader, String className, 
    Class&lt;?&gt; clazz, ProtectionDomain protectionDomain, byte[] b) {
    ClassReader reader = new ClassReader(b);
    ClassWriter writer = new ClassWriter(true);
    ClassAdapter adapter = new Definalizer(writer, className);
    reader.accept(adapter, true);
    return writer.toByteArray();
  }

  static class Definalizer extends ClassAdapter 
  {
    public Definalizer(ClassVisitor cv, String className) {
      super(cv);
    }

    @Override public void visit(int version, int access, /* ... */) {
      access &amp;= ~ACC_FINAL;
      cv.visit(version, access, name, signature, superName, interfaces);
    }

    @Override public MethodVisitor visitMethod(int access, String name, /* ... */) {
      access &amp;= ~ACC_FINAL;
      return cv.visitMethod(access, name, desc, signature, exceptions);
    }
  }
}
</pre>

<p>Compile this code into a jar and specify a "Premain-Class" manifest entry:</p>
<pre>
Premain-Class: com.sixlegs.definalizer.Main
</pre>

<p>Now the jar can be specified as an argument to <code>-javaagent</code>.
Here is an example which demonstrates using CGLIB to create a subclass at runtime:</p>

<pre class="highlight">
import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;

public class Test
{
  public static class FinalExample {
    @Override final public String toString()  {
      return "final method";
    }
  }
  
  public static void main(String[] args) throws Exception {
    Enhancer e = new Enhancer();
    e.setSuperclass(FinalExample.class);
    e.setCallback(new MethodInterceptor(){
      public Object intercept(Object obj, Method method,
        Object[] args, MethodProxy proxy) throws Throwable {
        System.err.println("calling " + method);
        return proxy.invokeSuper(obj, args);
      }
    });
    System.err.println("RESULT: " + (FinalExample)e.create());
  }
}</pre>

<p>The command line I used to run it was:</p>
<pre>CLASSPATH=.:cglib.jar java -javaagent:definalizer.jar Test</pre>

<p>Normally this would fail because the class and method are final, but
because definalizer has stripped all of the final modifiers, the method
is successfully intercepted:</p>

<pre>
calling public java.lang.String Test$FinalExample.toString()
</pre>

<p>The entire source distribution can be <a href="http://sixlegs.com/misc/definalizer-0.1-src.jar">downloaded here</a>,
or <a href="http://sixlegs.com/misc/definalizer.jar">just the binary jar</a> (use at your own risk). If someone is interested in
integrating this into their own project, let me know.</p></div>
    </content>
    <category term="java" scheme="http://sixlegs.com/blog/"/>
  </entry>
  <entry>
    <title>Free cross-platform PowerPoint viewer</title>
    <link href="http://sixlegs.com/blog/java/powerpoint-viewer.html"/>
    <id>tag:sixlegs.com,2005:/blog/powerpoint-viewer</id>
    <updated>2006-04-27T09:21:29-07:00</updated>
    <content type="xhtml" xml:lang="en">
      <div xmlns="http://www.w3.org/1999/xhtml"><img src="http://sixlegs.com/img/viewerlogo.png" width="64" height="64" alt="TonicPoint Viewer Logo" style="float: left; padding-right: 5px"/>
<p>Today we are releasing a free Java-based desktop application which
can view Microsoft PowerPoint 97-2003 presentations. 
<a href="http://tonicsystems.com/products/viewer/">Download it here</a>,
or <a href="http://tonicsystems.com/products/viewer/features">look at
the screenshots</a>. It uses the same underlying code as our enterprise
Java libraries and should run on any platform where the 1.5 JRE is
available.</p>

<p>OS X and Linux users should find it especially useful as Microsoft does
not provide a free viewer for those platforms (the last viewer for the
Mac was for Office 98 and requires OS 9). It should also start up faster
and have better overall fidelity than free office suites like
OpenOffice. There is no true "slide show" mode yet (we hope to add that
eventually), but the slide navigator view and incremental search feature
make browsing nicer.</p>

<p>Although fidelity is one of our top goals, there are likely a few things that
are "not quite right" because our knowledge of the file format is necessarily
reverse-engineered. If you find a presentation which demonstrates a bug,
please visit <a href="http://forums.tonicsystems.com/">our forums</a>.
Of course feature suggestions are welcome too!</p>

<p>On the technical side, there are a bunch of libraries and tools which we used
in creating the viewer, besides the standard ones like Ant and Emacs :).
Here are most of them:</p>
<ul>
<li><a href="http://xmlgraphics.apache.org/batik/">Batik</a> (for <a href="http://www.jroller.com/page/gfx/?anchor=new_gradients_in_java2d">linear and radial gradients</a>)</li>
<li><a href="http://schmidt.devlib.org/image-info/">ImageInfo</a> (to determine image dimensions)</li>
<li><a href="http://sixlegs.com/software/png/">Sixlegs PNG</a> (to decode PNG images)</li>
<li><a href="http://browserlaunch2.sourceforge.net/">BrowserLauncher</a> (to open browser to help page)</li>
<li><a href="http://www.jgoodies.com/">JGoodies Forms/Looks</a> (for layout and non-Mac L&amp;F)</li>
<li><a href="http://tonicsystems.com/products/jarjar/">Jar Jar Links</a> (to pack all libraries into a single jar)</li>
<li><a href="http://proguard.sourceforge.net/">ProGuard</a> (to compress the bytecode)</li>
<li><a href="http://informagen.com/JarBundler/">JarBundler</a> (to build OS X app bundle)</li>
<li><a href="http://launch4j.sourceforge.net/">Launch4j</a> (to build Windows EXE)</li>
<li><a href="http://nsis.sourceforge.net/">NSIS</a> (to build Windows installer)</li>
<li><a href="http://aws.amazon.com/s3">Amazon S3</a> (to host the downloads)</li>
</ul>

<p>The code is structured so that the viewer <i>could</i> be launched via
<a href="http://java.sun.com/products/javawebstart/">Java Web Start</a>,
although the experience isn't quite as nice as a desktop app. If anyone
really wants to run this via Web Start, let me know.</p></div>
    </content>
    <category term="java" scheme="http://sixlegs.com/blog/"/>
  </entry>
  <entry>
    <title>Jar Jar now supports Mustang-style classpath wildcards</title>
    <link href="http://sixlegs.com/blog/java/classpath-wildcards.html"/>
    <id>tag:sixlegs.com,2005:/blog/classpath-wildcards</id>
    <updated>2006-03-20T15:50:19-08:00</updated>
    <content type="xhtml" xml:lang="en">
      <div xmlns="http://www.w3.org/1999/xhtml"><p>Classpath wildcards are a long-awaited feature which are finally making
their appearance in Mustang. You can read more about them
<a href="http://blogs.sun.com/mr?entry=class_path_wildcards_in_mustang">here</a>
and <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6268383">here</a>.</p>

<p>Now that the syntax is nailed down I've added the same capabilities to
the latest release of the <a href="http://jarjar.sf.net/">Jar Jar Links</a> library.
In particular the <a href="http://sixlegs.com/blog/java/depfind.html">dependency
finding</a> feature is much easier to use now:</p>

<pre>
$ java -jar jarjar.jar --find --level=jar 'lib/*'
</pre>

<p>This will parse all of the jar files in the lib directory and print out
all of the inter-jar dependencies. Note that the asterisk normally must be
quoted in order to prevent expansion by the shell.</p>

<p>One good use I've found for the dependency code is in building WAR
files. We have a number of web applications built from the same source
tree, and each one depends on a slightly different set of libraries. The
simple approach is to just dump every library into every WAR, but it is
not too much harder to use Jar Jar to determine exactly which libraries
should be included.</p>

<p>Because the format of the <code>--find</code> command to Jar Jar is not exactly
what we need, we can use the programmatic API instead:</p>

<pre class="highlight">
import com.tonicsystems.jarjar.*;
public class DepDump
{
    public static void main(String[] args) throws Exception {
        DepHandler handler = new AbstractDepHandler(DepHandler.LEVEL_JAR){
            public void handle(String from, String to) {
                System.out.println(new File(to).getName());
            }
        };
        new DepFind().run(args[0], args[1], handler);
    }
}
</pre>

<p>This will only print out the dependencies in the second classpath
argument. For example:</p>

<pre>
$ java DepDump build/main 'lib/*' &gt; includes.txt
</pre>

<p>Assuming all of your class files are in <code>build/main</code> and your libraries in
<code>lib</code>, this will only print out the names of the libraries that your code actually
uses. Redirecting the output to includes.txt is useful because in our
Ant task we can use the <code>includesfile</code> option to only add those
particular libraries to our WAR:</p>

<pre>
&lt;zipfileset dir="lib" prefix="WEB-INF/lib" includesfile="includes.txt"/&gt;
</pre>

<p>If you are using the <code>JarJarTask</code> to embed other libraries, using the
<code>DepFind</code> API can also be useful to verify that the resulting library has
zero dependencies.</p></div>
    </content>
    <category term="java" scheme="http://sixlegs.com/blog/"/>
  </entry>
  <entry>
    <title>Serving Pack200 Jar files with Apache 2</title>
    <link href="http://sixlegs.com/blog/java/pack200-apache.html"/>
    <id>tag:sixlegs.com,2005:/blog/pack200-apache</id>
    <updated>2006-03-02T14:25:31-08:00</updated>
    <content type="xhtml" xml:lang="en">
      <div xmlns="http://www.w3.org/1999/xhtml"><p>I've been working on an application which can be deployed via Java
Web Start. One nice think about Web Start is that it will
use <a href="http://java.sun.com/j2se/1.5.0/docs/guide/deployment/deployment-guide/pack200.html">content
negotiation</a> with the server to download highly compressed jar files
when they are available.</p>

<p>The documentation includes sample Servlet code to handle the
negotiation, which is nice, but I didn't want to run a Servlet container
just for this. Thankfully I ran across Keith Lea's blog entry
<a href="http://joust.kano.net/weblog/archive/2004/10/16/pack200-on-apache-web-server/">Guide:
How to use Pack200 for your Java Web Start applications on Apache Web
Server</a> which shows how to use Apache's own content negotiation
modules and eliminates the need for any Servlets. However, it seemed
like it could still be made a little simpler. In particular, I didn't
like having to create a "type map" for each compressed jar. What follows is
what I <i>think</i> is the simplest possible configuration for getting
this to work on Apache 2.</p>

<p>Add the following to your global <code>httpd.conf</code> file:</p>
<pre>
AddType application/x-java-jnlp-file .jnlp
AddType application/x-java-archive .jar
&lt;Files *.jar.gz&gt;
  AddEncoding x-gzip .jar
  ForceType application/x-java-archive
&lt;/Files&gt;
&lt;Files *.jar.pack.gz&gt;
  AddEncoding pack200-gzip .jar
  ForceType application/x-java-archive
&lt;/Files&gt;
</pre>

<p>In each folder where you will serve jar files from, add
an <code>.htaccess</code> file with these lines:</p>
<pre>
Options +MultiViews
MultiviewsMatch Any
</pre>

<p>That's it for configuration! Now you just have to drop the right jars
into the folder with the <code>.htaccess</code> file. If your original
jar is named <code>foo.jar</code>, you should put the following into the
folder:</p>
<dl>
<dt><code>foo.jar.unpacked</code></dt><dd>original jar, just renamed</dd>
<dt><code>foo.jar.gz</code></dt><dd>gzipped</dd>
<dt><code>foo.jar.pack.gz</code></dt><dd>compressed with Pack200</dd>
</dl>

<p>For my application these three jars were 823, 698, and 234 kilobytes,
respectively. Because Web Start auto-updates those bytes can really
add up in saved bandwidth costs over time.</p>

<p>Here is a simple shell script which will take a single unpacked jar
file and create the three necessary files:</p>
<pre>
#!/bin/sh
gzip -c $1 &gt; $1.gz
pack200 $1.pack.gz $1
mv $1 $1.unpacked
</pre>

<p>Note that renaming <code>foo.jar</code>
to <code>foo.jar.unpacked</code> is a critical step. The Apache
MultiViews feature will disregard the compressed jars and always
serve <code>foo.jar</code> if it actually exists. You don't have to use
the <code>.unpacked</code> suffix, just make sure to tack on
something.</p></div>
    </content>
    <category term="java" scheme="http://sixlegs.com/blog/"/>
  </entry>
  <entry>
    <title>Compiling the JSP EL to bytecode</title>
    <link href="http://sixlegs.com/blog/java/compiled-el.html"/>
    <id>tag:sixlegs.com,2005:/blog/compiled-el</id>
    <updated>2006-02-15T12:09:50-08:00</updated>
    <content type="xhtml" xml:lang="en">
      <div xmlns="http://www.w3.org/1999/xhtml"><p>I recently came across Matthias Ernst's
<a href="http://www.mernst.org/blog/archives/02-01-2006_02-28-2006.html#39">blog entry</a>
on compiling the JSP expression language. Back in the day this was
something that I spent a bit of time on myself, but the code has been
languishing ever since we decided to focus on <a href="http://tonicsystems.com/">PowerPoint
solutions</a>, so Matthias has inspired me to dust it off and release it
as an open source project.</p>

<p><a href="http://sixlegs.com/misc/el.zip">This zip file</a> includes the entire project: Ant build file, JUnit tests, and
all the necessary libraries. It uses ASM 3.0 (beta) for bytecode
generation, and <a href="http://jarjar.sf.net/">Jar Jar Links</a> to embed the ASM libraries
when building the library Jar file. The source uses the same license
as <a href="http://www.gnu.org/software/classpath/">GNU Classpath</a> (GPL with library exception).</p>

<p>The library needs some more documentation, but essentially it is just an implementation of 
the <code><a href="http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/jsp/el/ExpressionEvaluator.html">javax.servlet.jsp.el.ExpressionEvaluator</a></code> interface:</p>

<pre class="highlight">
ExpressionEvaluator eval = new com.tonicsystems.el.Evaluator();
Expression e = eval.parseExpression("${8 * 8}", String.class, null);
assertEquals("64", e.evaluate(null));
</pre>

<p>The main benefit of byte-compiling is of course performance. In my very
simple tests the performance ranges from about 5-10x faster than the
Apache Commons EL, which uses an interpreter. However there are some
areas of the EL spec which cause big problems for byte-compiling. In
particular, the resulting type when dereferencing variables, Maps, and
Lists cannot be known until runtime.</p>

<p>The general solution to the unknown type issue is to compile as much of
an expression as you can, and lazily compile the rest once you have
enough information (i.e. when the variables have been defined). The
problem with this is it is possible to design some degenerate
expressions which have to be split up into many different
subexpressions, all compiled separately. To help counter this, I've
added an extension to the parsing interface whereby you can optionally
specify a <i>prototype</i> for your variables. This is basically just a
Map which "resembles" the variables you will actually end up using. The
compiler ignores the actual values, but uses the types of the objects to
generate more efficient bytecode:</p>

<pre class="highlight">
Map prototypes = new HashMap();
prototypes.put("a", new Integer(0));
Expression e = eval.parseExpression("${a + 3}", String.class, null, prototypes);
</pre>

<p>Another bytecode-specific issue is that the JSP EL interfaces only
provide a way to parse one expression at a time, but you <i>really</i> do not
want to compile each expression into a new class. For this I've added a
Precompiler class which can take multiple expressions and ensure that
they are all compiled into a single underlying class:</p>

<pre class="highlight">
Precompiler.process(new Expression[]{ e1, e2, e3 });
</pre>

<p>BTW, I recently changed the code to use a custom ClassLoader instead of
injecting the classes into the parent, in order to facilitate garbage
collection compiled expressions. However, this seems to
have a negative effect on the runtime performance--the expressions run
about twice as slow. Does the use of custom ClassLoaders affect HotSpot
somehow?</p>

<p>Because the code is relatively old and was never completely finished,
there are a few things on the TODO list:</p>
<ul>
<li>Support for JSP 2.1</li>
<li>Use generic type information to improve the bytecode, when available</li>
<li>Support for the implicit objects defined by JSP</li>
<li>More tests (or get access to the official tests)</li>
<li>Documentation</li>
</ul>
<p>If people are interested in working on the code, let me know and I'll register a
project somewhere like SourceForge.</p></div>
    </content>
    <category term="java" scheme="http://sixlegs.com/blog/"/>
  </entry>
  <entry>
    <title>Introductory article on CGLIB</title>
    <link href="http://sixlegs.com/blog/java/oci-cglib-article.html"/>
    <id>tag:sixlegs.com,2005:/blog/oci-cglib-article</id>
    <updated>2005-11-01T10:18:37-08:00</updated>
    <content type="xhtml" xml:lang="en">
      <div xmlns="http://www.w3.org/1999/xhtml"><p>I just came across a <a href="http://www.ociweb.com/jnb/jnbNov2005.html">this article</a> on
<a href="http://cglib.sf.net/">CGLIB</a>. It's the kind of thing I've meant to write for a long time, so
I'm glad someone has done it. It provides a nice overview of the proxy
side of CGLIB, including using a CallbackFilter and multiple
interceptors.</p></div>
    </content>
    <category term="java" scheme="http://sixlegs.com/blog/"/>
  </entry>
  <entry>
    <title>Please document EMF+</title>
    <link href="http://sixlegs.com/blog/java/please-document-emf-plus.html"/>
    <id>tag:sixlegs.com,2005:/blog/please-document-emf-plus</id>
    <updated>2005-10-10T12:08:21-07:00</updated>
    <content type="xhtml" xml:lang="en">
      <div xmlns="http://www.w3.org/1999/xhtml"><p>As part of our <a href="http://sixlegs.com/blog/java/powerpoint-renderer.html">Java
PowerPoint renderer</a> I've had to decode all of the
image formats that can be embedded within PowerPoint, including
the three metafile formats: WMF, EMF, and PICT. Now I could write a
whole essay on the how ugly these formats are, but it wouldn't really be
fair. All three are mostly just straight dumps of API
method calls and in-memory records to disk. A fine choice at the time,
I'm sure, but it means that to accurately render them you have to
reimplement a big chunk of Windows GDI and Color QuickDraw.</p>

<p>On the Windows platform,
<a href="http://msdn.microsoft.com/library/en-us/gdicpp/gdiplus/gdiplus.asp">GDI+</a>
promised to make a lot of the headaches of GDI go away. First and foremost,
GDI+ is much more device-independent than GDI. For example, GDI+ did away with
<a href="http://msdn.microsoft.com/library/en-us/gdi/pantdraw_6n77.asp">raster operations</a>,
which are particularly difficult to deal with when converting to modern vector formats like PDF
or SVG (although 
<a href="http://www.svgopen.org/2003/papers/RasterOperationsUsingFilterElements/">people have made
valiant efforts</a>). GDI+ also introduced a new metafile format, <a href="http://msdn.microsoft.com/library/en-us/gdicpp/GDIPlus/aboutGDIPlus/imagesbitmapsandmetafiles/metafiles.asp">EMF+</a>.
Because EMF+ uses the new GDI+ records, it <i>should</i> be much nicer to work with.
Some other advantages of EMF+ over EMF:</p>
<ul>
<li>Gradient fills are represented mathematically,
instead of by hundreds of tiny polygons (such "fake" gradients are very common in
EMF files, and prevent them from being anti-aliased without serious artifacts)</li>
<li>Embedded images are stored as PNG or JPEG, instead of BMP</li>
<li>Support for full transparency, instead of faking binary transparency
using bitmasks and raster operations</li>
</ul>

<p>Unfortunately, EMF+ is almost completely undocumented. People ask about it on
the newsgroups from time to time, but <a href="http://groups.google.com/group/microsoft.public.dotnet.framework.drawing/msg/b15f1fcb9155a752">this</a> is the closest
thing I found to an answer from Microsoft, three years ago. Luckily, in my searches I did find Jeremy Todd,
who as it turned out had reverse-engineered a good chunk of the 
<a href="http://www.aces.uiuc.edu/~jhtodd/Metafile/">EMF+
records</a> himself. There are still a number of missing pieces,
some of them critical, but it should be a very good base on which to build.
One of the reasons for this blog entry is to get the search engines to index his page!</p>

<p>What does this have to do with PowerPoint?  There is another variation
of EMF+, called EMF+ Dual. Dual metafiles are EMF files with EMF+
records hidden inside EMF comments. This lets applications that
understand EMF render them as normal. Applications which know to look
for the special EMF+ comments can extract the EMF+ records and use them
to render instead. In recent version of Microsoft Office, all generated EMFs
are actually EMF+ Dual metafiles, including
all the charts in Excel and PowerPoint.</p>

<p>The upshot is that currently <b>only Microsoft can leverage their knowledge of the
EMF+ records in order to produce better looking and more compact output
when <a href="http://blogs.msdn.com/brian_jones/archive/2005/10/01/476067.aspx">converting documents to PDF</a></b>.
Even after transitioning to their <a href="http://blogs.msdn.com/brian_jones/archive/2005/06/01/424085.aspx">new XML formats</a>,
image objects, including EMF, will exist as binary files within the container ZIP.
Hopefully Microsoft will see fit to finally document EMF+, because otherwise
I don't see how the presence of secret binary data can be reconciled with
the stated goal of an open format.</p></div>
    </content>
    <category term="java" scheme="http://sixlegs.com/blog/"/>
  </entry>
</feed>
