/* * Copyright 2007 - 2017 the original author or authors. * * 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.sf.jailer.util; import java.sql.Statement; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.log4j.Logger; /** * Handles cancellation request of the user and cancels database requests. * * @author Ralf Wisser */ public class CancellationHandler { /** * Contexts for which user have requested cancellation. */ private static Set<Object> cancelled = new HashSet<Object>(); /** * List of all currently running statements per context. */ private static Map<Object, List<Statement>> currentStatements = new HashMap<Object, List<Statement>>(); /** * The logger. */ private static final Logger _log = Logger.getLogger(JobManager.class); /** * Default context */ private static final Object DEFAULT_CONTEXT = new Object(); /** * Resets the handler. * * @param context cancellation context, <code>null</code> for default context */ public static synchronized void reset(Object context) { cancelled.remove(context == null? DEFAULT_CONTEXT : context); currentStatements.remove(context == null? DEFAULT_CONTEXT : context); } /** * Requests cancellation. * * @param context cancellation context, <code>null</code> for default context */ public static void cancel(Object context) { _log.warn("cancellation request received"); synchronizedCancel(context); } /** * Requests cancellation without logging. * * @param context cancellation context, <code>null</code> for default context */ public static void cancelSilently(Object context) { synchronizedCancel(context); } /** * Requests cancellation. * * @param context cancellation context, <code>null</code> for default context */ private static synchronized void synchronizedCancel(Object context) { cancelled.add(context == null? DEFAULT_CONTEXT : context); if (currentStatements.containsKey(context == null? DEFAULT_CONTEXT : context)) { final List<Statement> toBeCanceled = new ArrayList<Statement>(currentStatements.get(context == null? DEFAULT_CONTEXT : context)); currentStatements.remove(context == null? DEFAULT_CONTEXT : context); for (final Statement statement: toBeCanceled) { new Thread(new Runnable() { @Override public void run() { try { statement.cancel(); } catch (Exception e) { // ignore } } }).start(); } } } /** * Indicates that a statement is going to be executed. * * @param context cancellation context, <code>null</code> for default context * @param statement the statement */ public static synchronized void begin(Statement statement, Object context) { checkForCancellation(context); List<Statement> sl = currentStatements.get(context == null? DEFAULT_CONTEXT : context); if (sl == null) { sl = new ArrayList<Statement>(); currentStatements.put(context == null? DEFAULT_CONTEXT : context, sl); } sl.add(statement); } /** * Indicates that a statement has been executed. * * @param statement the statement * @param context cancellation context, <code>null</code> for default context */ public static synchronized void end(Statement statement, Object context) { if (currentStatements.containsKey(context == null? DEFAULT_CONTEXT : context)) { currentStatements.get(context == null? DEFAULT_CONTEXT : context).remove(statement); } } /** * Checks for cancellation. * * @param context cancellation context, <code>null</code> for default context * @throws CancellationException if cancellation have been requested */ public static synchronized void checkForCancellation(Object context) throws CancellationException { if (cancelled.contains(context == null? DEFAULT_CONTEXT : context)) { throw new CancellationException(); } } }