1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package ch.elca.el4j.coberturaruntime;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.text.SimpleDateFormat;
22 import java.util.ArrayList;
23 import java.util.Date;
24 import java.util.List;
25
26 import net.sourceforge.cobertura.coveragedata.CoverageDataFileHandler;
27 import net.sourceforge.cobertura.coveragedata.ProjectData;
28 import net.sourceforge.cobertura.reporting.Main;
29 import net.sourceforge.cobertura.util.ConfigurationUtil;
30
31 import org.codehaus.plexus.util.FileUtils;
32 import org.springframework.util.FileCopyUtils;
33 import org.springframework.util.StringUtils;
34
35 import ch.elca.el4j.util.codingsupport.annotations.FindBugsSuppressWarnings;
36
37
38
39
40
41
42
43
44 public class CoberturaRuntimeControllerImpl implements CoberturaRuntimeController {
45
46
47
48 public static final String COBERTURA_RUNTIME_DATA_DIRECTORY = "cobertura-runtime.dataDirectory";
49
50
51
52
53 public static final String COBERTURA_RUNTIME_DATA_FILENAME = "cobertura-runtime.dataFilename";
54
55
56
57
58 public static final String COBERTURA_RUNTIME_SRC_COL_DIR_NAME = "cobertura-runtime.sourceCollectorDirectoryName";
59
60
61
62
63 public static final String COBERTURA_RUNTIME_KEEP_REPORTS = "cobertura-runtime.keepReports";
64
65
66
67
68 protected final File m_coberturaDataDirectory;
69
70
71
72
73 protected final String m_coberturaDataFilename;
74
75
76
77
78 protected final File m_coberturaCollectedSourcesDirectory;
79
80
81
82
83 protected final boolean m_keepReports;
84
85
86
87
88 protected final boolean m_isOfflineMode;
89
90
91
92
93 private boolean m_isRecordingData = true;
94
95
96
97
98 private File m_coberturaDataFile;
99
100
101
102
103 public CoberturaRuntimeControllerImpl() {
104 this(false);
105 }
106
107
108
109
110
111
112 public CoberturaRuntimeControllerImpl(boolean offlineMode) {
113 ConfigurationUtil config = new ConfigurationUtil();
114
115
116 String path = config.getProperty(COBERTURA_RUNTIME_DATA_DIRECTORY, null);
117 if (!StringUtils.hasText(path)) {
118 throw new RuntimeException("Property '" + COBERTURA_RUNTIME_DATA_DIRECTORY + "' is not defined! "
119 + "It should be defined in file 'cobertura.properties'!");
120 }
121 m_coberturaDataDirectory = new File(path);
122
123
124 String dataFilename = config.getProperty(COBERTURA_RUNTIME_DATA_FILENAME, null);
125 if (!StringUtils.hasText(dataFilename)) {
126 throw new RuntimeException("Property '" + COBERTURA_RUNTIME_DATA_FILENAME + "' is not defined! "
127 + "It should be defined in file 'cobertura.properties'!");
128 }
129 m_coberturaDataFilename = dataFilename;
130
131
132 String sourceDir = config.getProperty(COBERTURA_RUNTIME_SRC_COL_DIR_NAME, null);
133 if (!StringUtils.hasText(sourceDir)) {
134 throw new RuntimeException("Property '" + COBERTURA_RUNTIME_SRC_COL_DIR_NAME + "' is not defined! "
135 + "It should be defined in file 'cobertura.properties'!");
136 }
137 m_coberturaCollectedSourcesDirectory = new File(m_coberturaDataDirectory, sourceDir);
138
139
140 String keepReportsString = config.getProperty(COBERTURA_RUNTIME_KEEP_REPORTS, null);
141 if (!StringUtils.hasText(keepReportsString)) {
142 throw new RuntimeException("Property '" + COBERTURA_RUNTIME_KEEP_REPORTS
143 + "' (boolean value) is not defined! "
144 + "It should be defined in file 'cobertura.properties'!");
145 }
146 m_keepReports = Boolean.parseBoolean(keepReportsString);
147
148
149 m_isOfflineMode = offlineMode;
150 m_coberturaDataFile = new File(m_coberturaDataDirectory, m_coberturaDataFilename);
151 if (m_isOfflineMode) {
152 m_isRecordingData = false;
153 CoverageDataFileHandler.loadCoverageData(m_coberturaDataFile);
154 } else {
155 File defaultDataFile = CoverageDataFileHandler.getDefaultDataFile();
156 if (!defaultDataFile.equals(m_coberturaDataFile)) {
157 throw new RuntimeException("The configured '" + m_coberturaDataFile.getAbsolutePath()
158 + "' and the already set cobertura data file path '" + defaultDataFile.getAbsolutePath()
159 + "' are not the same!");
160 }
161 }
162
163 }
164
165
166 public synchronized boolean startRecording() {
167 if (m_isOfflineMode || m_isRecordingData) {
168 return false;
169 }
170
171 flushRecords();
172 try {
173 Thread.sleep(1000);
174 ProjectData coverageData = CoverageDataFileHandler.loadCoverageData(m_coberturaDataFile);
175 setGlobalCoverageDataAndDataFile(coverageData, m_coberturaDataFile);
176 } catch (Exception e) {
177 throw new RuntimeException("Exception while trying to start recording!", e);
178 }
179
180 m_isRecordingData = true;
181 return true;
182 }
183
184
185 @FindBugsSuppressWarnings(value = "REC_CATCH_EXCEPTION",
186 justification = "Don't care which exception occurs, will always throw a Runtime exception.")
187 public synchronized boolean stopRecording() {
188 if (m_isOfflineMode || !m_isRecordingData) {
189 return false;
190 }
191
192 flushRecords();
193 try {
194 Thread.sleep(1000);
195 File tempDataFile = File.createTempFile("cobertura-temp-", ".ser");
196 FileCopyUtils.copy(m_coberturaDataFile, tempDataFile);
197 tempDataFile.deleteOnExit();
198 ProjectData coverageData = CoverageDataFileHandler.loadCoverageData(tempDataFile);
199 setGlobalCoverageDataAndDataFile(coverageData, tempDataFile);
200 } catch (Exception e) {
201 throw new RuntimeException("Exception while trying to stop recording!", e);
202 }
203
204 m_isRecordingData = false;
205 return true;
206 }
207
208
209
210
211
212
213
214
215 protected synchronized void setGlobalCoverageDataAndDataFile(ProjectData coverageData, File coberturaDataFile) {
216
217
218
219
220
221
222
223
224 ProjectData.setGlobalProjectData(coverageData);
225
226
227
228
229
230
231
232
233
234 CoverageDataFileHandler.setDefaultDataFile(coberturaDataFile);
235 }
236
237
238 public synchronized boolean isRecording() {
239 if (m_isOfflineMode) {
240 return false;
241 }
242 return m_isRecordingData;
243 }
244
245
246 public synchronized void flushRecords() {
247 if (m_isOfflineMode) {
248 return;
249 }
250 ProjectData.saveGlobalProjectData();
251 }
252
253
254 public synchronized String getDataFilePath() {
255 return m_coberturaDataFile != null ? m_coberturaDataFile.getAbsolutePath() : "UNKNOWN!";
256 }
257
258
259 public synchronized String generateReport() {
260
261 flushRecords();
262
263
264 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HHmmss");
265 String timestampString = sdf.format(new Date());
266
267
268
269 String reportDirectoryName;
270 if (m_keepReports) {
271 reportDirectoryName = "report-" + timestampString;
272 } else {
273 reportDirectoryName = "report";
274 }
275 File reportDirectory = new File(m_coberturaDataDirectory, reportDirectoryName);
276 String reportDirectoryPath = reportDirectory.getAbsolutePath();
277 if (reportDirectory.exists()) {
278 try {
279 FileUtils.deleteDirectory(reportDirectory);
280 } catch (IOException e) {
281 throw new RuntimeException("Could not delete the old report directory '"
282 + reportDirectoryPath + "'!", e);
283 }
284 }
285 if (!reportDirectory.mkdirs()) {
286 throw new RuntimeException("Could not create new report directory");
287 }
288
289
290 String newDataFileName = "cobertura-" + timestampString + ".ser";
291 File dataFile = new File(reportDirectory, newDataFileName);
292 try {
293 FileCopyUtils.copy(m_coberturaDataFile, dataFile);
294 } catch (IOException e) {
295 throw new RuntimeException("Could not copy the cobertura data file!", e);
296 }
297 String dataFilePath = dataFile.getAbsolutePath();
298
299
300 List<String> arguments = new ArrayList<String>();
301 arguments.add("--datafile");
302 arguments.add(dataFilePath);
303 arguments.add("--destination");
304 arguments.add(reportDirectoryPath);
305 arguments.add(m_coberturaCollectedSourcesDirectory.getAbsolutePath());
306 try {
307 Main.main(arguments.toArray(new String[arguments.size()]));
308 } catch (Exception e) {
309 throw new RuntimeException("Exception while generating the report!", e);
310 }
311
312 return reportDirectoryPath;
313 }
314 }