As I previously announced, I've started working on this RFE ( https:// issues.apache.org/jira/browse/DERBY-2469 ), implementing a WritableStorageFactory (along with StorageFile of course) around the Java Web Start JNLP PersistenceService API.

Some info about PersistenceService, so that we all know what we are talking about.


*** What are we talking about ?

"PersistenceService provides methods for storing data locally on the client system, even for applications that are running in the untrusted execution environment. The service is somewhat similar to that which the cookie mechanism provides to HTML-based applications." (javadoc here: http://java.sun.com/javase/6/docs/jre/ api/javaws/jnlp/javax/jnlp/PersistenceService.html )

To give more details, this interface allows you to create storage entities associated with an URL, and with a given maximum storage size (which can be expanded later at request, and if the request exceeds the default maximum size, it will ask for the user authorization with a warning popup). You can create them (create), retrieve them (get), delete them (delete), and ask for 'children' (getNames - children are other storage entities with URL hierarchically contained under that storage node you are asking to) and tag them (getTag/setTag - tags are user-managed CACHED, DIRTY, TEMPORARY int tags). (javadoc here: http://java.sun.com/javase/6/docs/ jre/api/javaws/jnlp/javax/jnlp/PersistenceService.html ).

When you retrieve a storage entity you are given a FileContents (a JNLP interface itself) which contains several methods for getting info (getName, canRead, canWrite, getLength), obtaining Input/Output streams to the file (getOutputStream, getInputStream), handling maximum size (getMaxLength, setMaxLength) and for obtaining a JNLPRandomAccessFile (getRandomAccessFile) which is a JNLP interface that extends java.io.DataInput and java.io.DataOutput (which is good).

In short, it seems we have all the tools for implementing a full derby StorageFactory/StorageFile around this API, with some work to properly 'map' things around.


*** Why?

As I previously said, since Derby is now bundled with the Java6 JDK as JavaDB, I think this integration would go a long way towards making derby more developer-friendly in Java Web Start environments, where using the sandbox tools Sun provides us it the right way to go, instead of working around it and force the user to give the app the authorization to write on the hard drive IMHO.

Moreover, PersistenceService is more user-friendly, since it doesn't fill the user hard-drive with unneeded directories/files for derby operations (all the persistence storage entitites are managed by Java and hidden to the user), and doesn't force the user to give full read/ write HD-wide security permissions (which can be dangerous in case of malicious intents / bugs).


*** What do we need to do then?

From what I've understood reading Derby documentation and javadocs (correct me here if I'm wrong pls!), I need to implement a PersistenceService-backed WritableStorageFactory, which will provide methods for initialization/shutdown, creating temporary and persistent 'files', and managing directory/files.

Along with it, I also need to implement a StorageFile (which is modeled somewhat after java.io.File but also contains some Derby specific methods) to provide methods for manipulating the file itself or files 'belows' it hierarchically (i.e. deleteAll, mkdir, etc...). Last but not least, if I want to support random access (which I want for performance reason), I also have to provide an implementation for StorageRandomAccessFile, which extends java DataInput/DataOutput interfaces and throws in some added seek/sync/whatever method as well.


*** How to do this then?

I think the best way would be to provide a JNLPStorageFactory implementing WritableStorageFactory, JNLPStorageFile implementing StorageFile, and JNLPStorageRandomAccessFile implementing StorageRandomAccessFile. No other classes needed.

I'm think I'll put most of the functionalities inside JNLPStorageFactory: the factory will hold the reference to PersistenceService and implements most of the methods for manipulating/enquire storage entities.

JNLPStorageFile/JNLPStorageRandomAccessFile will simply contains their own URL and a reference to the JNLPStorageFactory: they will simply act as adapters, implementing the StorageFile interfaces around FileContents/JNLPRandomAccessFile interfaces, and delegating to JNLPStorageFactory for other manipulating methods where the JNLP *file interfaces alone are not enough (isDirectory, mkdir, delete, rename, etc...). JNLPStorageFactory will therefore provide all sorts of methods for giving JNLPXXXXXFiles what they need to fully implement their interfaces (makeDirectory, isDirectory, rename, delete, deleteAll, etc...).

This will also allow me to have a singleton (JNLPStorageFactory) managing all the PersistenceService calls, and given that we don't have any guarantees regarding PersistenceService implementation thread-safety (neither javadoc or the official sun documentation mention thread-safety as a requirement, nor they provide details regarding the actual implementation), it's best if we have a single point where to put synchronization code in case it's needed (btw, this should be investigated at some point in the future, maybe by looking at the implementation downloading the JVM sources).

WritableStorageFactory seems quite easy to implement. I think I don't need any 'abstract' base class here, things are quite straightforward. The only 'critical' point is that the URL-based hierarchy given by PersistenceService does not map 1-to-1 with the file-based hierarchy derby expect. For example: I will need to create empty 'place-holder' jnlp storage entities to represent created directories (otherwise I have no mean to find out if a directory exists or not, if it doesn't contain any file).

Also, I will need to be able to tell if a given storage entity is a directory, a file, or a temporary file.

Temporary file: AFAIK in derby all temp files goes under the temp directory, so I think I could recognize them by the path, but given I have a "persistenceService.setTag(url, PersistenceService.TEMPORARY)", I think this is a faster and better way to mark temporary files.

Directory: this is doubtful. I could use the other 2 tags (CACHED, DIRTY) to mark directories/files, but this is abuse of the tags intents. Or I could use a given length (0/1 byte) to recognize the place-holder storage entities representing directories. I think this is a better approach, but relies on the PersistenceService allow me to create 0/1-length files, which I really don't know if it's possible, it could have a minimum length allowed along with a maximum length. (this needs to be checked as well)

With JNLPStorageFactory done, the other 2 classes should be easier to implement. JNLPStorageFile can be done as an adapter around FileContents/JNLPStorageFactory, and JNLPStorageRandomAccessFile around JNLPRandomAccessFile/JNLPStorageFactory. But maybe here an abstract base class using the input/output stream can be useful for some of the methods, to make things easier at least at start (I can always re-implement things later better, over-riding where needed or getting rid of the base class alltogether).

I've noticed there is an abstract InputStreamFile class which implements read-only methods around an inputstream, is this useful for me you think? I notice it also depends on the BaseStorageFactory class as well: do you think it's better if I start off from these 2 base classes, given my needs?

Also: is there a derby test-suite available for full WritableStorageFactory/StorageFile/StorageRandomAccessFile coverage tests?

Also #2: someone knows if there's a way for testing JNLP APIs outside of a Java Web Start environment? Unluckily those service managers (PersistenceServiceImpl included) get loaded only when the app is run by java web start runtime, which makes testing very very very very very very very uncomfortable.


*** What have I done?

Very little, just this long brainstorming regarding how things are and how to proceed, and a starting JNLPStorageFactory with some methods implemented in as a start and to make me understand what needs to be done.


*** How can you help?

Read all this (woohoo! This is a feat!), and answer here with your thoughts/suggestions/critics/ideas/jokes/whatever. Also, provides code if you feel like it, or get in touch with me (mail) if you wanna get actively involved in the coding I'm done.


Thanks in advance,
Luigi Lauro

Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to