comparison 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
comparison
equal deleted inserted replaced
1263:382c444a6c77 1264:d41997776788
2 2
3 import java.io.Closeable; 3 import java.io.Closeable;
4 import java.io.Writer; 4 import java.io.Writer;
5 import java.io.PrintWriter; 5 import java.io.PrintWriter;
6 import java.io.IOException; 6 import java.io.IOException;
7 import java.lang.ref.Reference;
8 import java.lang.ref.WeakReference;
7 import java.lang.reflect.Method; 9 import java.lang.reflect.Method;
8 import java.net.BindException; 10 import java.net.BindException;
11 import java.util.List;
12 import java.util.ArrayList;
13 import java.util.concurrent.locks.ReadWriteLock;
14 import java.util.concurrent.locks.ReentrantReadWriteLock;
9 import org.slf4j.Logger; 15 import org.slf4j.Logger;
10 import org.slf4j.LoggerFactory; 16 import org.slf4j.LoggerFactory;
11 import luan.webserver.Request; 17 import luan.webserver.Request;
12 import luan.webserver.Response; 18 import luan.webserver.Response;
13 import luan.webserver.Server; 19 import luan.webserver.Server;
22 import luan.LuanException; 28 import luan.LuanException;
23 import luan.modules.PackageLuan; 29 import luan.modules.PackageLuan;
24 import luan.modules.BasicLuan; 30 import luan.modules.BasicLuan;
25 31
26 32
27 public final class LuanHandler implements Handler, Closeable { 33 public final class LuanHandler implements Handler {
34
35 private class Instance implements LuanState.OnClose {
36 private final List<Reference<Closeable>> onClose;
37 private final LuanState luan;
38 private final ReadWriteLock lock = new ReentrantReadWriteLock();
39
40 Instance() {
41 onClose = new ArrayList<Reference<Closeable>>();
42 LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE);
43 luan = (LuanState)cloner.clone(luanInit);
44 luan.onClose = this;
45 try {
46 PackageLuan.load(luan,"site:/init.luan");
47 } catch(LuanException e) {
48 String err = e.getLuanStackTraceString();
49 logger.error(err);
50 }
51 }
52
53 Response handle(Request request,String modName) {
54 Thread thread = Thread.currentThread();
55 String oldName = thread.getName();
56 thread.setName(request.headers.get("host")+request.path);
57 lock.readLock().lock();
58 try {
59 return HttpServicer.service(luan,request,modName);
60 } finally {
61 lock.readLock().unlock();
62 thread.setName(oldName);
63 }
64 }
65
66 Object call_rpc(String fnName,Object... args) throws LuanException {
67 lock.readLock().lock();
68 try {
69 LuanFunction fn;
70 LuanState luan = this.luan;
71 synchronized(luan) {
72 PackageLuan.enableLoad(luan,"luan:Rpc.luan");
73 LuanTable rpc = (LuanTable)PackageLuan.require(luan,"luan:Rpc.luan");
74 LuanTable fns = (LuanTable)rpc.get(luan,"functions");
75 fn = (LuanFunction)fns.get(luan,fnName);
76 if( fn == null )
77 throw new LuanException( "function not found: " + fnName );
78 LuanCloner cloner = new LuanCloner(LuanCloner.Type.INCREMENTAL);
79 luan = (LuanState)cloner.clone(luan);
80 fn = (LuanFunction)cloner.get(fn);
81 }
82 return fn.call(luan,args);
83 } finally {
84 lock.readLock().unlock();
85 }
86 }
87
88 public Object runLuan(String sourceText,String sourceName) throws LuanException {
89 lock.readLock().lock();
90 try {
91 LuanFunction fn = Luan.load(sourceText,sourceName);
92 synchronized(luan) {
93 LuanCloner cloner = new LuanCloner(LuanCloner.Type.INCREMENTAL);
94 LuanState luan = (LuanState)cloner.clone(this.luan);
95 return fn.call(luan);
96 }
97 } finally {
98 lock.readLock().unlock();
99 }
100 }
101
102 public void onClose(Closeable c) {
103 synchronized(onClose) {
104 onClose.add(new WeakReference<Closeable>(c));
105 }
106 }
107
108 public void close() {
109 synchronized(onClose) {
110 for( Reference<Closeable> ref : onClose ) {
111 Closeable c = ref.get();
112 if( c != null ) {
113 try {
114 c.close();
115 } catch(IOException e) {
116 logger.error(c.toString(),e);
117 }
118 }
119 }
120 onClose.clear();
121 }
122 }
123
124 Instance cloneInstance() {
125 synchronized(luan) {
126 return new Instance(this);
127 }
128 }
129
130 private Instance(Instance instance) {
131 onClose = instance.onClose;
132 LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE);
133 luan = (LuanState)cloner.clone(instance.luan);
134 luan.onClose = this;
135 }
136 }
137
28 private final LuanState luanInit; 138 private final LuanState luanInit;
29 private final Logger logger; 139 private final Logger logger;
30 private volatile LuanState luan; 140 private volatile Instance instance;
31 141
32 private static final Method resetLuanMethod; 142 private static final Method resetLuanMethod;
33 private static final Method evalInRootMethod; 143 private static final Method evalInRootMethod;
34 static { 144 static {
35 try { 145 try {
50 Http.rawPut( "reset_luan", new LuanJavaFunction(resetLuanMethod,this) ); 160 Http.rawPut( "reset_luan", new LuanJavaFunction(resetLuanMethod,this) );
51 Http.rawPut( "eval_in_root", new LuanJavaFunction(evalInRootMethod,this) ); 161 Http.rawPut( "eval_in_root", new LuanJavaFunction(evalInRootMethod,this) );
52 } catch(LuanException e) { 162 } catch(LuanException e) {
53 throw new RuntimeException(e); 163 throw new RuntimeException(e);
54 } 164 }
55 setLuan(); 165 instance = new Instance();
56 luanInit.onClose(this); 166 }
57 } 167 /*
58
59 public LuanState getLuan() { 168 public LuanState getLuan() {
60 return luan; 169 return luan;
61 } 170 }
62 171 */
63 private void setLuan() {
64 LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE);
65 luan = (LuanState)cloner.clone(luanInit);
66 try {
67 PackageLuan.load(luan,"site:/init.luan");
68 } catch(LuanException e) {
69 String err = e.getLuanStackTraceString();
70 logger.error(err);
71 }
72 }
73
74 @Override public Response handle(Request request) { 172 @Override public Response handle(Request request) {
75 if( request.path.endsWith("/") ) 173 if( request.path.endsWith("/") )
76 return null; 174 return null;
77 String modName = "site:" + request.path +".luan"; 175 String modName = "site:" + request.path +".luan";
78 return handle(request,modName); 176 return handle(request,modName);
79 } 177 }
80 178
81 Response handle(Request request,String modName) { 179 Response handle(Request request,String modName) {
82 Thread thread = Thread.currentThread(); 180 return instance.handle(request,modName);
83 String oldName = thread.getName();
84 thread.setName(request.headers.get("host")+request.path);
85 try {
86 return HttpServicer.service(luan,request,modName);
87 } finally {
88 thread.setName(oldName);
89 }
90 } 181 }
91 182
92 public void close() { 183 public void close() {
93 synchronized(luan) { 184 instance.close();
94 luan.close();
95 }
96 } 185 }
97 186
98 public Object call_rpc(String fnName,Object... args) throws LuanException { 187 public Object call_rpc(String fnName,Object... args) throws LuanException {
99 LuanFunction fn; 188 return instance.call_rpc(fnName,args);
100 LuanState luan = this.luan;
101 synchronized(luan) {
102 PackageLuan.enableLoad(luan,"luan:Rpc.luan");
103 LuanTable rpc = (LuanTable)PackageLuan.require(luan,"luan:Rpc.luan");
104 LuanTable fns = (LuanTable)rpc.get(luan,"functions");
105 fn = (LuanFunction)fns.get(luan,fnName);
106 if( fn == null )
107 throw new LuanException( "function not found: " + fnName );
108 LuanCloner cloner = new LuanCloner(LuanCloner.Type.INCREMENTAL);
109 luan = (LuanState)cloner.clone(luan);
110 fn = (LuanFunction)cloner.get(fn);
111 }
112 return fn.call(luan,args);
113 } 189 }
114 190
115 public void reset_luan() { 191 public void reset_luan() {
116 setLuan(); 192 new Thread() {
193 public void run() {
194 instance.lock.writeLock().lock();
195 try {
196 instance.close();
197 instance = new Instance();
198 } finally {
199 instance.lock.writeLock().unlock();
200 }
201 }
202 }.start();
117 } 203 }
118 204
119 public Object runLuan(String sourceText,String sourceName) throws LuanException { 205 public Object runLuan(String sourceText,String sourceName) throws LuanException {
120 LuanFunction fn = Luan.load(sourceText,sourceName); 206 return instance.runLuan(sourceText,sourceName);
121 synchronized(luan) {
122 LuanCloner cloner = new LuanCloner(LuanCloner.Type.INCREMENTAL);
123 LuanState luan = (LuanState)cloner.clone(this.luan);
124 return fn.call(luan);
125 }
126 } 207 }
127 208
128 public void eval_in_root(String text) throws LuanException { 209 public void eval_in_root(String text) throws LuanException {
129 LuanState luan; 210 Instance newInstance = this.instance.cloneInstance();
130 synchronized(this.luan) { 211 BasicLuan.load(text,"<eval_in_root>",null).call(newInstance.luan);
131 LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE); 212 this.instance = newInstance;
132 luan = (LuanState)cloner.clone(this.luan);
133 }
134 BasicLuan.load(text,"<eval_in_root>",null).call(luan);
135 this.luan = luan;
136 } 213 }
137 214
138 public static void start(Server server) throws Exception { 215 public static void start(Server server) throws Exception {
139 try { 216 try {
140 server.start(); 217 server.start();