Overview of MacBinary Toolkit 2 for Java

Last revised: 11May2003 GLG

This document is an overview of the classes in the MacBinary Toolkit 2 for Java. For a complete discussion of the classes and API, see the API-docs themselves. This document presents the "big picture", pointing out principal classes, features, and relationships. Related documents cover other areas, such as details of implementations, rebuilding, or subsetting.

Table of Contents

Introduction

The MacBinary Toolkit for Java classes can be seen as four layers of behavior and abstraction:
    1) demo applications and tests,
    2) MacBinary encode/decode,
    3) file-system I/O, and
    4) I/O implementations.

In fact, only the latter three layers make up the real toolkit classes. The top-most application layer is a collection of illustrative applications (e.g. "MacBinary Converter" and "MacBinary Spy"), command-line utilities, and the tests written during development. When you use the toolkit for your own applications, you will often use only layers 2-4, though the classes in layer 1 may be extracted or followed as examples.

At the deepest level 4, beneath the file-system I/O abstractions, are platform-specific implementations -- all other classes in all other layers are platform-neutral, though sometimes platform-sensing, as in MacPlatform or PathnameFormat. You select a particular implementation to use, then tell one class, FileForker, what that class or class-name is. Everything thereafter will then use the implementation you have set. This is all explained below, and in even more detail in the API docs, with examples in the source.

Compatibility

Backward Compatibility

The current major release is very nearly binary compatible with the previous major release. One change to a method-name may affect binary compatibility: the assert() method in the FileAccess class was renamed to affirm(). This was done to be friendly to the Java assertion facility in JDK 1.4. If your code used FileAccess.assert(), you'll have to recompile in order to use this release. If you don't use FileAccess.assert(), then this release should be a drop-in replacement of JARs for the prior major release's JARs, and no recompile necessary.

If you are using an even earlier major release, then there are more extensive changes. Refer to the Release Notes and Revision History.

Other than the change to FileAccess.assert(), all new major features, fixes, improvements, and implementations should be binary compatible with any of your classes compiled against the previous major release. All new major features have default implementations. All fixes were made as compatible as possible, without attempting bug-for-bug compatibility. All improvements and implementation changes were done "behind the curtain" of the public API.

For more details on the changes, see the Release Notes and Revision History.

Java Compatibility

This toolkit requires a Java implementation compliant with JDK-1.1 or later. Some facilities may dynamically adjust to JDK-specific facilities, such as implementations of setLength() or isHidden() that use reflection on JDK 1.2 or higher.

Certain concrete implementations may require later than JDK 1.1, or require a specific platform in order to run. Recompilation requires compiling against certain classes or JARs. Some platforms may not have these classes available, so you may not be able to recompile every available implementation on every possible Java platform. See Rebuilding the MacBinary Toolkit 2 for Java for more information.

The supplied JARs have been compiled under JDK 1.1, so they will run as-is on JVMs implementing JDK 1.1 through JDK 1.4.1 (possibly higher, though I have not tested this). If you recompile the source with a later JDK, the compiled classes may not be runnable on a JDK earlier than the one you compiled for. That is the fault of the target compilation, not the MacBinary Toolkit. Refer to the "Target Compiling" section of the 'javac' manual.

This toolkit uses no methods or classes deprecated as of JDK 1.1. Use of AWT is isolated to classes in one package-tree, to simplify its use in environments where a particular graphical toolkit, e.g. AWT, Swing, etc., cannot be assumed.

Platform Compatibility

Specific implementations of the I/O classes have additional requirements noted elsewhere for each implementation.

When moving to a new platform, developers targeting non-Mac platforms will want to pay special attention to the PathnameFormat class and its platform-specific subclasses. This is where quirks of File-based pathnames are resolved into the universal "literalized" form held in Pathnames. Windows programmers should know that the form of Windows pathnames known as UNC is not supported. You will have to subclass PathnameFormat if you need to support UNC.

You may have difficulty compiling certain platform-specific implementations on host platforms other than the intended target platform. If you aren't using an implementation, then don't recompile it. Read the information on rebuilding before undertaking a complete recompile.

On Mac OS, this toolkit has been tested under MRJ 2.0, 2.1.*, and 2.2.*. It has been tested on a range of Mac OS versions, including 7.6.1, 8.6, 9.0, 9.2, and Mac OS X version 10.0 thru 10.2.3. It has been tested on PowerPC (603e, 604e, and G4) machines, as well as on a 68040-based machine under MRJ 2.0.

Commands, Demo Applications, and Tests

This layer is partly utilitarian and partly illustrative. The supplied applications do useful things, but they also illustrate how to use the MacBinary and I/O classes in various ways. There are both GUI and command-line applications. The commands may be able to do things the GUI can't, simply because GUIs may automatically resolve aliases rather than passing them back unresolved.

This package contains command-line interfaces to the MacBinary Toolkit's capabilities. The commands are fairly simple, but can be elaborated upon or modified. All the commands are platform-neutral, but default to the platform-sensitive FileForker implementation choice if no property is defined.

About describes the FileInfo and FileAccess of pathname args in a simple easy-to-read text form, along with the resolved pathname of each target. You can set the FileForker imp with a property.

Encode encodes files named as args to MacBinary form, writing the output files under unique names (NamingStrategyUnique). It can optionally resolve aliases. You can set the FileForker imp with a property.

Decode decodes files named as args from MacBinary form, writing the output files under unique names (NamingStrategyUnique). It can optionally resolve aliases. You can set the accepted MacBinary level and FileForker imp with properties.

Resolve resolves aliases given as command-line args, emitting their fully resolved pathname on stdout. You can set the FileForker imp with a property.

Spy dumps information about MacBinary-encoded files on stdout, in a form based on that of the About command, but with additional header-describing information. The Spy command doesn't use or need a FileForker imp.

The class ConverterFrame contains the main() method. It's mainly an AWT interface to an MBFileEncoder and an MBFileDecoder. Its doc-comments are extracted in the API docs, but it also has many internal comments. The source itself is more useful and illustrative than anything one might find in its doc-comments.

On Mac OS, the program runs as a droplet, so you can just drag-n-drop any file-icon onto the program's Finder-icon to encode or decode it. This feature doesn't work on Mac OS X yet.

The class SpyFrame is an AWT-based platform-neutral utility that examines files and displays some of the MacBinary-header information it finds. It can open any file on any platform, and automatically detects whether it is MacBinary or not before extracting information for display. This is useful in tracking down MacBinary file-format problems, or for testing your uses of the MacBinary Toolkit.

On Mac OS, the program runs as a droplet, so you can just drag-n-drop any file-icon onto the program's Finder-icon to display its MacBinary info. This feature doesn't work on Mac OS X yet.

The class PathToyFrame is an AWT-based platform-neutral utility that's useful for testing different implementations of PathnameFormat, and how a FileForker interacts with a Pathname in a concrete implementation. It was instrumental in creating and testing the TenForker implementation, especially when comparing its behavior to the GenericForker.

The two classes in this package define a test-app that illustrates how to use the method FileHelper.duplicate().

The class app.macbinary.test.Tests is a console-only invoker of test-classes. The tests themselves are all in 'app.macbinary.test'. Because these were developed incrementally as unit and integration tests, the main Tests class just contains commented-out lines where I wanted to skip a test. This is not a comprehensive test regimen by any means. It is included mainly so you can look at the tests and see how things might be done, and to possibly help you in debugging your own implementations.

None of the test-data files are included in the distribution, so most tests will fail unless you change or create the names of files and directories referred to. Some tests are also Mac-only, such as TestMacTime and its cohort MacOSTime, the latter which calls a native MacOS function via JDirect.

Layer 2: MacBinary Encoder/Decoder Classes

The classes of this layer perform all MacBinary encoding and decoding. All classes in this package are platform-neutral Java. They don't care what the origin or destination of any "resource-fork" or "file-info" data is, as long as it's accessible.

These classes use the Builder design pattern. The actions of the specific data-handler (the builder) are directed by the principal class (the director) at the appropriate times and in the ways that MacBinary requires. You can provide your own data-handlers while keeping the principal class the same. This separates the specifics of handling the raw bytes from the process of converting to and from well-formed MacBinary.

There are two levels of MacBinary classes here. The simple high-level classes cover the most common uses of MacBinary and can be used in most applications. The medium-level classes are more flexible, but also more complex to prepare and use. The high-level classes are built on the medium-level classes, so also serve as examples of how to use the medium-level classes.

The high-level classes are MBFileEncoder and MBFileDecoder. The both operate on files in the file-system, both for their inputs and their outputs. If you want to encode or decode on-the-fly, say using network data, then you should use the mid-level classes directly.

The medium-level classes are MacBinaryEncoder for encoding, and MacBinaryOutputStream or MacBinaryReceiver for decoding. These are in turn built using other classes in the package, but you can mostly ignore them. One pivotal class you shouldn't ignore is MacBinaryHeader, which you should understand in order to understand the encoded form.

A MacBinaryEncoder ultimately makes and returns an InputStream representing the encoded byte-stream. You can do what you want with this, since it's just an InputStream.

A MacBinaryOutputStream is the converse of the InputStream returned by MacBinaryEncoder. That is, you write encoded bytes onto it, and it decodes the file represented, in the place you tell it. If you only want to deal with Java's I/O streams, a MacBinaryOutputStream is the way to go. If you want more flexibility, though, you should use a MacBinaryReceiver to do the decoding. Look at the source of MacBinaryOutputStream to see how it works and how it relates to MacBinaryReceiver.

Layer 3: File-System I/O

This layer abstracts file-system I/O capabilities. It provides representations for many things that java.io.File does not. Many facilities are universally implemented, such as access to streams, random-R/W storage, and directory contents name-lists. Some facilities are only provided by a few concrete implementations, such as the nested Alias class or change-signals. Details of the provided concrete imps are described in Available FileForker Implementations. Also see the API docs for each specific implementation.

These classes represent file-system objects used at both higher and lower levels. The MacBinary classes perform most I/O with classes defined at this level. All the classes in this package are platform-neutral Java. Abstract classes will have platform-specific implementations in other packages.

Filenames are represented and manipulated using a Pathname in conjunction with a PathnameFormat. Specific subclasses of PathnameFormat handle all the specific details of a particular platform, so Pathname remains free from any platform-specific information or behavior. Pathnames provide the separation between name manipulation and file-system manipulation, which java.io.File does not.

Objects on the file-system are represented by FileForker, or more precisely, by its concrete implementations. A FileForker uses a Pathname to represent the name of the file it's working on. There is a static Abstract Factory Method in FileForker that you typically use to instantiate concrete FileForker instances. Each FileForker instance is also an Abstract Factory with Factory Methods that create new instances of interesting file-system objects: input and output streams, random-access R/W storage, fully alias-resolved Pathnames, etc. A FileForker also provides access-privilege manipulation, file-info manipulation, and other capabilities of a file-system object.

The FileForker class defines two abstract nested classes: Alias and Watcher. The implementation of these is optional. They represent a reference to another file and a way to receive change-signals, respectively. The Alias class is notable because it is how symlinks and alias-files are created, when that facility is provided.

FileInfo is an interface for working with the meta-data of a file. It includes both platform-neutral elements (length, directory-ness, etc.) and Mac-specific elements (file-creator, file-type, Finder flags, etc.) Other classes implement FileInfo, including MacBinaryHeader in glguerin.macbinary. There is also a basic implementation in this package -- BasicFileInfo.

FileAccess is a class representing access privileges and ownership of a file or directory. It encapsulates Unix-style access privileges, but allows different implementations to interpret the privileges and ownership identities in ways appropriate for the platform or implementation.

RandomRW and its subclasses represent random-access read-write data containers. These classes are similar to java.io.RandomAccessFile but are more flexible because they can refer to data-containers other than Files (e.g. byte-arrays). Most methods that encode or decode MacBinary will use or return a RandomRW instance. The FileForker implementation classes use and return these abstractions, too.

Some other useful classes provided here are:

Layer 4: I/O Implementations

This layer provides concrete implementations of the layer above. These implementations are the only platform-specific classes of the entire MacBinary Toolkit. This section only highlights some of the provided imps. Details of all the provided concrete imps are described in Available FileForker Implementations.

The PlainForker class is a plain-Java implementation that always acts as if resource-forks don't exist. It works on any platform, but doesn't provide resource-forks anywhere. Its FileInfo and FileAccess capabilities are limited to what a java.io.File can accomplish.

All non-Mac platforms default to using the PlainForker implementation.

This is a sub-tree containing several Mac-specific implementations based on a common set of base classes. Classical Mac OS and Mac OS X are supported. All these implementations are known to MacPlatform by default, and one is automatically selected based on which platform is detected.

The built-in default Mac OS implementations are:

Utility Classes

A number of utility classes live here, serving as underpinnings for classes in several other packages. All are platform-neutral Java, though some are platform-sensing, such as MacPlatform. They provide such things as:

A number of application-support utility classes live here. Among other things, they provide:

Some additional RandomRW subclasses live here. These are not used by anything else in the MacBinary Toolkit (other than test classes). You may find these useful, especially if you need a buffered RandomRW or access to the DataInput or DataOutput interfaces that RandomAccessFile provides.


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