Hansa Mount Protocol
The mount point is the ability to take a Resource and place it into the URL space shared with other resources. If any merging will be provided or not is still a topic of discussion.
The mount: protocol is really interesting. Let's look at it from an example point of view first; (Sorry for the ASCII art. Someone care to make it proper??)
+-------------+ creates URL +---------------------------------------+
| Client Code |--------------->| mount://some.point/abc/def/README.txt |
+-------------+ +---------------------------------------+
\________/
^
|
|
| provides/serves
|
|
+------------+ mounts +---------+
| ZIP Driver |--------->| abc.zip |
+------------+ +---------+
|
|
| contains
|
|
v
+---------------------+
| /abc/def/README.txt |
+---------------------+
In the above diagram, we see the ZIP Driver mounting the abc.zip file at the some.point _in the mount:_URL space. And the /abc/def/README.txt file is inside the abc.zip file. Now, from the client code point of view, we simply create a URL and open the stream to it. Like this;
// Create the URL. URL url = new URL( "mount://some.point/abc/def/README.txt" ); // Open the Stream. InputStream in = url.openStream();And the we can read out the stream from the README.txt file.
So far, so good.
The mount:// protocol has a Driver for each mount point. We will develop drivers for different needs, and different functionality.
- FileDriver for standard file system access.
- HttpDriver (perhaps combined with FTP) for ordinary HTTP access.
- ZipDriver to mount Zip and Jar files.
I am sure others will follow shortly. Each Driver can mount many URLs at the same mount point. That will lead to the directory trees of all the URLs of a mount point is merged, very much like the getResourceAsStream() method in ClassLoader.
Files can be read through the openStream() method, which is a convenience method for openConnection().getInputStream(), and files can be written in the same manner by openConnection().getOutputStream(). If you open a directory, a set of meta information will be return, so that the content of the directory can be browsed (if permitted and possible).
Directories are considered virtual. That means that all directories are non-existent if they don't contain any content, they don't need to be created nor deleted. When the last file in structure is gone, all parent directories unique to that file will also be gone, virtually that is.
Let's look at a more complex example.
mount point |
URL(s) |
Description |
|---|---|---|
//appspace |
myapp.jar |
Mounting a Jar file at appspace mount point. This Jar contain org.mine.Main |
//appspace |
mount://ext.deps |
mounting another mount: URL at appspace, containing the external dependencies |
//appspace |
mount://l10n.i18n |
mounting the localization and internationalization resources at appspace |
//ext.deps |
mounting an http resource as a dependency. |
|
//ext.deps |
artifact:jar:log4j/log4j#1.2.8 |
Mounting a Log4J artifact URL to the ext.deps mount point |
//ext.deps |
link:latest-servlet-api |
mounting a link: URL to ext.deps mount point. This link may point to any artifact, but in this example, it is expected to be a artifact:jar:servletapi/servletapi#2.4 or so. |
//l10n.i18n |
artifact:zip:myapp/resources/english#1.0.1 |
mount the english resources to the l10n.i18n mount point. |
//l10n.i18n |
artifact:zip:myapp/resources/german#1.0.4 |
mount the german resources to the l10n.i18n mount point. |
//l10n.i18n |
artifact:zip:myapp/resources/spanish#1.0.0 |
mount the spanish resources to the l10n.i18n mount point. |
//l10n.i18n |
artifact:zip:myapp/resources/chinese#1.0.8 |
mount the chinese resources to the l10n.i18n mount point. |
So what happens if I start the application with the following commandline;
java -cp hansa-boot.jar:mount\://appspace/l10n.i18n:mount\://appspace/ext.deps -Djava.protocol.handler.pkgs=org.ops4j.hansa org.mine.Main
Amazingly, it will work. The classes and the i18n resource will be available, including the external dependencies.
The aggregated tree of resources would look something like this;
classpath -> /appspace
/l10n.i18n
/Resources_es.properties
/Resources_de_properties
/Resources_en.properties
/Resources_zh.properties
/ext.deps
/org/apache/log4j
/org.hedhman.hyper
For instance, application would do the following for ResourceBundles;
Locale locale = Locale.CHINESE;
ResourceBundle rb = ResourceBundle.getBundle( "/l10n.i18n/Resources", locale );
since the l10n.i18n sits in the classpath.