| package org.apache.maven.archiva.web.action.reports; |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import com.opensymphony.xwork2.Preparable; |
| import org.apache.commons.lang.time.DateFormatUtils; |
| import org.apache.commons.lang.time.DateUtils; |
| import org.apache.maven.archiva.configuration.ArchivaConfiguration; |
| import org.apache.maven.archiva.database.ArchivaDAO; |
| import org.apache.maven.archiva.database.ArchivaDatabaseException; |
| import org.apache.maven.archiva.database.Constraint; |
| import org.apache.maven.archiva.database.ObjectNotFoundException; |
| import org.apache.maven.archiva.database.RepositoryContentStatisticsDAO; |
| import org.apache.maven.archiva.database.constraints.RangeConstraint; |
| import org.apache.maven.archiva.database.constraints.RepositoryContentStatisticsByRepositoryConstraint; |
| import org.apache.maven.archiva.database.constraints.RepositoryProblemByGroupIdConstraint; |
| import org.apache.maven.archiva.database.constraints.RepositoryProblemByRepositoryIdConstraint; |
| import org.apache.maven.archiva.database.constraints.RepositoryProblemConstraint; |
| import org.apache.maven.archiva.database.constraints.UniqueFieldConstraint; |
| import org.apache.maven.archiva.model.RepositoryContentStatistics; |
| import org.apache.maven.archiva.model.RepositoryProblem; |
| import org.apache.maven.archiva.model.RepositoryProblemReport; |
| import org.apache.maven.archiva.reporting.ArchivaReportException; |
| import org.apache.maven.archiva.reporting.DataLimits; |
| import org.apache.maven.archiva.reporting.RepositoryStatistics; |
| import org.apache.maven.archiva.reporting.RepositoryStatisticsReportGenerator; |
| import org.apache.maven.archiva.security.ArchivaRoleConstants; |
| import org.codehaus.plexus.redback.rbac.Resource; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import javax.servlet.http.HttpServletRequest; |
| |
| import java.text.ParseException; |
| import java.util.ArrayList; |
| import java.util.Calendar; |
| import java.util.Collection; |
| import java.util.Date; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.TreeMap; |
| import org.apache.maven.archiva.web.action.PlexusActionSupport; |
| import org.apache.struts2.interceptor.ServletRequestAware; |
| import org.codehaus.plexus.redback.struts2.interceptor.SecureAction; |
| import org.codehaus.plexus.redback.struts2.interceptor.SecureActionBundle; |
| import org.codehaus.plexus.redback.struts2.interceptor.SecureActionException; |
| |
| /** |
| * @plexus.component role="com.opensymphony.xwork2.Action" role-hint="generateReport" |
| */ |
| public class GenerateReportAction |
| extends PlexusActionSupport |
| implements SecureAction, ServletRequestAware, Preparable |
| { |
| private Logger log = LoggerFactory.getLogger( GenerateReportAction.class ); |
| |
| /** |
| * @plexus.requirement role-hint="jdo" |
| */ |
| protected ArchivaDAO dao; |
| |
| /** |
| * @plexus.requirement |
| */ |
| private ArchivaConfiguration archivaConfiguration; |
| |
| protected Constraint constraint; |
| |
| protected HttpServletRequest request; |
| |
| protected List<RepositoryProblemReport> reports = new ArrayList<RepositoryProblemReport>(); |
| |
| protected String groupId; |
| |
| protected String repositoryId; |
| |
| protected String prev; |
| |
| protected String next; |
| |
| protected int[] range = new int[2]; |
| |
| protected int page = 1; |
| |
| protected int rowCount = 100; |
| |
| protected boolean isLastPage; |
| |
| public static final String BLANK = "blank"; |
| |
| public static final String BASIC = "basic"; |
| |
| private static Boolean jasperPresent; |
| |
| private Collection<String> repositoryIds; |
| |
| public static final String ALL_REPOSITORIES = "All Repositories"; |
| |
| protected Map<String, List<RepositoryProblemReport>> repositoriesMap = |
| new TreeMap<String, List<RepositoryProblemReport>>(); |
| |
| // for statistics report |
| /** |
| * @plexus.requirement role-hint="simple" |
| */ |
| private RepositoryStatisticsReportGenerator generator; |
| |
| private List<String> selectedRepositories = new ArrayList<String>(); |
| |
| private List<String> availableRepositories; |
| |
| private String startDate; |
| |
| private String endDate; |
| |
| private int reposSize; |
| |
| private String selectedRepo; |
| |
| private List<RepositoryStatistics> repositoryStatistics = new ArrayList<RepositoryStatistics>(); |
| |
| private DataLimits limits = new DataLimits(); |
| |
| private String[] datePatterns = new String[] { "MM/dd/yy", "MM/dd/yyyy", "MMMMM/dd/yyyy", "MMMMM/dd/yy", |
| "dd MMMMM yyyy", "dd/MM/yy", "dd/MM/yyyy", "yyyy/MM/dd" }; |
| |
| public void prepare() |
| { |
| repositoryIds = new ArrayList<String>(); |
| repositoryIds.add( ALL_REPOSITORIES ); // comes first to be first in the list |
| repositoryIds.addAll( |
| dao.query( new UniqueFieldConstraint( RepositoryProblem.class.getName(), "repositoryId" ) ) ); |
| |
| availableRepositories = new ArrayList<String>(); |
| |
| // remove selected repositories in the option for the statistics report |
| availableRepositories.addAll( archivaConfiguration.getConfiguration().getManagedRepositoriesAsMap().keySet() ); |
| for( String repo : selectedRepositories ) |
| { |
| if( availableRepositories.contains( repo ) ) |
| { |
| availableRepositories.remove( repo ); |
| } |
| } |
| } |
| |
| public Collection<String> getRepositoryIds() |
| { |
| return repositoryIds; |
| } |
| |
| /** |
| * Generate the statistics report. |
| * |
| * check whether single repo report or comparison report |
| * 1. if it is a single repository, get all the statistics for the repository on the specified date |
| * - if no date is specified, get only the latest |
| * (total page = 1 --> no pagination since only the most recent stats will be displayed) |
| * - otherwise, get everything within the date range (total pages = repo stats / rows per page) |
| * - required params: repository, startDate, endDate |
| * |
| * 2. if multiple repositories, get the latest statistics on each repository on the specified date |
| * - if no date is specified, use the current date endDate |
| * - required params: repositories, endDate |
| * - total pages = repositories / rows per page |
| * |
| * @return |
| */ |
| public String generateStatistics() |
| { |
| if( rowCount < 10 ) |
| { |
| addFieldError( "rowCount", "Row count must be larger than 10." ); |
| return INPUT; |
| } |
| reposSize = selectedRepositories.size(); |
| Date startDateInDateFormat = null; |
| Date endDateInDateFormat = null; |
| |
| if( startDate == null || "".equals( startDate ) ) |
| { |
| startDateInDateFormat = getDefaultStartDate(); |
| } |
| else |
| { |
| try |
| { |
| startDateInDateFormat = DateUtils.parseDate( startDate, datePatterns ); |
| } |
| catch ( ParseException e ) |
| { |
| addFieldError( "startDate", "Invalid date format."); |
| return INPUT; |
| } |
| } |
| |
| if( endDate == null || "".equals( endDate ) ) |
| { |
| endDateInDateFormat = getDefaultEndDate(); |
| } |
| else |
| { |
| try |
| { |
| endDateInDateFormat = DateUtils.parseDate( endDate, datePatterns ); |
| } |
| catch ( ParseException e ) |
| { |
| addFieldError( "endDate", "Invalid date format."); |
| return INPUT; |
| } |
| } |
| |
| try |
| { |
| RepositoryContentStatisticsDAO repoContentStatsDao = dao.getRepositoryContentStatisticsDAO(); |
| if( selectedRepositories.size() > 1 ) |
| { |
| limits.setTotalCount( selectedRepositories.size() ); |
| limits.setCurrentPage( 1 ); |
| limits.setPerPageCount( 1 ); |
| limits.setCountOfPages( 1 ); |
| |
| // multiple repos |
| for( String repo : selectedRepositories ) |
| { |
| try |
| { |
| List contentStats = repoContentStatsDao.queryRepositoryContentStatistics( |
| new RepositoryContentStatisticsByRepositoryConstraint( repo, startDateInDateFormat, endDateInDateFormat ) ); |
| |
| if( contentStats == null || contentStats.isEmpty() ) |
| { |
| log.info( "No statistics available for repository '" + repo + "'." ); |
| // TODO set repo's stats to 0 |
| |
| continue; |
| } |
| repositoryStatistics.addAll( generator.generateReport( contentStats, repo, startDateInDateFormat, endDateInDateFormat, limits ) ); |
| } |
| catch ( ObjectNotFoundException oe ) |
| { |
| log.error( "No statistics available for repository '" + repo + "'." ); |
| // TODO set repo's stats to 0 |
| } |
| catch ( ArchivaDatabaseException ae ) |
| { |
| log.error( "Error encountered while querying statistics of repository '" + repo + "'." ); |
| // TODO set repo's stats to 0 |
| } |
| } |
| } |
| else if ( selectedRepositories.size() == 1 ) |
| { |
| limits.setCurrentPage( getPage() ); |
| limits.setPerPageCount( getRowCount() ); |
| |
| selectedRepo = selectedRepositories.get( 0 ); |
| try |
| { |
| List<RepositoryContentStatistics> contentStats = repoContentStatsDao.queryRepositoryContentStatistics( |
| new RepositoryContentStatisticsByRepositoryConstraint( selectedRepo, startDateInDateFormat, endDateInDateFormat ) ); |
| |
| if( contentStats == null || contentStats.isEmpty() ) |
| { |
| addActionError( "No statistics available for repository. Repository might not have been scanned." ); |
| return ERROR; |
| } |
| |
| limits.setTotalCount( contentStats.size() ); |
| int extraPage = ( limits.getTotalCount() % limits.getPerPageCount() ) != 0 ? 1 : 0; |
| int totalPages = ( limits.getTotalCount() / limits.getPerPageCount() ) + extraPage; |
| limits.setCountOfPages( totalPages ); |
| |
| repositoryStatistics = generator.generateReport( contentStats, selectedRepo, startDateInDateFormat, endDateInDateFormat, limits ); |
| } |
| catch ( ObjectNotFoundException oe ) |
| { |
| addActionError( oe.getMessage() ); |
| return ERROR; |
| } |
| catch ( ArchivaDatabaseException de ) |
| { |
| addActionError( de.getMessage() ); |
| return ERROR; |
| } |
| } |
| else |
| { |
| addFieldError( "availableRepositories", "Please select a repository (or repositories) from the list." ); |
| return INPUT; |
| } |
| |
| if( repositoryStatistics.isEmpty() ) |
| { |
| return BLANK; |
| } |
| |
| if( startDate.equals( getDefaultStartDate() ) ) |
| { |
| startDate = null; |
| } |
| else |
| { |
| startDate = DateFormatUtils.format( startDateInDateFormat, "MM/dd/yyyy" ); |
| } |
| |
| endDate = DateFormatUtils.format( endDateInDateFormat, "MM/dd/yyyy" ); |
| } |
| catch ( ArchivaReportException e ) |
| { |
| addActionError( "Error encountered while generating report :: " + e.getMessage() ); |
| return ERROR; |
| } |
| |
| return SUCCESS; |
| } |
| |
| private Date getDefaultStartDate() |
| { |
| Calendar cal = Calendar.getInstance(); |
| cal.clear(); |
| cal.set( 1900, 1, 1, 0, 0, 0 ); |
| |
| return cal.getTime(); |
| } |
| |
| private Date getDefaultEndDate() |
| { |
| return Calendar.getInstance().getTime(); |
| } |
| |
| public String execute() |
| throws Exception |
| { |
| if( repositoryId == null ) |
| { |
| addFieldError( "repositoryId", "You must provide a repository id."); |
| return INPUT; |
| } |
| |
| if( rowCount < 10 ) |
| { |
| addFieldError( "rowCount", "Row count must be larger than 10." ); |
| return INPUT; |
| } |
| |
| List<RepositoryProblem> problemArtifacts = |
| dao.getRepositoryProblemDAO().queryRepositoryProblems( configureConstraint() ); |
| |
| String contextPath = |
| request.getRequestURL().substring( 0, request.getRequestURL().indexOf( request.getRequestURI() ) ); |
| RepositoryProblem problemArtifact; |
| RepositoryProblemReport problemArtifactReport; |
| for ( int i = 0; i < problemArtifacts.size(); i++ ) |
| { |
| problemArtifact = (RepositoryProblem) problemArtifacts.get( i ); |
| problemArtifactReport = new RepositoryProblemReport( problemArtifact ); |
| |
| problemArtifactReport.setGroupURL( contextPath + "/browse/" + problemArtifact.getGroupId() ); |
| problemArtifactReport.setArtifactURL( |
| contextPath + "/browse/" + problemArtifact.getGroupId() + "/" + problemArtifact.getArtifactId() ); |
| |
| addToList( problemArtifactReport ); |
| |
| // retained the reports list because this is the datasource for the jasper report |
| reports.add( problemArtifactReport ); |
| } |
| |
| if ( reports.size() <= rowCount ) |
| { |
| isLastPage = true; |
| } |
| else |
| { |
| reports.remove( rowCount ); |
| } |
| |
| prev = request.getRequestURL() + "?page=" + ( page - 1 ) + "&rowCount=" + rowCount + "&groupId=" + groupId + |
| "&repositoryId=" + repositoryId; |
| next = request.getRequestURL() + "?page=" + ( page + 1 ) + "&rowCount=" + rowCount + "&groupId=" + groupId + |
| "&repositoryId=" + repositoryId; |
| |
| if ( reports.size() == 0 && page == 1 ) |
| { |
| return BLANK; |
| } |
| else if ( isJasperPresent() ) |
| { |
| return "jasper"; |
| } |
| else |
| { |
| return SUCCESS; |
| } |
| } |
| |
| private static boolean isJasperPresent() |
| { |
| if ( jasperPresent == null ) |
| { |
| try |
| { |
| Class.forName( "net.sf.jasperreports.engine.JRExporterParameter" ); |
| jasperPresent = Boolean.TRUE; |
| } |
| catch ( NoClassDefFoundError e ) |
| { |
| jasperPresent = Boolean.FALSE; |
| } |
| catch ( ClassNotFoundException e ) |
| { |
| jasperPresent = Boolean.FALSE; |
| } |
| } |
| return jasperPresent.booleanValue(); |
| } |
| |
| private Constraint configureConstraint() |
| { |
| Constraint constraint; |
| |
| range[0] = ( page - 1 ) * rowCount; |
| range[1] = ( page * rowCount ) + 1; // Add 1 to check if it's the last page or not. |
| |
| if ( groupId != null && ( !groupId.equals( "" ) ) ) |
| { |
| if ( repositoryId != null && ( !repositoryId.equals( "" ) && !repositoryId.equals( ALL_REPOSITORIES ) ) ) |
| { |
| constraint = new RepositoryProblemConstraint( range, groupId, repositoryId ); |
| } |
| else |
| { |
| constraint = new RepositoryProblemByGroupIdConstraint( range, groupId ); |
| } |
| } |
| else if ( repositoryId != null && ( !repositoryId.equals( "" ) && !repositoryId.equals( ALL_REPOSITORIES ) ) ) |
| { |
| constraint = new RepositoryProblemByRepositoryIdConstraint( range, repositoryId ); |
| } |
| else |
| { |
| constraint = new RangeConstraint( range, "repositoryId" ); |
| } |
| |
| return constraint; |
| } |
| |
| public SecureActionBundle getSecureActionBundle() |
| throws SecureActionException |
| { |
| SecureActionBundle bundle = new SecureActionBundle(); |
| |
| bundle.setRequiresAuthentication( true ); |
| bundle.addRequiredAuthorization( ArchivaRoleConstants.OPERATION_ACCESS_REPORT, Resource.GLOBAL ); |
| |
| return bundle; |
| } |
| |
| private void addToList( RepositoryProblemReport repoProblemReport ) |
| { |
| List<RepositoryProblemReport> problemsList = null; |
| |
| if ( repositoriesMap.containsKey( repoProblemReport.getRepositoryId() ) ) |
| { |
| problemsList = ( List<RepositoryProblemReport> ) repositoriesMap.get( repoProblemReport.getRepositoryId() ); |
| } |
| else |
| { |
| problemsList = new ArrayList<RepositoryProblemReport>(); |
| repositoriesMap.put( repoProblemReport.getRepositoryId(), problemsList ); |
| } |
| |
| problemsList.add( repoProblemReport ); |
| } |
| |
| public void setServletRequest( HttpServletRequest request ) |
| { |
| this.request = request; |
| } |
| |
| public List<RepositoryProblemReport> getReports() |
| { |
| return reports; |
| } |
| |
| public String getGroupId() |
| { |
| return groupId; |
| } |
| |
| public void setGroupId( String groupId ) |
| { |
| this.groupId = groupId; |
| } |
| |
| public String getRepositoryId() |
| { |
| return repositoryId; |
| } |
| |
| public void setRepositoryId( String repositoryId ) |
| { |
| this.repositoryId = repositoryId; |
| } |
| |
| public String getPrev() |
| { |
| return prev; |
| } |
| |
| public String getNext() |
| { |
| return next; |
| } |
| |
| public int getPage() |
| { |
| return page; |
| } |
| |
| public void setPage( int page ) |
| { |
| this.page = page; |
| } |
| |
| public int getRowCount() |
| { |
| return rowCount; |
| } |
| |
| public void setRowCount( int rowCount ) |
| { |
| this.rowCount = rowCount; |
| } |
| |
| public boolean getIsLastPage() |
| { |
| return isLastPage; |
| } |
| |
| public void setRepositoriesMap( Map<String, List<RepositoryProblemReport>> repositoriesMap ) |
| { |
| this.repositoriesMap = repositoriesMap; |
| } |
| |
| public Map<String, List<RepositoryProblemReport>> getRepositoriesMap() |
| { |
| return repositoriesMap; |
| } |
| |
| public List<String> getSelectedRepositories() |
| { |
| return selectedRepositories; |
| } |
| |
| public void setSelectedRepositories( List<String> selectedRepositories ) |
| { |
| this.selectedRepositories = selectedRepositories; |
| } |
| |
| public List<String> getAvailableRepositories() |
| { |
| return availableRepositories; |
| } |
| |
| public void setAvailableRepositories( List<String> availableRepositories ) |
| { |
| this.availableRepositories = availableRepositories; |
| } |
| |
| public String getStartDate() |
| { |
| return startDate; |
| } |
| |
| public void setStartDate( String startDate ) |
| { |
| this.startDate = startDate; |
| } |
| |
| public String getEndDate() |
| { |
| return endDate; |
| } |
| |
| public void setEndDate( String endDate ) |
| { |
| this.endDate = endDate; |
| } |
| |
| public List<RepositoryStatistics> getRepositoryStatistics() |
| { |
| return repositoryStatistics; |
| } |
| |
| public void setRepositoryStatistics( List<RepositoryStatistics> repositoryStatistics ) |
| { |
| this.repositoryStatistics = repositoryStatistics; |
| } |
| |
| public int getReposSize() |
| { |
| return reposSize; |
| } |
| |
| public void setReposSize( int reposSize ) |
| { |
| this.reposSize = reposSize; |
| } |
| |
| public String getSelectedRepo() |
| { |
| return selectedRepo; |
| } |
| |
| public void setSelectedRepo( String selectedRepo ) |
| { |
| this.selectedRepo = selectedRepo; |
| } |
| |
| public DataLimits getLimits() |
| { |
| return limits; |
| } |
| |
| public void setLimits( DataLimits limits ) |
| { |
| this.limits = limits; |
| } |
| } |