view src/luan/lib/webserver/handlers/DomainHandler.java @ 1400:221eedb0f54e

fix inner class gc bug
author Franklin Schmidt <fschmidt@gmail.com>
date Fri, 13 Sep 2019 05:05:51 -0600
parents 643cf1c37723
children ef1620aa99cb
line wrap: on
line source

package luan.lib.webserver.handlers;

import java.io.Closeable;
import java.io.IOException;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.ref.SoftReference;
import java.lang.ref.ReferenceQueue;
import java.util.Map;
import java.util.HashMap;
import luan.lib.logging.Logger;
import luan.lib.logging.LoggerFactory;
import luan.lib.webserver.Handler;
import luan.lib.webserver.Request;
import luan.lib.webserver.Response;


public final class DomainHandler implements Handler {
	private static final Logger logger = LoggerFactory.getLogger(DomainHandler.class);

	public interface Factory {
		public Handler newHandler(String domain);
	}

	private static class Ref {
		private final Handler handler;

		private Ref(Handler handler) {
			this.handler = handler;
		}
	}

	private final ReferenceQueue<Ref> queue = new ReferenceQueue<Ref>();

	private class MyReference extends WeakReference<Ref> {
		private Handler handler;

		private MyReference(Ref r) {
			super(r,queue);
			this.handler = r.handler;
		}
	}

	private static void close(Handler handler) {
		if( handler instanceof Closeable ) {
			try {
				((Closeable)handler).close();
			} catch(IOException e) {
				logger.error(handler.toString(),e);
			}
		}
	}

	private void sweep() {
		while(true) {
			MyReference ref = (MyReference)queue.poll();
			if( ref == null )
				return;
			//logger.info("sweep");
			close(ref.handler);
			ref.handler = null;
		}
	}

	private final Map<String,MyReference> map = new HashMap<String,MyReference>();

	private final Factory factory;

	public DomainHandler(Factory factory) {
		this.factory = factory;
	}

	public Response handle(Request request) {
		String host = (String)request.headers.get("host");
		if( host == null )
			return null;
		int i = host.indexOf(':');
		String domain = i == -1 ? host : host.substring(0,i);
		Handler handler = getHandler(domain);
		return handler==null ? null : handler.handle(request);
	}

	public Handler getHandler(String domain) {
		Ref r = getRef(domain);
		return r==null ? null : r.handler;
	}

	public void removeHandler(String domain) {
		domain = domain.toLowerCase();
		synchronized(map) {
			Reference<Ref> ref = map.remove(domain);
			Ref r = ref==null ? null : ref.get();
			if( r != null ) {
				close(r.handler);
			}
		}
	}

	private Ref getRef(String domain) {
		domain = domain.toLowerCase();
		synchronized(map) {
			Reference<Ref> ref = map.get(domain);
			Ref r = ref==null ? null : ref.get();
			if( r == null ) {
				//if(ref!=null) logger.info("gc "+domain);
				sweep();
				Handler handler = factory.newHandler(domain);
				if( handler == null )
					return null;
				r = new Ref(handler);
				map.put(domain,new MyReference(r));
			}
			return r;
		}
	}

}