Merge branch 'develop' of ssh://dev.e-taxonomy.eu/var/git/cdmlib into develop
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / service / ProgressMonitorManager.java
1 /**
2 * Copyright (C) 2015 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.cdm.api.service;
10
11 import java.util.ArrayList;
12 import java.util.HashMap;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.UUID;
16 import java.util.concurrent.ConcurrentHashMap;
17
18 import org.springframework.stereotype.Component;
19
20 import eu.etaxonomy.cdm.common.monitor.IRestServiceProgressMonitor;
21 import eu.etaxonomy.cdm.common.monitor.RemotingProgressMonitorThread;
22
23 /**
24 * Manages monitors for long running jobs.
25 *
26 * @author cmathew
27 * @since 14 Oct 2015
28 *
29 */
30 @Component
31 public class ProgressMonitorManager<T extends IRestServiceProgressMonitor> {
32
33 private final Map<UUID, T> monitors = new ConcurrentHashMap<UUID, T>();
34 private final Map<UUID, RemotingProgressMonitorThread> threads = new ConcurrentHashMap<>();
35
36
37 private final Map<UUID, Long> timeoutMap = new HashMap<UUID, Long>();
38
39 private Thread cleanUpThread = null;
40
41 /**
42 * Time out in minutes for monitors which are done.
43 * A monitor which is set done will be removed after this interval.
44 */
45 private final int cleanUpTimeout = 1;
46
47 /**
48 *
49 */
50 private final int cleanUpInterval = 1000 * 10; // 10 seconds
51
52 public ProgressMonitorManager() {
53
54 this.cleanUpThread = new Thread(){
55
56 @Override
57 public void run() {
58 while(true){
59 scheduledCleanUp();
60 try {
61 sleep(cleanUpInterval);
62 } catch (InterruptedException e) {
63 /* IGNORE */
64 System.err.println("interrupted");
65 }
66 }
67 }
68
69 };
70 cleanUpThread.start();
71 }
72
73 /**
74 * run every n minutes clean up monitors which have been marked done x minutes ago
75 */
76 private void scheduledCleanUp() {
77
78 List<UUID> timedOutMonitors = new ArrayList<UUID>();
79 IRestServiceProgressMonitor monitor;
80
81 long now = System.currentTimeMillis();
82 long nextTimeout = now + cleanUpTimeout * 1000 * 60;
83
84
85 // add monitors which are stopped or done to the timeoutMap
86 for(UUID uuid : monitors.keySet()){
87 monitor = monitors.get(uuid);
88 if((monitor.isFailed() || monitor.isDone())){
89 if(!timeoutMap.containsKey(uuid)){
90 timeoutMap.put(uuid, nextTimeout);
91 }
92 }
93 if(monitor.hasFeedbackWaitTimedOut()) {
94 monitor.interrupt();
95 threads.get(uuid).interrupt();
96 }
97 }
98
99 // check with monitor has timed out
100 for(UUID uuid : timeoutMap.keySet()){
101 if(timeoutMap.get(uuid) <= now){
102 timedOutMonitors.add(uuid);
103 }
104 }
105
106 //finally remove the monitors
107 for(UUID uuid : timedOutMonitors){
108 timeoutMap.remove(uuid);
109 monitors.remove(uuid);
110 threads.remove(uuid);
111
112 }
113
114 }
115
116 /**
117 * @return the threads
118 */
119 public RemotingProgressMonitorThread getThread(UUID uuid) {
120 return threads.get(uuid);
121 }
122
123
124 public UUID registerMonitor(T monitor, RemotingProgressMonitorThread thread){
125 UUID uuid = UUID.randomUUID();
126 monitors.put(uuid, monitor);
127 threads.put(uuid, thread);
128 return uuid;
129 }
130 public UUID registerMonitor(T monitor){
131 UUID uuid = UUID.randomUUID();
132 monitors.put(uuid, monitor);
133
134 return uuid;
135 }
136
137 public IRestServiceProgressMonitor getMonitor(UUID uuid) {
138 if(uuid == null) {
139 return null;
140 }
141 return monitors.get(uuid);
142 }
143
144 /**
145 * returns true if the {@link IRestServiceProgressMonitor} identified by the <code>uuid</code>
146 * exists and if it is still indicating a running thread
147 * @param uuid
148 * @return
149 */
150 public boolean isMonitorRunning(UUID uuid) {
151 IRestServiceProgressMonitor monitor = getMonitor(uuid);
152 return monitor != null && !monitor.isCanceled() && !monitor.isDone() && !monitor.isFailed();
153 }
154
155 public Map<UUID, T> getMonitors() {
156 return monitors;
157 }
158
159 }