View Javadoc
1   /*******************************************************************************
2    * Copyhacked (H) 2012-2020.
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 about 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      /**
36       * Log4j logger sent to view.
37       */
38      private static final Logger LOGGER = LogManager.getRootLogger();
39      
40      /**
41       * List of running jobs associated to a database injection task.
42       * We can interact with those tasks in order to pause/resume and stop the process.
43       */
44      // Fix #8258: ConcurrentModificationException on java.util.HashMap$ValueIterator.next()
45      private final Map<AbstractElementDatabase, AbstractSuspendable> suspendables = new ConcurrentHashMap<>(new HashMap<>());
46  
47      private final InjectionModel injectionModel;
48      
49      public ThreadUtil(InjectionModel injectionModel) {
50          this.injectionModel = injectionModel;
51      }
52  
53      /**
54       * Add a job to the list of ongoing tasks. It is used to allow the user to act
55       * on the job and stop/pause a running process.
56       * @param elementDatabase component associated to the active job
57       * @param suspendable active job to act on
58       */
59      public void put(AbstractElementDatabase elementDatabase, AbstractSuspendable suspendable) {
60          this.suspendables.put(elementDatabase, suspendable);
61      }
62      
63      /**
64       * Get the task associated to the database component.
65       * It's usually done to act on the task like stop/pause the corresponding process, or
66       * to check the status of the job.
67       * @param elementDatabase component associated to the active job
68       * @return job currently running
69       */
70      public AbstractSuspendable get(AbstractElementDatabase elementDatabase) {
71          return this.suspendables.get(elementDatabase);
72      }
73      
74      /**
75       * Remove the thread corresponding to the component in order to be
76       * garbage collected. The thread should be stopped prior the deletion.
77       * @param elementDatabase component associated to thread
78       */
79      public void remove(AbstractElementDatabase elementDatabase) {
80          this.suspendables.remove(elementDatabase);
81      }
82      
83      /**
84       * Force to stop every threads still running and empty the list where
85       * they were instantiated in order to be garbage collected.
86       */
87      public void reset() {
88          
89          this.suspendables.values().forEach(AbstractSuspendable::stop);
90          this.suspendables.clear();
91      }
92      
93      public ExecutorService getExecutor(String nameThread) {
94  
95          ExecutorService taskExecutor;
96          
97          if (this.injectionModel.getMediatorUtils().getPreferencesUtil().isLimitingThreads()) {
98              
99              int countThreads = this.injectionModel.getMediatorUtils().getPreferencesUtil().countLimitingThreads();
100             taskExecutor = Executors.newFixedThreadPool(countThreads, new ThreadFactoryCallable(nameThread));
101             
102         } else {
103             taskExecutor = Executors.newCachedThreadPool(new ThreadFactoryCallable(nameThread));
104         }
105         
106         return taskExecutor;
107     }
108 
109     public void shutdown(ExecutorService taskExecutor) {
110 
111         int timeout = 15;
112         if (this.injectionModel.getMediatorUtils().getPreferencesUtil().isConnectionTimeout()) {
113             timeout = this.injectionModel.getMediatorUtils().getPreferencesUtil().countConnectionTimeout();
114         }
115 
116         try {
117             taskExecutor.shutdown();
118             if (!taskExecutor.awaitTermination(timeout, TimeUnit.SECONDS)) {
119                 taskExecutor.shutdownNow();
120             }
121         } catch (InterruptedException e) {
122 
123             LOGGER.log(LogLevelUtil.IGNORE, e, e);
124             Thread.currentThread().interrupt();
125         }
126     }
127 }