db-derby-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Luigi Lauro <luigi.la...@gmail.com>
Subject JNLPStorageFactory: work started. Some 'half-baked ideas', come on in, don't be shy.
Date Wed, 21 Mar 2007 08:56:19 GMT
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  

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
View raw message