Added basic session support.
authorFredrik Tolf <fredrik@dolda2000.com>
Mon, 26 Oct 2009 15:56:15 +0000 (16:56 +0100)
committerFredrik Tolf <fredrik@dolda2000.com>
Mon, 26 Oct 2009 15:56:15 +0000 (16:56 +0100)
samples/bsh/build.xml
src/dolda/jsvc/util/Cookie.java
src/dolda/jsvc/util/Session.java [new file with mode: 0644]

index fd6d4df..19384b3 100644 (file)
@@ -24,7 +24,7 @@
    
    <target name="bin-jar" depends="bin">
      <copy todir="build/bin" file="etc/jsvc.properties" />
-      <copy todir="build/bin/haven/errsvc">
+      <copy todir="build/bin/dolda/bsvc/static">
        <fileset dir="static">
          <!-- <include name="static/**" /> -->
        </fileset>
index 8783427..591289d 100644 (file)
@@ -6,6 +6,7 @@ import java.text.*;
 import java.io.*;
 
 public class Cookie {
+    private final static Map<Request, MultiMap<String, Cookie>> cache = new WeakHashMap<Request, MultiMap<String, Cookie>>();
     public final static DateFormat datefmt;
     static {
        datefmt = new SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss z", Locale.ENGLISH);
@@ -88,6 +89,17 @@ public class Cookie {
        return(ret);
     }
     
+    public static MultiMap<String, Cookie> get(Request req) {
+       synchronized(cache) {
+           MultiMap<String, Cookie> ret = cache.get(req);
+           if(ret == null) {
+               ret = parse(req);
+               cache.put(req, ret);
+           }
+           return(ret);
+       }
+    }
+
     public String toString() {
        StringBuilder buf = new StringBuilder();
        buf.append("Cookie(");
diff --git a/src/dolda/jsvc/util/Session.java b/src/dolda/jsvc/util/Session.java
new file mode 100644 (file)
index 0000000..31b65a7
--- /dev/null
@@ -0,0 +1,130 @@
+package dolda.jsvc.util;
+
+import dolda.jsvc.*;
+import java.util.*;
+import java.security.SecureRandom;
+
+public class Session implements java.io.Serializable {
+    private static final Map<String, Session> sessions = new HashMap<String, Session>();
+    private static final SecureRandom prng;
+    private static long lastclean = 0;
+    private final Map<Object, Object> props = new HashMap<Object, Object>();
+    private long ctime = System.currentTimeMillis(), atime = ctime, etime = 86400 * 1000;
+    private Collection<Listener> ll = new HashSet<Listener>();
+    
+    static {
+       try {
+           prng = SecureRandom.getInstance("SHA1PRNG");
+       } catch(java.security.NoSuchAlgorithmException e) {
+           throw(new Error(e));
+       }
+    }
+    
+    public static interface Listener {
+       public void expire(Session sess);
+    }
+    
+    public void listen(Listener l) {
+       synchronized(ll) {
+           ll.add(l);
+       }
+    }
+    
+    public Object get(Object key, Object def) {
+       synchronized(props) {
+           if(props.containsKey(key))
+               return(props.get(key));
+           else
+               return(def);
+       }
+    }
+    
+    public Object put(Object key, Object val) {
+       synchronized(props) {
+           return(props.put(key, val));
+       }
+    }
+    
+    private void expire() {
+       synchronized(ll) {
+           for(Listener l : ll)
+               l.expire(this);
+       }
+    }
+    
+    public static int num() {
+       synchronized(sessions) {
+           return(sessions.size());
+       }
+    }
+
+    private static String newid() {
+       byte[] rawid = new byte[16];
+       prng.nextBytes(rawid);
+       StringBuilder buf = new StringBuilder();
+       for(byte b : rawid) {
+           buf.append(Misc.int2hex((b & 0xf0) >> 4, false));
+           buf.append(Misc.int2hex(b & 0x0f, false));
+       }
+       return(buf.toString());
+    }
+
+    private static Session create(Request req) {
+       Session sess = new Session();
+       long etime = 0;
+       int ct;
+       ct = Integer.parseInt(req.ctx().libconfig("jsvc.session.expire", "0"));
+       if(ct > 0)
+           sess.etime = ct;
+       ct = Integer.parseInt(req.ctx().sysconfig("jsvc.session.expire", "0"));
+       if(ct > 0)
+           sess.etime = ct;
+       return(sess);
+    }
+    
+    private static void clean() {
+       long now = System.currentTimeMillis();
+       synchronized(sessions) {
+           for(Iterator<Session> i = sessions.values().iterator(); i.hasNext();) {
+               Session sess = i.next();
+               if(now > sess.atime + sess.etime) {
+                   i.remove();
+                   sess.expire();
+               }
+           }
+       }
+    }
+
+    public static Session get(Request req) {
+       long now = System.currentTimeMillis();
+       if(now - lastclean > 3600 * 1000) {
+           clean();
+           lastclean = now;
+       }
+       
+       MultiMap<String, Cookie> cookies = Cookie.get(req);
+       Cookie sc = cookies.get("jsvc-session");
+       Session sess = null;
+       synchronized(sessions) {
+           if(sc != null)
+               sess = sessions.get(sc.value);
+           if(sess == null) {
+               String id = newid();
+               sess = create(req);
+               sessions.put(id, sess);
+               sc = new Cookie("jsvc-session", id);
+               sc.expires = new Date(System.currentTimeMillis() + (86400L * 365L * 1000L));
+               sc.path = req.ctx().sysconfig("jsvc.session.path", req.rooturl().getPath());
+               String pd = req.ctx().sysconfig("jsvc.session.domain", null);
+               if(pd != null)
+                   sc.domain = pd;
+               sc.addto(req);
+           }
+       }
+       return(sess);
+    }
+    
+    public static Session get() {
+       return(get(RequestThread.request()));
+    }
+}