/* * Copyright 2010 Richard Zschech. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package net.zschech.gwt.comet.server.impl; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import javax.servlet.ServletContext; import javax.servlet.ServletException; /** * A non-blocking (does not block HTTP request threads) implementation for AsyncServlet. * * Requires a scheduler for sending heart beats and keeping sessions alive. * * @author Richard Zschech */ public abstract class NonBlockingAsyncServlet extends AsyncServlet { private ScheduledExecutorService scheduledExecutor; @Override protected void init(ServletContext context) throws ServletException { super.init(context); scheduledExecutor = new RemoveOnCancelScheduledThreadPoolExecutor(1, new ThreadFactory() { @Override public Thread newThread(Runnable runnable) { String name = getServletContext().getServletContextName(); if (name == null || name.isEmpty()) { name = getServletContext().getContextPath(); } return new Thread(runnable, "gwt-comet " + name); } }); } @Override protected void shutdown() { scheduledExecutor.shutdown(); } protected ScheduledExecutorService getScheduledExecutor() { return scheduledExecutor; } @Override public ScheduledFuture<?> scheduleHeartbeat(final CometServletResponseImpl response, CometSessionImpl session) { assert Thread.holdsLock(response); return scheduledExecutor.schedule(new Runnable() { @Override public void run() { response.tryHeartbeat(); } }, response.getHeartbeat(), TimeUnit.MILLISECONDS); } @Override public ScheduledFuture<?> scheduleSessionKeepAlive(final CometServletResponseImpl response, final CometSessionImpl session) { assert Thread.holdsLock(response); try { long keepAliveTime = session.getKeepAliveScheduleTime(); if (keepAliveTime == Long.MAX_VALUE) { return null; } else { if (keepAliveTime <= 0) { if (!access(session.getHttpSession())) { response.tryTerminate(); return null; } } return scheduledExecutor.schedule(new Runnable() { @Override public void run() { if (!access(session.getHttpSession())) { response.tryTerminate(); } session.setLastAccessedTime(); response.scheduleSessionKeepAlive(); } }, keepAliveTime, TimeUnit.MILLISECONDS); } } catch (IllegalStateException e) { // the session has been invalidated response.tryTerminate(); return null; } } }