// DirectoryResource.java
// $Id: DirectoryResource.java,v 1.52 2002/06/26 17:55:05 ylafon Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html
package org.w3c.jigsaw.resources ;
import java.util.Hashtable;
import java.io.File;
import org.w3c.tools.resources.Attribute;
import org.w3c.tools.resources.AttributeHolder;
import org.w3c.tools.resources.AttributeRegistry;
import org.w3c.tools.resources.BooleanAttribute;
import org.w3c.tools.resources.ContainerResource;
import org.w3c.tools.resources.FramedResource;
import org.w3c.tools.resources.InvalidResourceException;
import org.w3c.tools.resources.LookupResult;
import org.w3c.tools.resources.LookupState;
import org.w3c.tools.resources.ProtocolException;
import org.w3c.tools.resources.RequestInterface;
import org.w3c.tools.resources.Resource;
import org.w3c.tools.resources.ResourceContext;
import org.w3c.tools.resources.ResourceReference;
import org.w3c.jigsaw.frames.NegotiatedFrame;
public class DirectoryResource
extends org.w3c.tools.resources.DirectoryResource
{
/**
* Attribute index - Should this directory support content negotiation.
*/
protected static int ATTR_NEGOTIABLE = -1 ;
static {
Attribute a = null ;
Class cls = null ;
// Get a pointer to our class.
try {
cls = Class.forName("org.w3c.jigsaw.resources.DirectoryResource") ;
} catch (Exception ex) {
ex.printStackTrace() ;
System.exit(1) ;
}
// The negotiate flag
a = new BooleanAttribute("negotiable"
, Boolean.FALSE
, Attribute.EDITABLE) ;
ATTR_NEGOTIABLE = AttributeRegistry.registerAttribute(cls, a) ;
}
/**
* Get the negotiable flag for this directory.
* When turned to <strong>true</strong>, this flag indicates to the
* directory resource that it should automatically build negotiated
* resources ont op of all existing resources.
* <p>You should know, at least, that turning this flag on has some
* not so small cost in terms of the size of the index files, and some
* not so small costs in CPU time when detecting not found documents.
* Otherwise, in all other situations its cost is probably negligible.
* @return A boolean, <strong>true</strong> if the directory is extensible
* <strong>false</strong> otherwise.
*/
public boolean getNegotiableFlag() {
return getBoolean(ATTR_NEGOTIABLE, false) ;
}
private String getUnextendedName(String name) {
int strlen = name.length() ;
for (int i = 0 ; i < strlen ; i++) {
// FIXME: Should use the system props to get the right sep
if ( name.charAt(i) == '.' ) {
if ( i == 0 )
return null ;
return name.substring(0, i) ;
}
}
return null ;
}
/**
* Update a negotiable resource.
* Given the name of a resource that exists, create or update the
* attributes of a resource that allows to negotiate its content.
* <p>I hate this part here: it has nothing to do within the directory
* resource itself, and the indexer shouldn't know that much about
* directory resource, so I am stuck.
* @param name The name of the newly created resource.
*/
public synchronized void updateNegotiableResource(String name) {
// Does the maintainer really wants us to perform this ugly hack ?
if ( ! getNegotiableFlag() )
return ;
// Check for the corresponding negotiable resource:
String noext = getUnextendedName(name) ;
if ( noext == null ) {
return ;
} else {
ResourceReference rr = lookup(noext);
ResourceReference rr_neg_frame = null;
if (rr != null) {
try {
FramedResource r = (FramedResource)rr.lock();
Class nClass =
Class.forName("org.w3c.jigsaw.frames.NegotiatedFrame");
rr_neg_frame = r.getFrameReference(nClass);
if (rr_neg_frame == null)
return;
} catch (ClassNotFoundException cex) {
return;
} catch (InvalidResourceException ex) {
return;
} finally {
rr.unlock();
}
}
if (rr_neg_frame == null) {
// we can't add a NegotiatedFrame to an existing resource.
if (rr == null) {
// create the resource.
FramedResource resource = new FramedResource();
Hashtable defs = new Hashtable(5) ;
defs.put(id, noext);
ResourceContext context =
updateDefaultChildAttributes(defs);
resource.initialize(defs);
addResource(resource, defs);
// add a NegotiatedFrame.
String variants[] = new String[1] ;
variants[0] = name ;
NegotiatedFrame negotiated = new NegotiatedFrame();
Hashtable f_defs = new Hashtable(5) ;
f_defs.put("variants".intern(), variants) ;
resource.registerFrame(negotiated, f_defs);
}
} else {
try {
NegotiatedFrame negotiated =
(NegotiatedFrame) rr_neg_frame.lock();
String variants[] = negotiated.getVariantNames() ;
boolean exists = false;
for ( int i=0 ; i < variants.length ; i++ ) {
if (variants[i].equals(name))
exists = true;
}
if (!exists) {
String nvariants[] = new String[variants.length+1] ;
System.arraycopy(variants, 0, nvariants,
0, variants.length);
nvariants[variants.length] = name ;
negotiated.setVariants(nvariants) ;
}
} catch (InvalidResourceException ex) {
//FIXME
} finally {
rr_neg_frame.unlock();
}
}
}
}
/**
* Lookup the next component of this lookup state in here.
* @param ls The current lookup state.
* @param lr The lookup result under construction.
* @exception ProtocolException If an error occurs.
* @return A boolean, <strong>true</strong> if lookup has completed,
* <strong>false</strong> if it should be continued by the caller.
*/
public boolean lookup(LookupState ls, LookupResult lr)
throws ProtocolException
{
int remain = ls.countRemainingComponents();
String name = null;
// save the name if it is the last
if (remain == 1) {
name = ls.peekNextComponent();
}
// if it is ok, great!
if (super.lookup(ls, lr)) {
return true;
}
// fails: check if we can create a negotiated resource
if ( (name != null) && getNegotiableFlag() && getExtensibleFlag()) {
// try to create the right negotiated resource
String rname = name + '.';
File directory = getDirectory() ;
if ( directory != null ) {
synchronized(this) {
long dirstamp = directory.lastModified() ;
String lst[] = directory.list() ;
// FIXME we should perhaps get also the children
// FIXME in case specific config has been done
if ( lst != null ) {
for (int i = 0 ; i < lst.length ; i++) {
if (lst[i].equals(".") ||
lst[i].equals(".."))
continue ;
// if it is not matching the name, abort
if (!lst[i].startsWith(rname))
continue;
if (lookup(lst[i]) == null) {
String indexed = getIndexedName(lst[i]);
if (indexed.equals(lst[i])) {
createDefaultResource(lst[i]) ;
} else if (super.lookup(indexed) == null) {
createDefaultResource(lst[i]) ;
}
}
updateNegotiableResource(lst[i]);
}
}
setLong(ATTR_DIRSTAMP, dirstamp) ;
}
}
ResourceReference rr = null;
rr = lookup(name);
if (rr == null) {
lr.setTarget(null);
return false;
}
try {
lr.setTarget(rr);
FramedResource resource = (FramedResource) rr.lock();
return (resource != null ) ? resource.lookup(ls, lr) : false;
} catch (InvalidResourceException ex) {
return false;
} finally {
rr.unlock();
}
}
return false;
}
}