From dev-return-188084-archive-asf-public=cust-asf.ponee.io@tomcat.apache.org Tue Jan 9 22:50:51 2018 Return-Path: X-Original-To: archive-asf-public@eu.ponee.io Delivered-To: archive-asf-public@eu.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by mx-eu-01.ponee.io (Postfix) with ESMTP id B111E180718 for ; Tue, 9 Jan 2018 22:50:51 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id A0BFD160C2D; Tue, 9 Jan 2018 21:50:51 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id BE909160C17 for ; Tue, 9 Jan 2018 22:50:50 +0100 (CET) Received: (qmail 74274 invoked by uid 500); 9 Jan 2018 21:50:49 -0000 Mailing-List: contact dev-help@tomcat.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "Tomcat Developers List" Delivered-To: mailing list dev@tomcat.apache.org Received: (qmail 74264 invoked by uid 99); 9 Jan 2018 21:50:49 -0000 Received: from Unknown (HELO svn01-us-west.apache.org) (209.188.14.144) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 09 Jan 2018 21:50:49 +0000 Received: from svn01-us-west.apache.org (localhost [127.0.0.1]) by svn01-us-west.apache.org (ASF Mail Server at svn01-us-west.apache.org) with ESMTP id 5CA8B3A0168 for ; Tue, 9 Jan 2018 21:50:47 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1820705 - in /tomcat/trunk/webapps: docs/ examples/WEB-INF/ examples/WEB-INF/classes/async/ Date: Tue, 09 Jan 2018 21:50:45 -0000 To: dev@tomcat.apache.org From: markt@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20180109215048.5CA8B3A0168@svn01-us-west.apache.org> Author: markt Date: Tue Jan 9 21:50:44 2018 New Revision: 1820705 URL: http://svn.apache.org/viewvc?rev=1820705&view=rev Log: Prevent NullPointerException and other errors if the stock ticker example is running when the examples web application is stopped. Added: tomcat/trunk/webapps/examples/WEB-INF/classes/async/AsyncStockContextListener.java (with props) Modified: tomcat/trunk/webapps/docs/changelog.xml tomcat/trunk/webapps/examples/WEB-INF/classes/async/AsyncStockServlet.java tomcat/trunk/webapps/examples/WEB-INF/classes/async/Stockticker.java tomcat/trunk/webapps/examples/WEB-INF/web.xml Modified: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1820705&r1=1820704&r2=1820705&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Tue Jan 9 21:50:44 2018 @@ -183,6 +183,11 @@ application. (markt) + 61886: Prevent NullPointerException and other + errors if the stock ticker example is running when the examples web + application is stopped. (markt) + + 61910: Clarify the meaning of the allowLinking option in the documentation web application. (markt) Added: tomcat/trunk/webapps/examples/WEB-INF/classes/async/AsyncStockContextListener.java URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/async/AsyncStockContextListener.java?rev=1820705&view=auto ============================================================================== --- tomcat/trunk/webapps/examples/WEB-INF/classes/async/AsyncStockContextListener.java (added) +++ tomcat/trunk/webapps/examples/WEB-INF/classes/async/AsyncStockContextListener.java Tue Jan 9 21:50:44 2018 @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 async; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +/* + * Ensures the Stockticker is shut down cleanly when the context stops. This + * also covers the case when the server shuts down. + */ +public class AsyncStockContextListener implements ServletContextListener { + + public static final String STOCK_TICKER_KEY = "StockTicker"; + + @Override + public void contextInitialized(ServletContextEvent sce) { + Stockticker stockticker = new Stockticker(); + ServletContext sc = sce.getServletContext(); + sc.setAttribute(STOCK_TICKER_KEY, stockticker); + } + + @Override + public void contextDestroyed(ServletContextEvent sce) { + ServletContext sc = sce.getServletContext(); + Stockticker stockticker = (Stockticker) sc.getAttribute(STOCK_TICKER_KEY); + stockticker.shutdown(); + } +} Propchange: tomcat/trunk/webapps/examples/WEB-INF/classes/async/AsyncStockContextListener.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/trunk/webapps/examples/WEB-INF/classes/async/AsyncStockServlet.java URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/async/AsyncStockServlet.java?rev=1820705&r1=1820704&r2=1820705&view=diff ============================================================================== --- tomcat/trunk/webapps/examples/WEB-INF/classes/async/AsyncStockServlet.java (original) +++ tomcat/trunk/webapps/examples/WEB-INF/classes/async/AsyncStockServlet.java Tue Jan 9 21:50:44 2018 @@ -25,6 +25,7 @@ import java.util.concurrent.atomic.Atomi import javax.servlet.AsyncContext; import javax.servlet.AsyncEvent; import javax.servlet.AsyncListener; +import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -45,7 +46,6 @@ public class AsyncStockServlet extends H private static final ConcurrentLinkedQueue clients = new ConcurrentLinkedQueue<>(); private static final AtomicInteger clientcount = new AtomicInteger(0); - private static final Stockticker ticker = new Stockticker(); public AsyncStockServlet() { log.info("AsyncStockServlet created"); @@ -63,6 +63,8 @@ public class AsyncStockServlet extends H resp.setContentType("text/plain"); clients.add(actx); if (clientcount.incrementAndGet()==1) { + Stockticker ticker = (Stockticker) req.getServletContext().getAttribute( + AsyncStockContextListener.STOCK_TICKER_KEY); ticker.addTickListener(this); } } else { @@ -104,8 +106,27 @@ public class AsyncStockServlet extends H @Override + public void shutdown() { + // The web application is shutting down. Complete any AsyncContexts + // associated with an active client. + Iterator it = clients.iterator(); + while (it.hasNext()) { + AsyncContext actx = it.next(); + try { + actx.complete(); + } catch (Exception e) { + // Ignore. The async error handling will deal with this. + } + } + } + + + @Override public void onComplete(AsyncEvent event) throws IOException { if (clients.remove(event.getAsyncContext()) && clientcount.decrementAndGet()==0) { + ServletContext sc = event.getAsyncContext().getRequest().getServletContext(); + Stockticker ticker = (Stockticker) sc.getAttribute( + AsyncStockContextListener.STOCK_TICKER_KEY); ticker.removeTickListener(this); } } Modified: tomcat/trunk/webapps/examples/WEB-INF/classes/async/Stockticker.java URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/async/Stockticker.java?rev=1820705&r1=1820704&r2=1820705&view=diff ============================================================================== --- tomcat/trunk/webapps/examples/WEB-INF/classes/async/Stockticker.java (original) +++ tomcat/trunk/webapps/examples/WEB-INF/classes/async/Stockticker.java Tue Jan 9 21:50:44 2018 @@ -37,6 +37,12 @@ public class Stockticker implements Runn } public synchronized void stop() { + // On context stop this can be called multiple times. + // NO-OP is the ticker thread is not set + // (i.e. stop() has already completed) + if (ticker == null) { + return; + } run = false; try { ticker.join(); @@ -47,6 +53,17 @@ public class Stockticker implements Runn ticker = null; } + public void shutdown() { + // Notify each listener of the shutdown. This enables them to + // trigger any necessary clean-up. + for (TickListener l : listeners) { + l.shutdown(); + } + // Wait for the thread to stop. This prevents warnings in the logs + // that the thread is still active when the context stops. + stop(); + } + public void addTickListener(TickListener listener) { if (listeners.add(listener)) { if (counter.incrementAndGet()==1) start(); @@ -98,6 +115,7 @@ public class Stockticker implements Runn public static interface TickListener { public void tick(Stock stock); + public void shutdown(); } public static final class Stock implements Cloneable { Modified: tomcat/trunk/webapps/examples/WEB-INF/web.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/web.xml?rev=1820705&r1=1820704&r2=1820705&view=diff ============================================================================== --- tomcat/trunk/webapps/examples/WEB-INF/web.xml (original) +++ tomcat/trunk/webapps/examples/WEB-INF/web.xml Tue Jan 9 21:50:44 2018 @@ -95,6 +95,11 @@ listeners.SessionListener + + + async.AsyncStockContextListener + + --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org For additional commands, e-mail: dev-help@tomcat.apache.org