Available FileForker Implementations

Last revised: 14May2003 GLG

This document describes all the concrete FileForker implementations provided in the MacBinary Toolkit 2 for Java. All necessary JARs and JNI-libraries are provided in ready-to-use form. You need not compile anything in order to use any of these concrete FileForker imps on any supported platform.

The source for all imps is provided, though some imps may not be recompileable on some platforms unless you obtain additional classes to compile against. The C source for the JNI-based imps may be somewhat difficult to recompile on Mac OS X unless you create a ProjectBuilder project for it. Details of recompilation are described in Rebuilding the Toolkit.

Table of Contents

Introduction

If you haven't already read the overview, you should.

Compatibility

Before January 2003, no FileForker imp resolved alias-files on-the-fly. That is, no FileForker would automatically resolve alias-files that appeared as non-leaf directory-names leading up to some leaf element. The Mac OS X version would automatically resolve non-leaf symlinks on-the-fly, but Finder-style alias-files would not, and were definitely second-class citizens.

In hindsight, this was stupid. At the very least, a FileForker imp should have been free to choose whether it would resolve non-leaf aliases on-the-fly or not. And that's exactly what I've now decided is the best approach:

Any FileForker implementation may resolve non-leaf aliases of any kind on-the-fly, so that aliases can appear as leading directories in Pathnames.
Unfortunately, this is a new behavior, so none of the historical FileForker imps do so. Fortunately, a new alias-resolving imp is provided for every historical imp that didn't. Unfortunately, this means that the historical imps wired into MacPlatform are still non-resolving. Fortunately, this isn't a serious problem, because you can override what MacPlatform does (refer to its API docs), or use your own approach for designating a FileForker imp.

New FileForker imps can either resolve-on-the-fly or not, and must always clearly state how they behave with non-leaf aliases in pathnames. For example, consider the new JNI-based FileForker imp for Mac OS X: MacOSXForker. Because on-the-fly resolving is generally more useful, I decided that this implementation would always resolve-on-the-fly. That means there isn't a non-resolving JNI-based FileForker, so if you need that behavior for some reason, you'll have to write it yourself.

On-the-fly alias-resolving never affects leaf aliases. Those are always identifiable as aliases, and must be explicitly resolved if that's what you want to happen. Otherwise, the leaf-alias itself is the item acted upon. Nor does resolve-on-the-fly affect the Pathname used by a FileForker. A FileForker's Pathname stays the same until you change it, or the FileForker is selfResolve()'ed.

Resolve-on-the-fly basically means that Finder-style alias-files are on roughly the same footing as Unix symlinks, and that's pretty much all it means. It's so simple, so powerful, and so obvious. That's why the initial design choice was so stupid.

Generic Implementations

These generic implementations are platform-neutral plain Java, and use java.io.File to refer to the file-system. They work on Mac OS, too, though there is a platform-aware selection of a default PathnameFormat, and their behavior is limited to whatever can be expressed with a java.io.File object.

Typically, a java.io.File won't distinguish symlinks from original referents, so these classes effectively behave as resolve-on-the-fly imps. But only if that's how File behaves. If File doesn't resolve shortcuts or aliases, then these imps are NOT resolve-on-the-fly imps. Since File's behavior regarding shortcuts, symlinks, aliases, etc. is platform-dependent and largely undiscoverable, that's how these generic imps are constrained to act.

A java.io.File typically won't identify or distinguish leaf-aliases, either. For example, you can't distinguish a symlink to a directory from the original referent directory. Both kinds of File instances will return T from isDirectory(). Or maybe not, depending on platform.

All this indeterminacy may confuse some applications that use FileForker. This can't be helped, since it's all determined by how java.io.File behaves (or misbehaves).

Usage Considerations

These imps are present in the "All-MB.jar" file. You don't need to add anything to use most of them.

The glguerin.io.imp.gen.PlainForker imp is the implementation of last resort built into glguerin.util.MacPlatform. If the methods selectFactoryName() or selectFactoryBinding() find no other suitable FileForker imp, then the PlainForker will be returned.

The glguerin.io.imp.gen.GenericForker imp needs "MRJToolkitStubs.jar" when it is run on non-Mac platforms. If those classes aren't present in your program's jar-file, or are not found in its classpath, then GenericForker will not work.

Classical Mac OS Implementations

These implementations are for various versions of Java and Mac OS prior to Mac OS X.

There are resolving and non-resolving versions of each imp. The non-resolving versions are the ones MacPlatform knows about. Since classical Mac OS didn't have much of a command-line, the non-resolving versions usually work fine. Only if you allow users to type pathnames, which may contain alias-files, would you absolutely need a resolve-on-the-fly imp. For flexibility, you might want to use a resolve-on-the-fly imp, simply so you don't have to worry about it.

Usage Considerations

These imps are all present in the "All-MB.jar" file. You don't need to add anything to use them. Your program must be running on classical Mac OS for any of them to work.

The non-resolving imps are assigned as the default imps built into glguerin.util.MacPlatform. One of these imps may be returned if the methods selectFactoryName() or selectFactoryBinding() decide they are a suitable FileForker imp for the current host platform.

The imps are arranged so that NineForker is used, if possible, followed in turn by an attempt to use JD2Forker and then JD1Forker.

If you want to automatically use the resolving imps, you will have to clear and then refill the Implicator.Chain returned by MacPlatform.getFactoryImplicators(). You can make the necessary Implicator instances using the MacPlatform.Imp nested class. Refer to the MacPlatform API docs, and the source, for more information.

Mac OS X Implementations

These implementations are for Mac OS X. All imps always resolve symlinks on-the-fly. Only some imps resolve Finder-aliases on-the-fly.

There are resolving and non-resolving versions of the default TenForker imp. MacPlatform only knows the non-resolving version.

The JDirect-based imps need no external native-code library. They are self-contained in the class-files or JAR alone. The JNI-based imps have their native methods implemented in a separate JNI library file. You must place this file in the same place as the JAR, or the Java classes won't work.

There isn't really a significant speed difference between the JDirect and JNI imps. Speed is dominated by I/O time, so any difference between JDirect and JNI overhead is insignificant. The JNI imps have noticeably shorter app-startup times, but only because JDirect adds to an app's startup time. This is a characteristic of JDirect, not of the FileForker imp itself.

The JDirect-based imps will not work in Cocoa-Java apps. JDirect technology is hostile to Cocoa event-loops and a fatal deadlock or wedge ensues. The JNI-based imps work in Cocoa-Java apps, and have been tested there. They should also work in background-only (faceless daemon) processes, which is another area that JDirect has problems with.

The JNI-based imps are the most capable and full-featured Mac OS X imps. I chose JNI for these imps because that's the most widely usable approach (see above), and because it's the future of Java on Mac OS X. As of this date, Apple has eliminated JDirect from Java 1.4.1 on Mac OS X. As a result, JNI is the only available technology for native-code implementations moving forward.

Usage Considerations for JDirect Imps

The JDirect-based imps in the glguerin.io.imp.mac.ten package are present in the "All-MB.jar" file. Your program must be running on Mac OS X and Java 1.3.* for them to work. You don't need to add anything to use them.

The glguerin.io.imp.mac.ten.TenForker imp is assigned as one of two possible default imps for Mac OS X built into glguerin.util.MacPlatform. The TenForker imp is returned as the default on Mac OS X 10.0, and on other versions of Mac OS X when MacOSXForker is unavailable. One of these imps may be returned if the methods selectFactoryName() or selectFactoryBinding() decide they are a suitable FileForker imp for the current host platform.

There are additional considerations for using the TenForker imp in a signed applet.

Usage Considerations for JNI Imps

The JNI-based imps in the glguerin.io.imp.mac.macosx package are located in the "MacOSXForker.jar" file, and supplemented by the "libMacOSXForkerIO.jnilib" file. Your program must be running on Mac OS X 10.1+ under Java 1.3.* or 1.4.* for them to work. YOU MUST TAKE EXTRA STEPS TO USE THESE IMPS.

The glguerin.io.imp.mac.macosx.MacOSXForker imp is assigned as one of two possible default imps for Mac OS X built into glguerin.util.MacPlatform. The MacOSXForker imp is preferred over TenForker on 10.1 and higher, even though MacOSXForker is not supplied in "All-MB.jar". This was done because MacOSXForker generally has more features and fewer limitations than TenForker, so if MacOSXForker is available, it should generally be used.

However, MacOSXForker IS NOT the default on 10.0, even if it is available. Since MacOSXForker doesn't run on 10.0, the 10.0 platform is listed as a special case in MacPlatform's Implicator chain.

The MacOSXForker classes are provided in a separate jar-file. If you don't deploy this jar-file properly, the MacOSXForker classes won't work. You can merge this jar with other jar-files in your program, or leave it separate. If you leave it separate, you must include it in the program's classpath. If you don't do this, the MacOSXForker classes won't be found, even though the class-name is known to MacPlatform.

The MacOSXForker classes rely on a JNI-library file: "libMacOSXForkerIO.jnilib". This file contains the native code for the MacOSXForker classes. In general, this file should be placed in the same location as the jar that contains the MacOSXForker classes. Do not rename "libMacOSXForkerIO.jnilib". That's the name the MacOSXForker class knows the library as, and if you change it, then it won't be found.

If your program is a double-clickable jar, simply place "libMacOSXForkerIO.jnilib" in the same location as the double-clickable jar-file. It should then be found, because the default library-path contains ".".

Bundled double-clickable apps should place "libMacOSXForkerIO.jnilib" in the Contents/Resources/Java sub-directory within the app-bundle. That is, in the same place as the jar-file containing the MacOSXForker classes. This should work for Cocoa-Java apps, as well as "pure" Java apps.

JNLP (Java Web Start) applications should deploy the MacOSXForker classes in a jar, and the JNI-lib file using the normal JNLP native-library deployment mechanisms.

You can merge the MacOSXForker classes, or even all the MacBinary Toolkit classes, into a single jar-file for your app, if you wish. You can also maintain them as separate files, if you wish, with an appropriate classpath.

Applet Usage Considerations

All FileForker imps have security implications for applets because they all refer to the fileystem. Even all-Java implementations like PlainForker need the appropriate security permission when run from an applet. Using a FileForker implementation in an applet also poses challenges for other reasons.

First is the applet security and signing model. Only signed applets can escape the sandbox, and the signing and privilege model itself has evolved over the various Java releases. Exactly how to sign and privilege, and what to sign with, depends on the target platform. Even signed applets, though, cannot do certain things, such as supplying a native-code library which is subsequently loaded.

Second is the applet ClassLoader model, which is related to the security model. The security model is abstract, and is implemented by a ClassLoader in conjunction with the hosting application's SecurityManager and other classes. Since ClassLoader is an actual class, albeit an abstract one, it has specific relationships (e.g. inheritance) with other actual Java classes which the JVM enforces.

Third is the targeted host's deployment environment. An applet need not contain the MacBinary Toolkit classes if it can instead rely on the client machine already having them installed as a class library or Java extension. This might be done by a previously downloaded and executed installer application, specifically to "lay the foundation" for one or more applets that will be deployed more dynamically. An unsigned applet would still be unable to access the MacBinary Toolkit class library, but a signed applet with appropriate privileges should be able to use the installed classes. In short, the overall deployment model and the relationship between applets and class-libraries will affect MacBinary Toolkit usability on a given host platform.

The JDirect-based FileForker imps have the additional complication of referring to native code using Apple-specific JDirect technology. Depending on the applet's hosting application, it may or may not "play nicely" with JDirect. Common browsers, for example, may differ from all-Java hosting apps.

The JNI-based imps refer to native code contained in JNI-library files, which cannot usually be supplied by applets because it would violate the security model, which forbids untrusted and unverifiable native code supplied from remote origins.


To Greg's Home Page
To Greg's Software Page