diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/servlets/CallbackServlet.java b/ganttzk/src/main/java/org/zkoss/ganttz/servlets/CallbackServlet.java index a0eecef99..9706a8145 100644 --- a/ganttzk/src/main/java/org/zkoss/ganttz/servlets/CallbackServlet.java +++ b/ganttzk/src/main/java/org/zkoss/ganttz/servlets/CallbackServlet.java @@ -21,6 +21,7 @@ package org.zkoss.ganttz.servlets; import java.io.IOException; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.Map.Entry; @@ -29,6 +30,7 @@ import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; import javax.servlet.ServletConfig; import javax.servlet.ServletException; @@ -51,12 +53,9 @@ public class CallbackServlet extends HttpServlet { // minute // minutes - private static final long EXPIRATION_TIME_MILLIS = 1000 * 60 * 2; // two - // minutes - private static Random random = new Random(); - private static ConcurrentMap handlersCallbacks = new ConcurrentHashMap(); + private static ConcurrentMap handlersCallbacks = new ConcurrentHashMap(); private static Timer cleaningTimer = new Timer(true); @@ -66,32 +65,105 @@ public class CallbackServlet extends HttpServlet { IOException; } - private static class HandlerWithRegisterTime { - private final IServletRequestHandler handler; - private final long creationTime; + public enum DisposalMode { + WHEN_NO_LONGER_REFERENCED { + @Override + public IHandler create(IServletRequestHandler handler) { + return new WeakReferencedHandler(handler); + } + }, + AFTER_TEN_MINUTES { + @Override + public IHandler create(IServletRequestHandler handler) { + return new BasedOnExpirationTimeHandler(handler, + tenMinutesInMillis); + } + }; - public HandlerWithRegisterTime(IServletRequestHandler handler) { + private static final long tenMinutesInMillis = TimeUnit.MILLISECONDS + .convert(10, TimeUnit.MINUTES); + + public abstract IHandler create( + IServletRequestHandler handler); + } + + private interface IHandler { + + abstract boolean hasExpired(); + + abstract IServletRequestHandler getHandler(); + } + + private static class BasedOnExpirationTimeHandler implements IHandler { + + private IServletRequestHandler handler; + + private final long creationTime; + private final long expirationTimeMilliseconds; + + public BasedOnExpirationTimeHandler(IServletRequestHandler handler, + long expirationTimeMilliseconds) { Validate.notNull(handler); this.handler = handler; this.creationTime = System.currentTimeMillis(); + this.expirationTimeMilliseconds = expirationTimeMilliseconds; } - boolean hasExpired() { - return System.currentTimeMillis() - creationTime > EXPIRATION_TIME_MILLIS; + @Override + public IServletRequestHandler getHandler() { + return handler; } + + @Override + public boolean hasExpired() { + return System.currentTimeMillis() - creationTime > expirationTimeMilliseconds; + } + } + + private static class WeakReferencedHandler implements IHandler { + + private final WeakReference handler; + + WeakReferencedHandler(IServletRequestHandler handler) { + this.handler = new WeakReference(handler); + } + + @Override + public boolean hasExpired() { + return handler.get() == null; + } + + @Override + public IServletRequestHandler getHandler() { + return handler.get(); + } + } public static String registerAndCreateURLFor(HttpServletRequest request, IServletRequestHandler handler) { - return registerAndCreateURLFor(request, handler, true); + return registerAndCreateURLFor(request, handler, + DisposalMode.AFTER_TEN_MINUTES); + } + + public static String registerAndCreateURLFor(HttpServletRequest request, + IServletRequestHandler handler, DisposalMode disposalMode) { + return registerAndCreateURLFor(request, handler, true, disposalMode); } public static String registerAndCreateURLFor(HttpServletRequest request, IServletRequestHandler handler, boolean withContextPath) { + return registerAndCreateURLFor(request, handler, withContextPath, + DisposalMode.AFTER_TEN_MINUTES); + } + + public static String registerAndCreateURLFor(HttpServletRequest request, + IServletRequestHandler handler, boolean withContextPath, + DisposalMode disposalMode) { + Validate.notNull(disposalMode); // theoretically could be an infinite loop, could be improved. String generatedKey = ""; - HandlerWithRegisterTime toBeRegistered = new HandlerWithRegisterTime( - handler); + IHandler toBeRegistered = disposalMode.create(handler); do { generatedKey = generateKey(); } while (handlersCallbacks.putIfAbsent(generatedKey, toBeRegistered) != null); @@ -127,10 +199,10 @@ public class CallbackServlet extends HttpServlet { } private static List findExpired() { - ArrayList> handlersList = new ArrayList>( + ArrayList> handlersList = new ArrayList>( handlersCallbacks.entrySet()); List expired = new ArrayList(); - for (Entry entry : handlersList) { + for (Entry entry : handlersList) { if (entry.getValue().hasExpired()) { expired.add(entry.getKey()); } @@ -171,8 +243,8 @@ public class CallbackServlet extends HttpServlet { } private IServletRequestHandler handlerFor(String callbackId) { - HandlerWithRegisterTime h = handlersCallbacks.get(callbackId); - return h != null ? h.handler : null; + IHandler h = handlersCallbacks.get(callbackId); + return h != null ? h.getHandler() : null; } }