Developing Plug-Ins For Applets
By Adrian Sutton
One of the new features in EditLive! 6.1 that we released today is a plug-in architecture that handles deployment of extensions to the editor. Plug-ins in Java apps are pretty common these days, but there aren’t all that many applets that have them so I thought it would be worth documenting some of the challenges we faced and how we overcame them.
The biggest differences between plug-ins for applications vs applets are:
- Start-up time is really sensitive.
- Download size is sensitive, but mostly just when it affects start-up time.
- Security matters.
- Resources are non-local.
Resources Are Non-Local
You don’t just get to read all the files in a local directory and load them as plug-ins, you have to have some mechanism for plug-ins to be loaded specifically and you need to download and cache them. This is where it would be really useful to have a ready-made library for client side HTTP caching, sadly no such thing currently exists.
Security Matters
Most plug-in architectures use separate class loaders for each plug-in, custom class loaders make for some security challenges, particularly when combined with local caching. While standalone applications generally just give plug-ins full permissions, applets need to make sure that the plug-ins follow the security restrictions that usually apply to applets. So you need to verify the signatures on jar files and make sure the user is prompted to accept them. Even if you can trust the system administrator not to load nasty plug-ins, having a plug-in capable applet that doesn’t enforce security on the plug-ins turns any cross-site scripting vulnerability into an exploit of the user’s local account.
When resources are loaded from a local cache, you really should preserve the original location and apply security policies on that instead of the local source.
The Java plug-in gets all of these things right, so one option is to just add any needed jar files to the applet’s classpath and let the plug-in handle it all. The downside to this approach is that you have little to no control over when that jar file will be downloaded and what thread will suddenly be stopped while it does so. The plug-in by default only loads jar files when it needs them, so if you only have one loaded plug-in this is workable. You have to make sure you don’t have any code that searches the classpath (no JAXP or similar discovery mechanisms) and no ClassNotFoundExceptions and obviously the plug-in jar needs to be last on the applet classpath. As soon as you get two plug-ins though, you can’t dynamically decide which plug-in to load first. You also can’t provide any feedback to the user that a plug-in jar is downloading – if they’ve performed a command that needs that plug-in, the applet will just lock up until the jar finishes downloading. The best you could do is display a dialog with an indeterminate progress bar and trigger the plug-in class loading off the swing thread, but you can’t find out how long the download will take or where it’s up to.
A custom class loader can delegate to the applet’s class loader for determining security which takes care of most of these issues, you just need to do it carefully to make sure the right information is passed back and forth.
Start-up Time Really Matters
The biggest complaint about applets is that they take too long to start, so you need to do everything you can to speed that up. Plug-ins, done right, can help here. The key to it, is to make sure plug-ins don’t load at start up unless they absolutely have to. EditLive! has three plug-in loading modes:
- immediate – load and init the plug-in before starting up the editor.
- background – start loading the plug-in in a background thread and init it when it’s ready.
- lazy – start loading the plug-in in a background and init it when the user performs an action that requires the plug-in.
The background and lazy loading modes don’t cause the applet start-up to be delayed and usually result in the plug-in being ready by the time the user wants it anyway. These are the best modes to use and every plug-in architecture for applets needs to at least support background loading. Lazy loading has the added benefit that if the plug-in isn’t required it is never loaded, but it’s cached locally anyway so it’s ready if the user uses it in the future. In EditLive! only lazy loading plug-ins will pop up a progress dialog box when the user has to wait for them to download because currently they’re the only plug-ins that we know when they are needed. Over time we’ll hopefully add more triggers to the plug-in declaration to allow us to detect more situations when the user really should be waiting for a plug-in to load.
You also want to avoid having to wait to download the plug-in description. Either provide all the information when registering the plug-in or provide a way to specify the plug-in declaration as inline text on the page that loads the applet. Even if the descriptor file is tiny, the overhead of creating a HTTP connection causes quite a noticeable delay and you need to get that declaration before the applet can start up so that you can identify at which point the plug-in is needed.
Summary
The key points I’ve taken away from developing plug-ins would be:
- Delegate security matters whenever possible. It reduces the chances that you’ll introduce a vulnerability and means the user sees a consistent UI for security warnings and dialogs.
- Cache everything. We need to look into ways to avoid needing to check that we have the latest version of plug-in resources just to avoid the HTTP overhead.
- Defer loading whenever possible. Provide ways for plug-ins to specify when they are required and delay loading them until they are really needed so that your start up time doesn’t suffer.
- Eat your own dog food. We found a lot of improvements because we use a number of plug-ins in a range of internal systems – theorizing about this stuff tends not to work, real experience is king. I’m looking forward to hearing the feedback from our clients about how we could make it better for them.