Mercurial Hosting > luan
view src/luan/modules/http/LuanHandler.java @ 1264:d41997776788
fix onClose issues
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Tue, 25 Sep 2018 17:03:57 -0600 |
parents | 382c444a6c77 |
children | 3f4644246e39 |
line wrap: on
line source
package luan.modules.http; import java.io.Closeable; import java.io.Writer; import java.io.PrintWriter; import java.io.IOException; import java.lang.ref.Reference; import java.lang.ref.WeakReference; import java.lang.reflect.Method; import java.net.BindException; import java.util.List; import java.util.ArrayList; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import luan.webserver.Request; import luan.webserver.Response; import luan.webserver.Server; import luan.webserver.Handler; import luan.webserver.ResponseOutputStream; import luan.Luan; import luan.LuanState; import luan.LuanTable; import luan.LuanFunction; import luan.LuanJavaFunction; import luan.LuanCloner; import luan.LuanException; import luan.modules.PackageLuan; import luan.modules.BasicLuan; public final class LuanHandler implements Handler { private class Instance implements LuanState.OnClose { private final List<Reference<Closeable>> onClose; private final LuanState luan; private final ReadWriteLock lock = new ReentrantReadWriteLock(); Instance() { onClose = new ArrayList<Reference<Closeable>>(); LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE); luan = (LuanState)cloner.clone(luanInit); luan.onClose = this; try { PackageLuan.load(luan,"site:/init.luan"); } catch(LuanException e) { String err = e.getLuanStackTraceString(); logger.error(err); } } Response handle(Request request,String modName) { Thread thread = Thread.currentThread(); String oldName = thread.getName(); thread.setName(request.headers.get("host")+request.path); lock.readLock().lock(); try { return HttpServicer.service(luan,request,modName); } finally { lock.readLock().unlock(); thread.setName(oldName); } } Object call_rpc(String fnName,Object... args) throws LuanException { lock.readLock().lock(); try { LuanFunction fn; LuanState luan = this.luan; synchronized(luan) { PackageLuan.enableLoad(luan,"luan:Rpc.luan"); LuanTable rpc = (LuanTable)PackageLuan.require(luan,"luan:Rpc.luan"); LuanTable fns = (LuanTable)rpc.get(luan,"functions"); fn = (LuanFunction)fns.get(luan,fnName); if( fn == null ) throw new LuanException( "function not found: " + fnName ); LuanCloner cloner = new LuanCloner(LuanCloner.Type.INCREMENTAL); luan = (LuanState)cloner.clone(luan); fn = (LuanFunction)cloner.get(fn); } return fn.call(luan,args); } finally { lock.readLock().unlock(); } } public Object runLuan(String sourceText,String sourceName) throws LuanException { lock.readLock().lock(); try { LuanFunction fn = Luan.load(sourceText,sourceName); synchronized(luan) { LuanCloner cloner = new LuanCloner(LuanCloner.Type.INCREMENTAL); LuanState luan = (LuanState)cloner.clone(this.luan); return fn.call(luan); } } finally { lock.readLock().unlock(); } } public void onClose(Closeable c) { synchronized(onClose) { onClose.add(new WeakReference<Closeable>(c)); } } public void close() { synchronized(onClose) { for( Reference<Closeable> ref : onClose ) { Closeable c = ref.get(); if( c != null ) { try { c.close(); } catch(IOException e) { logger.error(c.toString(),e); } } } onClose.clear(); } } Instance cloneInstance() { synchronized(luan) { return new Instance(this); } } private Instance(Instance instance) { onClose = instance.onClose; LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE); luan = (LuanState)cloner.clone(instance.luan); luan.onClose = this; } } private final LuanState luanInit; private final Logger logger; private volatile Instance instance; private static final Method resetLuanMethod; private static final Method evalInRootMethod; static { try { resetLuanMethod = LuanHandler.class.getMethod( "reset_luan" ); evalInRootMethod = LuanHandler.class.getMethod( "eval_in_root", String.class ); } catch(NoSuchMethodException e) { throw new RuntimeException(e); } } public LuanHandler(LuanState luanInit,String loggerRoot) { this.luanInit = luanInit; if( loggerRoot==null ) loggerRoot = ""; logger = LoggerFactory.getLogger(loggerRoot+LuanHandler.class.getName()); try { LuanTable Http = (LuanTable)PackageLuan.require(luanInit,"luan:http/Http.luan"); Http.rawPut( "reset_luan", new LuanJavaFunction(resetLuanMethod,this) ); Http.rawPut( "eval_in_root", new LuanJavaFunction(evalInRootMethod,this) ); } catch(LuanException e) { throw new RuntimeException(e); } instance = new Instance(); } /* public LuanState getLuan() { return luan; } */ @Override public Response handle(Request request) { if( request.path.endsWith("/") ) return null; String modName = "site:" + request.path +".luan"; return handle(request,modName); } Response handle(Request request,String modName) { return instance.handle(request,modName); } public void close() { instance.close(); } public Object call_rpc(String fnName,Object... args) throws LuanException { return instance.call_rpc(fnName,args); } public void reset_luan() { new Thread() { public void run() { instance.lock.writeLock().lock(); try { instance.close(); instance = new Instance(); } finally { instance.lock.writeLock().unlock(); } } }.start(); } public Object runLuan(String sourceText,String sourceName) throws LuanException { return instance.runLuan(sourceText,sourceName); } public void eval_in_root(String text) throws LuanException { Instance newInstance = this.instance.cloneInstance(); BasicLuan.load(text,"<eval_in_root>",null).call(newInstance.luan); this.instance = newInstance; } public static void start(Server server) throws Exception { try { server.start(); } catch(BindException e) { throw new LuanException(e.toString()); } } }