1 package org.apache.continuum.web.action;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.commons.io.IOUtils;
23 import org.apache.commons.lang.StringUtils;
24 import org.apache.commons.lang.time.DateUtils;
25 import org.apache.maven.continuum.model.project.BuildResult;
26 import org.apache.maven.continuum.model.project.Project;
27 import org.apache.maven.continuum.model.project.ProjectGroup;
28 import org.apache.maven.continuum.project.ContinuumProjectState;
29 import org.apache.maven.continuum.web.action.ContinuumActionSupport;
30 import org.apache.maven.continuum.web.exception.AuthorizationRequiredException;
31 import org.apache.maven.continuum.web.model.ProjectBuildsSummary;
32
33 import java.io.ByteArrayInputStream;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.io.StringReader;
37 import java.text.ParseException;
38 import java.util.ArrayList;
39 import java.util.Collections;
40 import java.util.Date;
41 import java.util.LinkedHashMap;
42 import java.util.List;
43 import java.util.Map;
44
45
46
47
48 public class ViewBuildsReportAction
49 extends ContinuumActionSupport
50 {
51 private int buildStatus;
52
53 private String triggeredBy = "";
54
55 private String startDate = "";
56
57 private String endDate = "";
58
59 private int projectGroupId;
60
61 private int rowCount = 30;
62
63 private int page = 1;
64
65 private int numPages;
66
67 private Map<Integer, String> buildStatuses;
68
69 private Map<Integer, String> projectGroups;
70
71 private List<ProjectBuildsSummary> projectBuilds;
72
73 private InputStream inputStream;
74
75 public static final String SEND_FILE = "send-file";
76
77 private static final String[] datePatterns =
78 new String[]{"MM/dd/yy", "MM/dd/yyyy", "MMMMM/dd/yyyy", "MMMMM/dd/yy", "dd MMMMM yyyy", "dd/MM/yy",
79 "dd/MM/yyyy", "yyyy/MM/dd", "yyyy-MM-dd", "yyyy-dd-MM", "MM-dd-yyyy", "MM-dd-yy"};
80
81 public void prepare()
82 throws Exception
83 {
84 super.prepare();
85
86 buildStatuses = new LinkedHashMap<Integer, String>();
87 buildStatuses.put( 0, "ALL" );
88 buildStatuses.put( ContinuumProjectState.OK, "Ok" );
89 buildStatuses.put( ContinuumProjectState.FAILED, "Failed" );
90 buildStatuses.put( ContinuumProjectState.ERROR, "Error" );
91
92 projectGroups = new LinkedHashMap<Integer, String>();
93 projectGroups.put( 0, "ALL" );
94
95 List<ProjectGroup> groups = getContinuum().getAllProjectGroups();
96 if ( groups != null )
97 {
98 for ( ProjectGroup group : groups )
99 {
100 projectGroups.put( group.getId(), group.getName() );
101 }
102 }
103 }
104
105 public String init()
106 {
107 try
108 {
109 checkViewReportsAuthorization();
110 }
111 catch ( AuthorizationRequiredException authzE )
112 {
113 addActionError( authzE.getMessage() );
114 return REQUIRES_AUTHORIZATION;
115 }
116
117
118 return SUCCESS;
119 }
120
121 public String execute()
122 {
123 try
124 {
125 checkViewReportsAuthorization();
126 }
127 catch ( AuthorizationRequiredException authzE )
128 {
129 addActionError( authzE.getMessage() );
130 return REQUIRES_AUTHORIZATION;
131 }
132
133 Date fromDate = null;
134 Date toDate = null;
135
136 try
137 {
138 fromDate = getStartDateInDateFormat();
139 toDate = getEndDateInDateFormat();
140 }
141 catch ( ParseException e )
142 {
143 addActionError( "Error parsing date(s): " + e.getMessage() );
144 return ERROR;
145 }
146
147 if ( fromDate != null && toDate != null && fromDate.after( toDate ) )
148 {
149 addFieldError( "startDate", "Start Date must be earlier than the End Date" );
150 return INPUT;
151 }
152
153 if ( rowCount < 10 )
154 {
155
156 addFieldError( "rowCount", "Row count should be at least 10." );
157 return INPUT;
158 }
159
160 List<BuildResult> buildResults = getContinuum().getBuildResultsInRange( projectGroupId, fromDate, toDate,
161 buildStatus, triggeredBy );
162 projectBuilds = Collections.emptyList();
163
164 if ( buildResults != null && !buildResults.isEmpty() )
165 {
166 projectBuilds = mapBuildResultsToProjectBuildsSummaries( buildResults );
167
168 int extraPage = ( projectBuilds.size() % rowCount ) != 0 ? 1 : 0;
169 numPages = ( projectBuilds.size() / rowCount ) + extraPage;
170
171 if ( page > numPages )
172 {
173 addActionError(
174 "Error encountered while generating project builds report :: The requested page exceeds the total number of pages." );
175 return ERROR;
176 }
177
178 int start = rowCount * ( page - 1 );
179 int end = ( start + rowCount );
180
181 if ( end > projectBuilds.size() )
182 {
183 end = projectBuilds.size();
184 }
185
186 projectBuilds = projectBuilds.subList( start, end );
187 }
188
189 return SUCCESS;
190 }
191
192
193
194
195 public String downloadBuildsReport()
196 {
197 try
198 {
199 checkViewReportsAuthorization();
200 }
201 catch ( AuthorizationRequiredException authzE )
202 {
203 addActionError( authzE.getMessage() );
204 return REQUIRES_AUTHORIZATION;
205 }
206
207 Date fromDate = null;
208 Date toDate = null;
209
210 try
211 {
212 fromDate = getStartDateInDateFormat();
213 toDate = getEndDateInDateFormat();
214 }
215 catch ( ParseException e )
216 {
217 addActionError( "Error parsing date(s): " + e.getMessage() );
218 return ERROR;
219 }
220
221 if ( fromDate != null && toDate != null && fromDate.after( toDate ) )
222 {
223 addFieldError( "startDate", "Start Date must be earlier than the End Date" );
224 return INPUT;
225 }
226
227 List<BuildResult> buildResults = getContinuum().getBuildResultsInRange( projectGroupId, fromDate, toDate,
228 buildStatus, triggeredBy );
229 List<ProjectBuildsSummary> builds = Collections.emptyList();
230
231 StringBuffer input = new StringBuffer( "Project Group,Project Name,Build Date,Triggered By,Build Status\n" );
232
233 if ( buildResults != null && !buildResults.isEmpty() )
234 {
235 builds = mapBuildResultsToProjectBuildsSummaries( buildResults );
236
237 for ( ProjectBuildsSummary build : builds )
238 {
239 input.append( build.getProjectGroupName() ).append( "," );
240 input.append( build.getProjectName() ).append( "," );
241
242 input.append( new Date( build.getBuildDate() ) ).append( "," );
243
244 input.append( build.getBuildTriggeredBy() ).append( "," );
245
246 String status;
247 switch ( build.getBuildState() )
248 {
249 case 2:
250 status = "Ok";
251 break;
252 case 3:
253 status = "Failed";
254 break;
255 case 4:
256 status = "Error";
257 break;
258 case 6:
259 status = "Building";
260 break;
261 case 7:
262 status = "Checking Out";
263 break;
264 case 8:
265 status = "Updating";
266 break;
267 default:
268 status = "";
269 }
270 input.append( status );
271 input.append( "\n" );
272 }
273 }
274
275 StringReader reader = new StringReader( input.toString() );
276
277 try
278 {
279 inputStream = new ByteArrayInputStream( IOUtils.toByteArray( reader ) );
280 }
281 catch ( IOException e )
282 {
283 addActionError( "Error occurred while generating CSV file." );
284 return ERROR;
285 }
286
287 return SEND_FILE;
288 }
289
290 private List<ProjectBuildsSummary> mapBuildResultsToProjectBuildsSummaries( List<BuildResult> buildResults )
291 {
292 List<ProjectBuildsSummary> buildsSummary = new ArrayList<ProjectBuildsSummary>();
293
294 for ( BuildResult buildResult : buildResults )
295 {
296 Project project = buildResult.getProject();
297
298
299 if ( !isAuthorized( project.getProjectGroup().getName() ) )
300 {
301 continue;
302 }
303
304 ProjectBuildsSummary summary = new ProjectBuildsSummary();
305 summary.setProjectGroupName( project.getProjectGroup().getName() );
306 summary.setProjectName( project.getName() );
307 summary.setBuildDate( buildResult.getStartTime() );
308 summary.setBuildState( buildResult.getState() );
309 summary.setBuildTriggeredBy( buildResult.getUsername() );
310
311 buildsSummary.add( summary );
312 }
313
314 return buildsSummary;
315 }
316
317 private Date getStartDateInDateFormat()
318 throws ParseException
319 {
320 Date date = null;
321
322 if ( !StringUtils.isEmpty( startDate ) )
323 {
324 date = DateUtils.parseDate( startDate, datePatterns );
325 }
326
327 return date;
328 }
329
330 private Date getEndDateInDateFormat()
331 throws ParseException
332 {
333 Date date = null;
334
335 if ( !StringUtils.isEmpty( endDate ) )
336 {
337 date = DateUtils.parseDate( endDate, datePatterns );
338 }
339
340 return date;
341 }
342
343 public int getBuildStatus()
344 {
345 return this.buildStatus;
346 }
347
348 public void setBuildStatus( int buildStatus )
349 {
350 this.buildStatus = buildStatus;
351 }
352
353 public int getProjectGroupId()
354 {
355 return this.projectGroupId;
356 }
357
358 public void setProjectGroupId( int projectGroupId )
359 {
360 this.projectGroupId = projectGroupId;
361 }
362
363 public String getTriggeredBy()
364 {
365 return this.triggeredBy;
366 }
367
368 public void setTriggeredBy( String triggeredBy )
369 {
370 this.triggeredBy = triggeredBy;
371 }
372
373 public String getStartDate()
374 {
375 return this.startDate;
376 }
377
378 public void setStartDate( String startDate )
379 {
380 this.startDate = startDate;
381 }
382
383 public String getEndDate()
384 {
385 return this.endDate;
386 }
387
388 public void setEndDate( String endDate )
389 {
390 this.endDate = endDate;
391 }
392
393 public int getRowCount()
394 {
395 return rowCount;
396 }
397
398 public void setRowCount( int rowCount )
399 {
400 this.rowCount = rowCount;
401 }
402
403 public Map<Integer, String> getBuildStatuses()
404 {
405 return buildStatuses;
406 }
407
408 public Map<Integer, String> getProjectGroups()
409 {
410 return projectGroups;
411 }
412
413 public List<ProjectBuildsSummary> getProjectBuilds()
414 {
415 return projectBuilds;
416 }
417
418 public int getPage()
419 {
420 return page;
421 }
422
423 public void setPage( int page )
424 {
425 this.page = page;
426 }
427
428 public int getNumPages()
429 {
430 return numPages;
431 }
432
433 public InputStream getInputStream()
434 {
435 return inputStream;
436 }
437
438 private boolean isAuthorized( String projectGroupName )
439 {
440 try
441 {
442 checkViewProjectGroupAuthorization( projectGroupName );
443 return true;
444 }
445 catch ( AuthorizationRequiredException authzE )
446 {
447 return false;
448 }
449 }
450 }