// DirectoryResource.java
// $Id: DirectoryResource.html,v 1.2 1999/10/27 22:10:34 ylafon Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html
packageorg.w3c.tools.resources ;
importjava.util.*;
importjava.io.*;
importorg.w3c.tools.resources.indexer.*;
importorg.w3c.tools.resources.event.*;
/**
* A simple, and reasonably efficient directory resource.
*/publicclassDirectoryResourceextendsContainerResource {
/**
* Attribute index - The index for our directory attribute.
*/protectedstaticintATTR_DIRECTORY = -1 ;
/**
* Attribute index - The last time we physically visited the directory.
*/protectedstaticintATTR_DIRSTAMP = -1 ;
/**
* Attribute index - The indexer to use for that directory, if any.
*/protectedstaticintATTR_INDEXER = -1;
/**
* Attribute index - The index of wether we are extensible.
*/protectedstaticintATTR_EXTENSIBLE = -1 ;
static {
Attributea = null ;
Classcls = null ;
// Get a pointer to our class.
try {
cls = Class.forName("org.w3c.tools.resources.DirectoryResource") ;
} catch (Exceptionex) {
ex.printStackTrace() ;
System.exit(1) ;
}
// The directory attribute.
a = newFileAttribute("directory"
, null
, Attribute.COMPUTED|Attribute.DONTSAVE);
ATTR_DIRECTORY = AttributeRegistry.registerAttribute(cls, a) ;
// The last time we visited the directory
a = newDateAttribute("dirstamp"
, null
, Attribute.COMPUTED) ;
ATTR_DIRSTAMP = AttributeRegistry.registerAttribute(cls, a) ;
// Our indexer name (optional).
a = newStringAttribute("indexer"
, null
, Attribute.EDITABLE) ;
ATTR_INDEXER = AttributeRegistry.registerAttribute(cls, a) ;
// Are we extensible (can we create resources on the fly):
a = newBooleanAttribute("extensible"
, Boolean.TRUE
, Attribute.EDITABLE) ;
ATTR_EXTENSIBLE = AttributeRegistry.registerAttribute(cls, a) ;
}
/**
* Get the indexer out of the given context.
* @return A ResourceIndexer instance, guaranteeed not to be <strong>
* null</strong>.
*/protectedResourceReferencegetIndexer(ResourceContextc) {
IndexerModulem = (IndexerModule) c.getModule(IndexerModule.NAME);
ResourceReferencerr = m.getIndexer(c);
return rr;
}
publicvoidsetValue(intidx, Objectvalue) {
super.setValue(idx, value);
if ( idx == ATTR_INDEXER ) {
Stringindexer = getString(ATTR_INDEXER, null);
if ( indexer != null ) {
ResourceContextc = null;
IndexerModulem = null;
c = getContext();
m = (IndexerModule) c.getModule(IndexerModule.NAME);
m.registerIndexer(c, indexer);
}
}
}
/**
* Get the physical directory exported by this resource.
* @return A non-null File object giving the directory of this resource.
*/publicFilegetDirectory() {
return (File) getValue(ATTR_DIRECTORY, null) ;
}
/**
* Get the absolute time at which we examined the physicall directory.
* @return The date (as a long number of ms since Java epoch), or
* <strong>-1</strong> if we never examined it before.
*/publiclonggetDirStamp() {
return getLong(ATTR_DIRSTAMP, -1) ;
}
/**
* Get the extensible flag value.
* A DirectoryResource is extensible, if it is allowed to create new
* resources out of the file system knowledge on the fly.
* <p>Setting this flag might slow down the server. It unfortunatelly
* defaults to <strong>true</strong> until I have a decent admin
* program.
* @return A boolean <strong>true</strong> if the directory is
* extensible.
*/publicbooleangetExtensibleFlag() {
return getBoolean(ATTR_EXTENSIBLE, true) ;
}
/**
* A resource is about to be removed
* This handles the <code>RESOURCE_REMOVED</code> kind of events.
* @param evt The event describing the change.
*/publicvoidresourceRemoved(StructureChangedEventevt) {
super.resourceRemoved(evt);
markModified();
}
/**
* Create a DirectoryResource and the physical directory too.
* @param name the name of the resource.
* @return A ResourceReference instance.
*/publicResourceReferencecreateDirectoryResource(Stringname) {
// Create an empty file:
Filefile = newFile(getDirectory(), name) ;
booleancreated = false ;
booleanexists_before = false ;
try {
if (file.exists()) {
if (! file.isDirectory())
created = false;
else
exists_before = true;
} else {
file.mkdir();
created = true;
}
} catch (Exceptionex) {
created = false;
}
if (! created)
returnnull;
ResourceReferencerr = createDefaultResource(name);
if (rr == null) {
if (!exists_before)
file.delete();
returnnull;
}
try {
Resourcer = rr.lock();
if (! (r instanceofDirectoryResource)) {
try {
r.delete();
} catch (MultipleLockExceptionex) {
//OUCH!
//manual delete
}
if (!exists_before)
file.delete();
returnnull;
}
} catch (InvalidResourceExceptionex) {
if (!exists_before)
file.delete();
returnnull;
} finally {
rr.unlock();
}
return rr;
}
/**
* Create a Resource and the physical file too.
* @param name the name of the resource.
* @return A ResourceReference instance.
*/publicResourceReferencecreateResource(Stringname) {
return createResource(name, null);
}
/**
* Create a Resource and the physical file too.
* @param name the name of the resource.
* @param req the protocol request.
* @return A ResourceReference instance.
*/publicResourceReferencecreateResource(Stringname,
RequestInterfacereq)
{
// Create an empty file:
Filefile = newFile(getDirectory(), name) ;
booleancreated = false ;
if ( ! file.exists() ) {
try {
(newRandomAccessFile(file, "rw")).close() ;
created = true ;
} catch (Exceptionex) {
created = false ;
}
}
if (! created)
returnnull;
ResourceReferencerr = createDefaultResource(name, req);
if (rr == null)
file.delete();
return rr;
}
/**
* Index a Resource. Call the indexer.
* @param name The name of the resource to index.
* @param defs The defaults attributes.
* @return A resource instance.
* @see org.w3c.tools.resources.indexer.SampleResourceIndexer
*/privateResourceindex(Stringname, Hashtabledefs) {
return index(name, defs, null);
}
/**
* Index a Resource. Call the indexer.
* @param name The name of the resource to index.
* @param defs The defaults attributes.
* @param req The protocol request.
* @return A resource instance.
* @see org.w3c.tools.resources.indexer.SampleResourceIndexer
*/protectedResourceindex(Stringname,
Hashtabledefs,
RequestInterfacereq)
{
// Prepare a set of default parameters for the resource:
defs.put("identifier", name);
updateDefaultChildAttributes(defs);
ResourceContextcontext = getContext();
// Try to get the indexer to create the resource:
Resourceresource = null;
ResourceReferencerr_indexer = null;
ResourceReferencerr_lastidx = null;
while ( context != null ) {
// Lookup for next indexer in hierarchy:
do {
rr_indexer = getIndexer(context);
context = context.getParent();
} while ((rr_indexer == rr_lastidx) && (context != null));
// Is this a usefull indexer ?
if ((rr_lastidx = rr_indexer) != null ) {
try {
ResourceIndexerindexer =
(ResourceIndexer)rr_indexer.lock();
resource = indexer.createResource(this,
req,
getDirectory(),
name,
defs) ;
if ( resource != null )
break;
} catch (InvalidResourceExceptionex) {
resource = null;
} finally {
rr_indexer.unlock();
}
}
}
return resource;
}
publicsynchronizedResourceReferencecreateDefaultResource(Stringname) {
return createDefaultResource(name, null);
}
/**
* Try creating a default resource having the given name.
* This method will make its best effort to create a default resource
* having this name in the directory. If a file with this name exists,
* it will check the pre-defined admin extensions and look for a match.
* If a directory with this name exists, and admin allows to do so, it
* will create a sub-directory resource.
* @param name The name of the resource to try to create.
* @param req The incomming request
* @return A Resource instance, if possible, <strong>null</strong>
* otherwise.
*/protectedsynchronizedResourceReferencecreateDefaultResource(Stringname,
RequestInterfacereq)
{
// Don't automagically create resources of name '..' or '.'
if (name.equals("..") || name.equals("."))
returnnull ;
Hashtabledefs = newHashtable(10) ;
Resourceresource = index(name, defs, req);
// Did we finally create a resource ?
ResourceReferencerr = null;
if ( resource != null ) {
// Register this child in our store:
rr = addResource(resource, defs) ;
markModified() ;
}
return rr ;
}
/**
* Initialize and register a new resource into this directory.
* @param resource The uninitialized resource to be added.
*/protectedResourceContextupdateDefaultChildAttributes(Hashtableattrs) {
ResourceContextcontext = null;
context = super.updateDefaultChildAttributes(attrs);
Stringname = (String) attrs.get("identifier");
if (( name != null ) && (getDirectory() != null)) {
attrs.put("directory", newFile(getDirectory(), name));
return context;
} else {
returnnull;
}
}
/**
* Reindex recursivly all the resources from this DirectoryResource.
*/publicsynchronizedvoidreindex() {
if (getExtensibleFlag()) {
Enumeratione = enumerateAllResourceIdentifiers();
Stringname = null;
ResourceReferencerr = null;
Resourcer = null;
while (e.hasMoreElements()) {
name = (String) e.nextElement();
rr = lookup(name);
if (rr != null) {
try {
r = rr.lock();
// forbid cycles
if (r == this)
continue;
if (r instanceofDirectoryResource) {
//launch reindex
DirectoryResourcedir = (DirectoryResource) r;
//reindex directory itself
//the new diretory must have the same context
Hashtabledefs = newHashtable(10);
defs.put("context", dir.getContext());
//indexing ...
Resourcenewdir = index(name, defs);
// do we want it to keep its indexer?
if (newdir == null) {
dir.reindex();
} else {
if (! (newdir instanceofDirectoryResource)) {
thrownewRuntimeException(
"Reindex Error : "+
name+" can't be reindexed. "+
"The reindexed resource is "+
"no more a DirectoryResource.");
}
DirectoryResourcereindexed =
(DirectoryResource) newdir;
Stringindexer =
reindexed.getString(ATTR_INDEXER, "");
if (indexer.equals("")) {
dir.reindex();
indexer =
dir.getString(ATTR_INDEXER, null);
reindexed.setValue(ATTR_INDEXER, indexer);
} else {
dir.setValue(ATTR_INDEXER, indexer);
dir.reindex();
}
//move children to the reindexed directory
reindexed.setValue(ATTR_KEY, dir.getKey());
dir.setValue(ATTR_IDENTIFIER,
name+"-bakindex");
addResource(reindexed, defs);
// Now replace the old DirectoryResource
// by the new one
try {
dir.replace(reindexed);
} catch (MultipleLockExceptionex) {
thrownewRuntimeException(
"Reindex Error : "+
ex.getMessage());
}
}
} elseif (! (r instanceofAbstractContainer)) {
//leaf
Hashtableresdefs = newHashtable(10);
Resourceresource = index(name, resdefs);
if (resource != null) {
try {
r.delete();
} catch (MultipleLockExceptionex) {
thrownewRuntimeException(
"Reindex Error : "+
ex.getMessage());
}
addResource(resource, resdefs);
}
}
} catch (InvalidResourceExceptionex) {
System.out.println(ex.getMessage());
} finally {
rr.unlock();
}
}
}
markModified();
}
}
/**
* Enumerate all available children resource identifiers.
* This method <em>requires</em> that we create all our pending resources.
* @return An enumeration of all our resources.
*/protectedsynchronizedEnumerationenumerateAllResourceIdentifiers() {
Filedirectory = getDirectory() ;
if ( directory != null ) {
synchronized(this) {
Stringlst[] = directory.list() ;
if ( lst != null ) {
for (inti = 0 ; i < lst.length ; i++) {
if (lst[i].equals(".") || lst[i].equals(".."))
continue ;
if (lookup(lst[i]) == null)
createDefaultResource(lst[i]) ;
}
}
}
}
returnsuper.enumerateResourceIdentifiers(true);
}
/**
* Enumerate all available children resource identifiers.
* This method <em>requires</em> that we create all our pending resources
* if we are in the extensible mode...too bad !
* @return An enumeration of all our resources.
*/publicsynchronizedEnumerationenumerateResourceIdentifiers(booleanall) {
// If extensible, update if needed:
if (all && getExtensibleFlag() ) {
Filedirectory = getDirectory() ;
if ( directory != null ) {
synchronized(this) {
longdirstamp = directory.lastModified() ;
if ( dirstamp > getDirStamp() ) {
Stringlst[] = directory.list() ;
if ( lst != null ) {
for (inti = 0 ; i < lst.length ; i++) {
if (lst[i].equals(".") || lst[i].equals(".."))
continue ;
if (lookup(lst[i]) == null)
createDefaultResource(lst[i]) ;
}
}
setLong(ATTR_DIRSTAMP, dirstamp) ;
}
}
}
}
returnsuper.enumerateResourceIdentifiers(all);
}
/**
* Lookup the resource having the given name in this directory.
* @param name The name of the resource.
* @return A resource instance, or <strong>null</strong>.
*/publicResourceReferencelookup(Stringname)
{
ResourceReferencerr = null;
// Try our store:
rr = super.lookup(name);
if (rr != null)
return rr;
// If allowed, than try a default fallback:
return getExtensibleFlag() ? createDefaultResource(name) : null ;
}
/**
* Delete this directory resource, for ever.
* This method will delete the directory resource, and its associated
* store, <strong>along</strong> with any of the sub-resources it contains.
* Deleting the root directory of your server might take sometime...
* <p>Once the resource is deleted, it isx1 removed from its inital store
* and will not be unpickleable any more.
*/publicsynchronizedvoiddelete()
throwsMultipleLockException
{
disableEvent();
// Remove all the defined resources in this directory
// Set the extensible flag to false, otherwise, the directory grows
// as we shrink it :-)
setBoolean(ATTR_EXTENSIBLE, false);
super.delete();
}
/**
* Was return false (don't khow why)
*/publicsynchronizedbooleanverify() {
return getDirectory().exists();
}
/**
* Initialize this directory resource with the given set of attributes.
* @param values The attribute values.
*/publicvoidinitialize(Objectvalues[]) {
super.initialize(values) ;
disableEvent();
// Get our parent resource and compute our directory:
Filedir = null ;
if ( ! definesAttribute(ATTR_DIRECTORY) ) {
// Get our parent:
ResourceReferencerr = getParent();
if (rr != null) {
try {
Resourceparent = rr.lock();
if (parent.definesAttribute("directory")) {
Filepdir = (File) parent.getValue("directory", null);
if ( pdir != null ) {
// Compute and set our directory attribute:
dir = newFile(pdir, getIdentifier()) ;
setValue(ATTR_DIRECTORY, dir) ;
}
}
} catch (InvalidResourceExceptionex) {
} finally {
rr.unlock();
}
}
} else {
dir = getDirectory();
}
// Register our specific indexer, if any:
ResourceContextc = getContext();
Stringindexer = getString(ATTR_INDEXER, null);
if (( indexer != null ) && (!indexer.equals(""))) {
IndexerModulem = (IndexerModule)c.getModule(IndexerModule.NAME);
m.registerIndexer(c, indexer);
}
enableEvent();
}
}