Improved the store library massively and added a preliminary filesystem store.
[jsvc.git] / src / dolda / jsvc / store / Store.java
index 8e050a3..0664156 100644 (file)
@@ -3,83 +3,68 @@ package dolda.jsvc.store;
 import dolda.jsvc.*;
 import dolda.jsvc.util.Misc;
 import java.io.*;
-import java.security.*;
-import java.security.cert.Certificate;
 import java.util.*;
 
-public class Store {
+public abstract class Store implements Iterable<File> {
+    private static Map<String, Factory> kinds = new TreeMap<String, Factory>();
     private static Map<Package, Store> interned = new WeakHashMap<Package, Store>();
-    private final Package pkg;
-    private final File base;
+    protected final Package pkg;
     
-    private Store(Package pkg, CodeSource src, File root) {
+    protected Store(Package pkg) {
        this.pkg = pkg;
-       String nm = pkg.getName();
-       File base = root;
-       if(src != null) {
-           try {
-               MessageDigest fdig = MessageDigest.getInstance("MD5");
-               for(Certificate cert : src.getCertificates()) {
-                   MessageDigest cdig = MessageDigest.getInstance("MD5");
-                   cdig.update(cert.getEncoded());
-                   fdig.update(cdig.digest());
-               }
-               byte[] fp = fdig.digest();
-               StringBuilder buf = new StringBuilder();
-               for(byte b : fp) {
-                   buf.append(Misc.int2hex((b & 0xf0) >> 4, true));
-                   buf.append(Misc.int2hex(b & 0x0f, true));
-               }
-               base = new File(base, buf.toString());
-           } catch(NoSuchAlgorithmException e) {
-               throw(new Error(e));
-           } catch(java.security.cert.CertificateEncodingException e) {
-               throw(new Error(e));
-           }
-       }
-       int p = 0;
-       int p2;
-       while((p2 = nm.indexOf('.', p)) >= 0) {
-           base = new File(base, nm.substring(p, p2));
-           p = p2 + 1;
-       }
-       this.base = new File(base, nm.substring(p));
     }
     
-    private static File getstoreroot() {
+    public abstract File get(String name);
+    
+    public static interface Factory {
+       public Store create(String root, Package pkg);
+    }
+
+    private static String getstoreroot() {
        ThreadContext ctx = ThreadContext.current();
        if(ctx == null)
            throw(new RuntimeException("Not running in jsvc context"));
        String bn = ctx.server().config("jsvc.storage");
        if(bn == null)
            throw(new RuntimeException("No storage root has been configured"));
-       return(new File(bn));
+       return(bn);
     }
-
+    
     public static Store forclass(final Class<?> cl) {
        Package pkg = cl.getPackage();
-       File root = getstoreroot();
        Store s;
        synchronized(interned) {
            s = interned.get(pkg);
            if(s == null) {
-               ProtectionDomain dom;
-               dom = AccessController.doPrivileged(new PrivilegedAction<ProtectionDomain>() {
-                       public ProtectionDomain run() {
-                           try {
-                               return(cl.getProtectionDomain());
-                           } catch(SecurityException e) {
-                               return(null);
-                           }
-                       }
-                   });
-               if(dom != null)
-                   s = new Store(pkg, dom.getCodeSource(), root);
-               else
-                   s = new Store(pkg, null, root);
+               String root = getstoreroot();
+               int p = root.indexOf(':');
+               if(p < 0)
+                   throw(new RuntimeException("Invalid store specification: " + root));
+               String kind = root.substring(0, p);
+               root = root.substring(p + 1);
+               Factory fac;
+               synchronized(kinds) {
+                   fac = kinds.get(kind);
+                   if(fac == null)
+                       throw(new RuntimeException("No such store kind: " + kind));
+               }
+               s = fac.create(root, pkg);
                interned.put(pkg, s);
            }
        }
        return(s);
     }
+    
+    public static void register(String kind, Factory fac) {
+       synchronized(kinds) {
+           if(!kinds.containsKey(kind))
+               kinds.put(kind, fac);
+           else
+               throw(new RuntimeException("Store of type " + kind + " already exists"));
+       }
+    }
+    
+    static {
+       FileStore.register();
+    }
 }