001: // SampleResourceIndexer.java
002: // $Id: SampleResourceIndexer.java,v 1.22 2002/10/29 14:39:02 ylafon Exp $
003: // (c) COPYRIGHT MIT and INRIA, 1997.
004: // Please first read the full copyright statement in file COPYRIGHT.html
005:
006: package org.w3c.tools.resources.indexer;
007:
008: import java.util.Enumeration;
009: import java.util.Hashtable;
010: import java.util.NoSuchElementException;
011: import java.util.Vector;
012:
013: import java.io.File;
014:
015: import org.w3c.tools.resources.Attribute;
016: import org.w3c.tools.resources.AttributeHolder;
017: import org.w3c.tools.resources.AttributeRegistry;
018: import org.w3c.tools.resources.ContainerInterface;
019: import org.w3c.tools.resources.ContainerResource;
020: import org.w3c.tools.resources.DummyResourceReference;
021: import org.w3c.tools.resources.FramedResource;
022: import org.w3c.tools.resources.InvalidResourceException;
023: import org.w3c.tools.resources.MultipleLockException;
024: import org.w3c.tools.resources.RequestInterface;
025: import org.w3c.tools.resources.Resource;
026: import org.w3c.tools.resources.ResourceContext;
027: import org.w3c.tools.resources.ResourceFrame;
028: import org.w3c.tools.resources.ResourceReference;
029: import org.w3c.tools.resources.ServerInterface;
030: import org.w3c.tools.resources.StringArrayAttribute;
031: import org.w3c.tools.resources.StringAttribute;
032:
033: class SampleIndexerEnumeration implements Enumeration {
034: private static final String list[] = { "directories".intern(),
035: "extensions".intern() };
036:
037: int idx = 0;
038:
039: public boolean hasMoreElements() {
040: return idx < list.length;
041: }
042:
043: public Object nextElement() {
044: if (idx >= list.length)
045: throw new NoSuchElementException(
046: "SampleResourceIndexer enum");
047: return list[idx++];
048: }
049:
050: SampleIndexerEnumeration() {
051: this .idx = 0;
052: }
053:
054: }
055:
056: /**
057: * A container for directories and templates.
058: */
059:
060: public class SampleResourceIndexer extends Resource implements
061: ContainerInterface, ResourceIndexer {
062: private static final boolean debug = false;
063: protected static final boolean extCaseSensitive = false;
064: protected static final String defname = "*default*";
065:
066: private static final String harmfulNames[] = { "aux".intern(),
067: "con".intern() };
068:
069: static public boolean isWinPlatform = (File.pathSeparatorChar == ';');
070: /**
071: * Attribute index - the super indexer, if any.
072: */
073: protected static int ATTR_SUPER_INDEXER = -1;
074:
075: /**
076: * Attribute index - the super indexer, if any.
077: */
078: protected static int ATTR_NOT_INDEXED = -1;
079:
080: static {
081: Attribute a = null;
082: Class c = org.w3c.tools.resources.indexer.SampleResourceIndexer.class;
083: // Our super indexer:
084: a = new StringAttribute("super-indexer", null,
085: Attribute.EDITABLE);
086: ATTR_SUPER_INDEXER = AttributeRegistry.registerAttribute(c, a);
087: a = new StringArrayAttribute("not-indexed-names", null,
088: Attribute.EDITABLE);
089: ATTR_NOT_INDEXED = AttributeRegistry.registerAttribute(c, a);
090: }
091:
092: protected ResourceReference directories = null;
093: protected ResourceReference extensions = null;
094: protected ResourceReference contentTypes = null;
095:
096: protected synchronized ResourceReference getDirectories() {
097: if (directories == null) {
098: String diridxid = getIdentifier() + "-d";
099: directories = new DummyResourceReference(
100: new TemplateContainer(new ResourceContext(
101: getContext()), diridxid + ".db"));
102: }
103: return directories;
104: }
105:
106: protected synchronized ResourceReference getExtensions() {
107: if (extensions == null) {
108: String extidxid = getIdentifier() + "-e";
109: extensions = new DummyResourceReference(
110: new TemplateContainer(new ResourceContext(
111: getContext()), extidxid + ".db"));
112: }
113: return extensions;
114: }
115:
116: public long lastModified() {
117: return getLong(ATTR_LAST_MODIFIED, -1);
118: }
119:
120: public String getSuperIndexer() {
121: return getString(ATTR_SUPER_INDEXER, null);
122: }
123:
124: public Enumeration enumerateResourceIdentifiers(boolean all) {
125: return new SampleIndexerEnumeration();
126: }
127:
128: public ResourceReference lookup(String name) {
129: if (name.equals("directories")) {
130: return getDirectories();
131: } else if (name.equals("extensions")) {
132: return getExtensions();
133: }
134: return null;
135: }
136:
137: /**
138: * Delete this inexer
139: * @exception org.w3c.tools.resources.MultipleLockException if someone
140: * else has locked the indexer.
141: */
142: public synchronized void delete() throws MultipleLockException {
143: // Remove the two stores we are responsible for:
144: DummyResourceReference rr = (DummyResourceReference) getExtensions();
145: try {
146: Resource r = rr.lock();
147: r.delete();
148: } catch (InvalidResourceException ex) {
149: } finally {
150: rr.invalidate();
151: rr.unlock();
152: }
153:
154: rr = (DummyResourceReference) getDirectories();
155: try {
156: Resource r = rr.lock();
157: r.delete();
158: } catch (InvalidResourceException ex) {
159: } finally {
160: rr.invalidate();
161: rr.unlock();
162: }
163:
164: super .delete();
165: }
166:
167: public void delete(String name) {
168: throw new RuntimeException("static container");
169: }
170:
171: public void registerResource(String name, Resource resource,
172: Hashtable defs) {
173: throw new RuntimeException("static container");
174: }
175:
176: /*
177: * Load an extension descriptor.
178: * @param ext The name of the extension.
179: * @return An instance of Extension, or <strong>null</strong>.
180: */
181:
182: public synchronized ResourceReference loadExtension(String name) {
183: ResourceReference rr = getExtensions();
184: ResourceReference ext = null;
185: try {
186: TemplateContainer exts = (TemplateContainer) rr.lock();
187: // try with exact and if it fails, try to with lower case
188: ext = exts.lookup(name);
189: if (ext == null && !extCaseSensitive)
190: return exts.lookup(name.toLowerCase());
191: return ext;
192: } catch (InvalidResourceException ex) {
193: String msg = ("[resource indexer]: extensions \"" + name
194: + "\" couldn't be restored (" + ex.getMessage() + ")");
195: getContext().getServer().errlog(msg);
196: return null;
197: } finally {
198: rr.unlock();
199: }
200: }
201:
202: /**
203: * Return the class (if any) that our store defines for given extension.
204: * @param ext The extension we want a class for.
205: * @return A Class instance, or <strong>null</strong>.
206: */
207:
208: protected ResourceReference getTemplateFor(String ext) {
209: ResourceReference rr = loadExtension(ext);
210: if (rr != null) {
211: try {
212: Resource template = rr.lock();
213: if (template != null) {
214: Resource check = new Resource();
215: if (template.getClass() == check.getClass())
216: return null;
217: else
218: return rr;
219: }
220: return null;
221: } catch (InvalidResourceException ex) {
222: return null;
223: } finally {
224: rr.unlock();
225: }
226: }
227: return null;
228: }
229:
230: /**
231: * Merge the attributes this extension defines, with the provided ones.
232: * @param attrs The attributes we want to fill with default values.
233: * @param ext The extension name.
234: * @param into The already built set of default values.
235: * @return A Hashtable, containing the augmented set of default attribute
236: * values.
237: */
238:
239: protected Hashtable mergeDefaultAttributes(Resource template,
240: String ext, Hashtable into) {
241: Attribute attrs[] = template.getAttributes();
242: ResourceReference rr = loadExtension(ext);
243: if (rr != null) {
244: try {
245: Resource e = rr.lock();
246: if (e != null) {
247: for (int i = 0; i < attrs.length; i++) {
248: if (!template.definesAttribute(i)) {
249: int idx = e.lookupAttribute(attrs[i]
250: .getName());
251: if (idx >= 0) {
252: Object value = e.getValue(idx, null);
253: if (value != null)
254: into.put(attrs[i].getName(), value);
255: }
256: }
257: }
258: }
259: return into;
260: } catch (InvalidResourceException ex) {
261: return null;
262: } finally {
263: rr.unlock();
264: }
265: }
266: return null;
267: }
268:
269: /**
270: * Merge the attributes this extension defines, with the provided ones.
271: * @param origFrame The original frame
272: * @param ext The extension name
273: * @param into The ResourceReference of the frame to be merged
274: */
275:
276: protected void mergeFrameAttributes(ResourceFrame origFrame,
277: String ext, ResourceReference frameref) {
278: int idx;
279: Object oldval, newval;
280: String atname;
281:
282: try {
283: Resource frame = frameref.lock();
284: Attribute attrs[] = frame.getAttributes();
285: for (int i = 0; i < attrs.length; i++) {
286: atname = attrs[i].getName();
287: try {
288: oldval = origFrame.getValue(atname, null);
289: if (oldval == null) { // not defined, try to merge
290: try {
291: origFrame.setValue(atname, frame.getValue(
292: atname, null));
293: } catch (Exception ex) {
294: // undefined value, will stay null
295: }
296: } else if (atname.equals("quality")) {
297: // small hack here, quality factor are merged
298: // should be removed by a quality per encoding
299: Double d = (Double) frame
300: .getValue(atname, null);
301: if (d != null) {
302: d = new Double(d.doubleValue()
303: * ((Double) oldval).doubleValue());
304: origFrame.setValue(atname, d);
305: }
306: }
307: } catch (Exception undefined) {
308: // attribute is NOT defined
309: }
310: }
311: } catch (InvalidResourceException ex) {
312: ex.printStackTrace();
313: } finally {
314: frameref.unlock();
315: }
316: }
317:
318: /**
319: * Get this name's extensions.
320: * @param name The file name.
321: * @return An array of string, giving ach (parsed) extension, or
322: * <strong>null</strong> if none was found.
323: */
324:
325: private final static String noextension[] = { "*noextension*" };
326:
327: protected String[] getFileExtensions(String name) {
328: Vector items = new Vector();
329: int dpos = name.indexOf('.');
330:
331: if (dpos > 0) {
332: int pos = dpos + 1;
333: while ((dpos = name.indexOf('.', pos)) != -1) {
334: // Skip empty extension:
335: if (dpos == pos + 1) {
336: pos++;
337: continue;
338: }
339: // Else add new extension:
340: items.addElement(name.substring(pos, dpos));
341: pos = dpos + 1;
342: }
343: if (pos < name.length())
344: items.addElement(name.substring(pos));
345: String exts[] = new String[items.size()];
346: items.copyInto(exts);
347: return exts;
348: } else {
349: // That file has no extensions, we'll use '.' as its extension
350: return noextension;
351: }
352: }
353:
354: /**
355: * Create a default file resource for this file (that exists).
356: * @param directory The directory of the file.
357: * @param name The name of the file.
358: * @param defs A set of default attribute values.
359: * @return An instance of Resource, or <strong>null</strong> if
360: * we were unable to create it.
361: */
362:
363: protected Resource createFileResource(File directory,
364: RequestInterface req, String name, Hashtable defs) {
365: ResourceReference rr = null;
366: FramedResource template = null;
367: Resource newres = null;
368: Class proto = null;
369: try {
370: proto = Class
371: .forName("org.w3c.tools.resources.ProtocolFrame");
372: } catch (Exception ex) {
373: // fatal error!
374: return null;
375: }
376: // Check that at least one class is defined for all the extensions:
377: String exts[] = getFileExtensions(name);
378: if (exts == null)
379: return null;
380: for (int i = exts.length - 1; i >= 0; i--) {
381: rr = getTemplateFor(exts[i]);
382: if (rr != null)
383: break;
384: }
385: if (rr == null) {
386: // Look for a default template:
387: if ((rr = loadExtension(defname)) == null)
388: return null;
389: }
390: // Create the runtime-time default values for attributes.
391: if (defs == null) {
392: defs = new Hashtable(5);
393: }
394: String s_dir = "directory".intern();
395: String s_ide = "identifier".intern();
396: String s_fil = "filename".intern();
397: String s_con = "context".intern();
398:
399: if (defs.get(s_dir) == null) {
400: defs.put(s_dir, directory);
401: }
402: if (defs.get(s_ide) == null) {
403: defs.put(s_ide, getIndexedFileName(name));
404: } else {
405: defs.put(s_ide,
406: getIndexedFileName((String) defs.get(s_ide)));
407: }
408: if (defs.get(s_fil) == null) {
409: defs.put(s_fil, name);
410: }
411: if (defs.get(s_con) == null) {
412: defs.put(s_con, getContext());
413: }
414: try {
415: template = (FramedResource) rr.lock();
416: if (exts != null) {
417: // Merge with values defined by the extension:
418: for (int i = exts.length; --i >= 0;)
419: mergeDefaultAttributes(template, exts[i], defs);
420: }
421: // Create, initialize and return the new resouce
422: try {
423: newres = (FramedResource) template.getClone(defs);
424: } catch (Exception ex) {
425: ex.printStackTrace();
426: return null;
427: }
428: } catch (InvalidResourceException ex) {
429: ex.printStackTrace();
430: return null;
431: } finally {
432: rr.unlock();
433: }
434: // clone has been done, merge frames now
435: if (exts != null) {
436: ResourceFrame rf[] = newres.collectFrames(proto);
437: if (rf != null) {
438: for (int j = 0; j < rf.length; j++) {
439: for (int i = exts.length - 1; i >= 0; i--) {
440: rr = getTemplateFor(exts[i]);
441: if (rr != null) {
442: FramedResource fr = null;
443: try {
444: fr = (FramedResource) rr.lock();
445: ResourceReference trr = null;
446: trr = fr.getFrameReference(proto);
447: if (trr != null) {
448: mergeFrameAttributes(rf[j],
449: exts[i], trr);
450: }
451: } catch (InvalidResourceException iex) {
452: iex.printStackTrace();
453: return null;
454: } finally {
455: rr.unlock();
456: }
457: }
458: }
459: }
460: }
461: }
462: return newres;
463: }
464:
465: /**
466: * Load a given directory template from the store.
467: * @param name The name of the template to load.
468: * @return An instance of ResourceReference, or <strong>null</strong>.
469: */
470:
471: public synchronized ResourceReference loadDirectory(String name) {
472: ResourceReference rr = getDirectories();
473: try {
474: TemplateContainer dirs = (TemplateContainer) rr.lock();
475: return dirs.lookup(name);
476: } catch (InvalidResourceException ex) {
477: // Emit an error message, and remove it !
478: String msg = ("[resource indexer]: directory template \""
479: + name + "\" couldn't be restored. It has " + "been removed.");
480: getContext().getServer().errlog(msg);
481: return null;
482: } finally {
483: rr.unlock();
484: }
485: }
486:
487: /**
488: * Create a default container resource for this directory (that exists).
489: * @param directory The parent directory.
490: * @param req the request that triggered this creation
491: * @param name The name of its sub-directory to index.
492: * @param defaults A set of default atribute values.
493: * @return A Resource instance, or <strong>null</strong> if
494: * the indexer was unable to build a default resource for the directory.
495: */
496:
497: protected Resource createDirectoryResource(File directory,
498: RequestInterface req, String name, Hashtable defs) {
499: // Lookup the directory path, for an existing template.
500: File dir = new File(directory, name);
501: Resource dirtempl = null;
502: ResourceReference rr = null;
503:
504: rr = loadDirectory(name);
505: // If no template available, default to a raw DirectoryResource
506: if ((rr == null) && ((rr = loadDirectory(defname)) == null))
507: return null;
508: try {
509: dirtempl = rr.lock();
510: // Clone the appropriate template:
511: if (defs == null) {
512: defs = new Hashtable(3);
513: }
514: String s_dir = "directory".intern();
515: String s_ide = "identifier".intern();
516: if (defs.get(s_dir) == null) {
517: defs.put(s_dir, directory);
518: }
519: if (defs.get(s_ide) == null) {
520: defs.put(s_ide, getIndexedDirName(name));
521: } else {
522: defs.put(s_ide, getIndexedDirName((String) defs
523: .get(s_ide)));
524: }
525: //FIXME context ???
526: // if ( defs.get("context") == null )
527: // defs.put("context", getContext());
528: try {
529: return (Resource) dirtempl.getClone(defs);
530: } catch (Exception ex) {
531: ex.printStackTrace();
532: return null;
533: }
534: } catch (InvalidResourceException ex) {
535: ex.printStackTrace();
536: return null;
537: } finally {
538: rr.unlock();
539: }
540: }
541:
542: /**
543: * Try to create a virtual resource if the real (physical) resource
544: * is not there.
545: * @param directory The directory the file is in.
546: * @param req the request that triggered this creation
547: * @param name The name of the file.
548: * @param defs Any default attribute values that should be provided
549: * to the created resource at initialization time.
550: * @return A Resource instance, or <strong>null</strong> if the given
551: * file can't be truned into a resource given our configuration
552: * database.
553: */
554:
555: protected Resource createVirtualResource(File directory,
556: RequestInterface req, String name, Hashtable defs) {
557: ResourceReference rr = null;
558: Resource dirtempl = null;
559:
560: rr = loadDirectory(name);
561: if (rr != null) {
562: try {
563: dirtempl = rr.lock();
564: String classname = dirtempl.getClass().getName()
565: .intern();
566: String idr = "org.w3c.jigsaw.resources.DirectoryResource"
567: .intern();
568: if (classname == idr) {
569: File file = new File(directory, name);
570: // check in this case that we will have a special
571: // configuration ONLY for a real directory
572: if (!file.exists()) {
573: return null;
574: }
575: if (!file.isDirectory()) {
576: return null;
577: }
578: }
579: String ifr = "org.w3c.tools.resources.FileResource"
580: .intern();
581: if (classname == ifr) {
582: File file = new File(directory, name);
583: // check that we won't override a bad resource type
584: if (!file.exists()) {
585: return null;
586: }
587: if (file.isDirectory()) {
588: return null;
589: }
590: }
591: if (defs == null) {
592: defs = new Hashtable(4);
593: }
594: String s_dir = "directory".intern();
595: String s_ide = "identifier".intern();
596: String s_con = "context".intern();
597: if (defs.get(s_dir) == null) {
598: defs.put(s_dir, directory);
599: }
600: if (defs.get(s_ide) == null) {
601: defs.put(s_ide, name);
602: }
603: if (defs.get(s_con) == null) {
604: defs.put(s_con, getContext());
605: }
606: try {
607: return (Resource) dirtempl.getClone(defs);
608: } catch (Exception ex) {
609: ex.printStackTrace();
610: return null;
611: }
612: } catch (InvalidResourceException ex) {
613: ex.printStackTrace();
614: return null;
615: } finally {
616: rr.unlock();
617: }
618: }
619: return null;
620: }
621:
622: /**
623: * Try to create a resource for the given file.
624: * This method makes its best efforts to try to build a default
625: * resource out of a file.
626: * @param directory The directory the file is in.
627: * @param name The name of the file.
628: * @param defs Any default attribute values that should be provided
629: * to the created resource at initialization time.
630: * @return A Resource instance, or <strong>null</strong> if the given
631: * file can't be truned into a resource given our configuration
632: * database.
633: */
634:
635: public Resource createResource(ContainerResource container,
636: RequestInterface request, File directory, String name,
637: Hashtable defs) {
638: if (isWinPlatform) {
639: for (int i = 0; i < harmfulNames.length; i++) {
640: if (name.equalsIgnoreCase(harmfulNames[i])) {
641: return null;
642: }
643: }
644: }
645: // if it matches the Not-Indexed list, then exit
646: String[] removed = (String[]) getValue(ATTR_NOT_INDEXED, null);
647: if (removed != null) {
648: for (int i = 0; i < removed.length; i++) {
649: if (name.equals(removed[i])) {
650: return null;
651: }
652: }
653: }
654: // Does this file exists ?
655: File file = new File(directory, name);
656: Resource result = null;
657: result = createVirtualResource(directory, request, name, defs);
658: if (result != null) {
659: return result;
660: }
661: if (!file.exists()) {
662: return null;
663: }
664: // Okay, dispatch on wether it is a file or a directory.
665: if (file.isDirectory()) {
666: result = createDirectoryResource(directory, request, name,
667: defs);
668: } else if (file.isFile()) {
669: result = createFileResource(directory, request, name, defs);
670: } else {
671: // not a directory and not a real file, perhaps something not
672: // really wanted
673: return null;
674: }
675: if (result != null)
676: return result;
677: // Try the super indexer if available:
678: String super Indexer = getSuperIndexer();
679: if (super Indexer == null)
680: return null;
681: IndexerModule m = null;
682: m = (IndexerModule) getContext().getModule(IndexerModule.NAME);
683: ResourceReference rri = m.getIndexer(super Indexer);
684: if (rri == null)
685: return null;
686: try {
687: ResourceIndexer p = (ResourceIndexer) rri.lock();
688: return ((p != null) ? p.createResource(container, request,
689: directory, name, defs) : null);
690: } catch (InvalidResourceException ex) {
691: return null;
692: } finally {
693: rri.unlock();
694: }
695: }
696:
697: /**
698: * Get the name of the resource relative to the given filename.
699: * @param name The name of the file.
700: * @return a String, the resource name.
701: */
702: public String getIndexedName(File directory, String name) {
703: if (isWinPlatform) {
704: for (int i = 0; i < harmfulNames.length; i++) {
705: if (name.equalsIgnoreCase(harmfulNames[i])) {
706: return null;
707: }
708: }
709: }
710: File file = new File(directory, name);
711: if (!file.exists())
712: return null;
713: if (file.isDirectory())
714: return getIndexedDirName(name);
715: //make sure that we will index this file (or directory)
716: String exts[] = getFileExtensions(name);
717: ResourceReference rr = null;
718: if (exts == null)
719: return null;
720: for (int i = exts.length - 1; i >= 0; i--) {
721: rr = getTemplateFor(exts[i]);
722: if (rr != null)
723: break;
724: }
725: if (rr != null)
726: return getIndexedFileName(name);
727: //try the super indexer
728: String super Indexer = getSuperIndexer();
729: if (super Indexer == null)
730: return null;
731: IndexerModule m = null;
732: m = (IndexerModule) getContext().getModule(IndexerModule.NAME);
733: ResourceReference rri = m.getIndexer(super Indexer);
734: if (rri == null)
735: return null;
736: try {
737: ResourceIndexer p = (ResourceIndexer) rri.lock();
738: return ((p != null) ? p.getIndexedName(directory, name)
739: : null);
740: } catch (InvalidResourceException ex) {
741: return null;
742: } finally {
743: rri.unlock();
744: }
745: }
746:
747: protected String getIndexedFileName(String name) {
748: return name;
749: }
750:
751: protected String getIndexedDirName(String name) {
752: return name;
753: }
754:
755: // FIXME tests
756: public SampleResourceIndexer(ResourceContext ctxt) {
757: Hashtable init = new Hashtable(3);
758: String s_ide = "identifier".intern();
759: String s_con = "context".intern();
760: init.put(s_con, ctxt);
761: init.put(s_ide, "default");
762: initialize(init);
763: }
764:
765: public SampleResourceIndexer() {
766: super();
767: }
768: }
|