a little bit documentation
[cdmlib.git] / cdmlib-remote / src / main / java / eu / etaxonomy / cdm / remote / controller / ProgressMonitorController.java
1 // $Id$
2 /**
3 * Copyright (C) 2012 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
6 *
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
9 */
10 package eu.etaxonomy.cdm.remote.controller;
11
12 import java.io.IOException;
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.UUID;
18
19 import javax.servlet.http.HttpServletRequest;
20 import javax.servlet.http.HttpServletResponse;
21
22 import org.apache.commons.io.FileUtils;
23 import org.apache.commons.io.FilenameUtils;
24 import org.springframework.stereotype.Controller;
25 import org.springframework.web.bind.WebDataBinder;
26 import org.springframework.web.bind.annotation.InitBinder;
27 import org.springframework.web.bind.annotation.PathVariable;
28 import org.springframework.web.bind.annotation.RequestMapping;
29 import org.springframework.web.bind.annotation.RequestMethod;
30 import org.springframework.web.servlet.ModelAndView;
31
32 import eu.etaxonomy.cdm.common.monitor.IRestServiceProgressMonitor;
33 import eu.etaxonomy.cdm.remote.editor.UUIDPropertyEditor;
34
35 /**
36 * @author Andreas Kohlbecker
37 * @date Jul 16, 2012
38 *
39 */
40 @Controller
41 @RequestMapping(value="/progress/")
42 public class ProgressMonitorController {
43
44 private Map<UUID, IRestServiceProgressMonitor> monitors = new HashMap<UUID, IRestServiceProgressMonitor>();
45
46 private Map<UUID, Long> timeoutMap = new HashMap<UUID, Long>();
47
48 private Thread cleanUpThread = null;
49
50 /**
51 * Time out in minutes for monitors which are done.
52 * A monitor which is set done will be removed after this interval.
53 */
54 private int cleanUpTimeout = 1;
55
56 /**
57 *
58 */
59 private int cleanUpInterval = 1000 * 10; // 10 seconds
60
61 @InitBinder
62 public void initBinder(WebDataBinder binder) {
63 binder.registerCustomEditor(UUID.class, new UUIDPropertyEditor());
64 }
65
66 public ProgressMonitorController(){
67
68 this.cleanUpThread = new Thread(){
69
70 public void run() {
71 scheduledCeanUp();
72 try {
73 sleep(cleanUpInterval);
74 } catch (InterruptedException e) {
75 /* IGNORE */
76 }
77 run();
78 }
79
80 };
81 cleanUpThread.start();
82 }
83
84
85 /**
86 * run every n minutes clean up monitors which have been marked done x minutes ago
87 */
88 private void scheduledCeanUp() {
89
90 List<UUID> timedOutMonitors = new ArrayList<UUID>();
91 IRestServiceProgressMonitor monitor;
92
93 long now = System.currentTimeMillis();
94 long nextTimeout = now + cleanUpTimeout * 1000 * 60;
95
96
97 // add monitors which are stopped or done to the timeoutMap
98 for(UUID uuid : monitors.keySet()){
99 monitor = monitors.get(uuid);
100 if((monitor.isFailed() || monitor.isDone())){
101 if(!timeoutMap.containsKey(uuid)){
102 timeoutMap.put(uuid, nextTimeout);
103 }
104 }
105 }
106
107 // check with monitor has timed out
108 for(UUID uuid : timeoutMap.keySet()){
109 if(timeoutMap.get(uuid) <= now){
110 timedOutMonitors.add(uuid);
111 }
112 }
113
114 //finally remove the monitors
115 for(UUID uuid : timedOutMonitors){
116 timeoutMap.remove(uuid);
117 monitors.remove(uuid);
118 }
119
120 }
121
122 public UUID registerMonitor(IRestServiceProgressMonitor monitor){
123 UUID uuid = UUID.randomUUID();
124 monitors.put(uuid, monitor);
125 return uuid;
126 }
127
128 public IRestServiceProgressMonitor getMonitor(UUID uuid) {
129 return monitors.get(uuid);
130 }
131
132 /**
133 * returns true if the {@link IRestServiceProgressMonitor} identified by the <code>uuid</code>
134 * exists and if it is still indicating a running thread
135 * @param uuid
136 * @return
137 */
138 public boolean isMonitorRunning(UUID uuid) {
139 IRestServiceProgressMonitor monitor = getMonitor(uuid);
140 return monitor != null && !monitor.isCanceled() && !monitor.isDone() && !monitor.isFailed();
141 }
142
143 /**
144 * @param request the request for which to create he path for, is needed to read the file extension from.
145 * @param uuid the uuid key of the monitor
146 * @return
147 */
148 public String pathFor(HttpServletRequest request, UUID uuid){
149 String fileExtension = FilenameUtils.getExtension(request.getServletPath());
150 return "/progress/" + uuid.toString() + (fileExtension.length() > 0 ? '.': "") + fileExtension;
151 }
152
153 @RequestMapping(value = "{uuid}", method = RequestMethod.GET)
154 public ModelAndView doProgressMonitor(@PathVariable("uuid") UUID uuid, HttpServletRequest request, HttpServletResponse response)
155 throws IOException {
156
157 ModelAndView mv = new ModelAndView();
158
159 if (monitors.containsKey(uuid)) {
160 mv.addObject(monitors.get(uuid));
161 } else {
162 response.sendError(404, "No such progress monitor found. The process being monitored may have been completed and the according monitor may have been removed due to the clean up timepout.");
163 }
164
165 return mv;
166 }
167 }