ThreadUtil.java

1
/*******************************************************************************
2
 * Copyhacked (H) 2012-2025.
3
 * This program and the accompanying materials
4
 * are made available under no term at all, use it like
5
 * you want, but share and discuss it
6
 * every time possible with every body.
7
 * 
8
 * Contributors:
9
 *      ron190 at ymail dot com - initial implementation
10
 ******************************************************************************/
11
package com.jsql.util;
12
13
import com.jsql.model.InjectionModel;
14
import com.jsql.model.bean.database.AbstractElementDatabase;
15
import com.jsql.model.suspendable.AbstractSuspendable;
16
import com.jsql.model.suspendable.callable.ThreadFactoryCallable;
17
import org.apache.logging.log4j.LogManager;
18
import org.apache.logging.log4j.Logger;
19
20
import java.util.HashMap;
21
import java.util.Map;
22
import java.util.concurrent.ConcurrentHashMap;
23
import java.util.concurrent.ExecutorService;
24
import java.util.concurrent.Executors;
25
import java.util.concurrent.TimeUnit;
26
27
/**
28
 * Utility class managing running threads on which the user can act.
29
 * It must be noted that as SwingWorker class are used then only 10 jobs can be run
30
 * at the same time, the 11th will be waiting in the thread pool until one of the 10
31
 * actives one is freed.
32
 */
33
public final class ThreadUtil {
34
    
35
    private static final Logger LOGGER = LogManager.getRootLogger();
36
    
37
    /**
38
     * List of running jobs associated to a database injection task.
39
     * We can interact with those tasks in order to pause/resume and stop the process.
40
     */
41
    // Fix #8258: ConcurrentModificationException on java.util.HashMap$ValueIterator.next()
42
    private final Map<AbstractElementDatabase, AbstractSuspendable> suspendables = new ConcurrentHashMap<>(new HashMap<>());
43
44
    private final InjectionModel injectionModel;
45
    
46
    public ThreadUtil(InjectionModel injectionModel) {
47
        this.injectionModel = injectionModel;
48
    }
49
50
    /**
51
     * Add a job to the list of ongoing tasks. It is used to allow the user to act
52
     * on the job and stop/pause a running process.
53
     * @param elementDatabase component associated to the active job
54
     * @param suspendable active job to act on
55
     */
56
    public void put(AbstractElementDatabase elementDatabase, AbstractSuspendable suspendable) {
57
        this.suspendables.put(elementDatabase, suspendable);
58
    }
59
    
60
    /**
61
     * Get the task associated to the database component.
62
     * It's usually done to act on the task like stop/pause the corresponding process, or
63
     * to check the status of the job.
64
     * @param elementDatabase component associated to the active job
65
     * @return job currently running
66
     */
67
    public AbstractSuspendable get(AbstractElementDatabase elementDatabase) {
68 1 1. get : replaced return value with null for com/jsql/util/ThreadUtil::get → NO_COVERAGE
        return this.suspendables.get(elementDatabase);
69
    }
70
    
71
    /**
72
     * Remove the thread corresponding to the component in order to be
73
     * garbage collected. The thread should be stopped prior the deletion.
74
     * @param elementDatabase component associated to thread
75
     */
76
    public void remove(AbstractElementDatabase elementDatabase) {
77
        this.suspendables.remove(elementDatabase);
78
    }
79
    
80
    /**
81
     * Force to stop every threads still running and empty the list where
82
     * they were instantiated in order to be garbage collected.
83
     */
84
    public void reset() {
85 1 1. reset : removed call to java/util/Collection::forEach → NO_COVERAGE
        this.suspendables.values().forEach(AbstractSuspendable::stop);
86 1 1. reset : removed call to java/util/Map::clear → NO_COVERAGE
        this.suspendables.clear();
87
    }
88
    
89
    public ExecutorService getExecutor(String nameThread) {
90
        ExecutorService taskExecutor;
91
        
92 1 1. getExecutor : negated conditional → NO_COVERAGE
        if (this.injectionModel.getMediatorUtils().getPreferencesUtil().isLimitingThreads()) {
93
            int countThreads = this.injectionModel.getMediatorUtils().getPreferencesUtil().countLimitingThreads();
94
            taskExecutor = Executors.newFixedThreadPool(countThreads, new ThreadFactoryCallable(nameThread));
95
        } else {
96
            taskExecutor = Executors.newCachedThreadPool(new ThreadFactoryCallable(nameThread));
97
        }
98 1 1. getExecutor : replaced return value with null for com/jsql/util/ThreadUtil::getExecutor → NO_COVERAGE
        return taskExecutor;
99
    }
100
101
    public void shutdown(ExecutorService taskExecutor) {
102
        int timeout = 15;
103 1 1. shutdown : negated conditional → NO_COVERAGE
        if (this.injectionModel.getMediatorUtils().getPreferencesUtil().isConnectionTimeout()) {
104
            timeout = this.injectionModel.getMediatorUtils().getPreferencesUtil().countConnectionTimeout();
105
        }
106
107
        try {
108 1 1. shutdown : removed call to java/util/concurrent/ExecutorService::shutdown → NO_COVERAGE
            taskExecutor.shutdown();
109 1 1. shutdown : negated conditional → NO_COVERAGE
            if (!taskExecutor.awaitTermination(timeout, TimeUnit.SECONDS)) {
110
                taskExecutor.shutdownNow();
111
            }
112
        } catch (InterruptedException e) {
113
            LOGGER.log(LogLevelUtil.IGNORE, e, e);
114 1 1. shutdown : removed call to java/lang/Thread::interrupt → NO_COVERAGE
            Thread.currentThread().interrupt();
115
        }
116
    }
117
}

Mutations

68

1.1
Location : get
Killed by : none
replaced return value with null for com/jsql/util/ThreadUtil::get → NO_COVERAGE

85

1.1
Location : reset
Killed by : none
removed call to java/util/Collection::forEach → NO_COVERAGE

86

1.1
Location : reset
Killed by : none
removed call to java/util/Map::clear → NO_COVERAGE

92

1.1
Location : getExecutor
Killed by : none
negated conditional → NO_COVERAGE

98

1.1
Location : getExecutor
Killed by : none
replaced return value with null for com/jsql/util/ThreadUtil::getExecutor → NO_COVERAGE

103

1.1
Location : shutdown
Killed by : none
negated conditional → NO_COVERAGE

108

1.1
Location : shutdown
Killed by : none
removed call to java/util/concurrent/ExecutorService::shutdown → NO_COVERAGE

109

1.1
Location : shutdown
Killed by : none
negated conditional → NO_COVERAGE

114

1.1
Location : shutdown
Killed by : none
removed call to java/lang/Thread::interrupt → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.19.1