001/* 002 * The contents of this file are subject to the license and copyright 003 * detailed in the LICENSE and NOTICE files at the root of the source 004 * tree. 005 */ 006package org.fcrepo.stats.impl; 007 008import java.util.ArrayList; 009import java.util.List; 010 011import javax.annotation.PostConstruct; 012import javax.inject.Inject; 013import javax.sql.DataSource; 014 015import org.fcrepo.kernel.api.RdfLexicon; 016import org.fcrepo.stats.api.MimeTypeStatsResult; 017import org.fcrepo.stats.api.RdfTypeStatsResult; 018import org.fcrepo.stats.api.RepositoryStats; 019import org.fcrepo.stats.api.RepositoryStatsByMimeTypeResults; 020import org.fcrepo.stats.api.RepositoryStatsByRdfTypeResults; 021import org.fcrepo.stats.api.RepositoryStatsParameters; 022import org.fcrepo.stats.api.RepositoryStatsResult; 023import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; 024import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; 025import org.springframework.jdbc.support.rowset.SqlRowSet; 026import org.springframework.stereotype.Component; 027import org.springframework.util.CollectionUtils; 028 029/** 030 * A database-backed implementation of the <code>RepositoryStats</code> interface. 031 * It depends on the tables that drive the search index. 032 * 033 * @author dbernstein 034 */ 035@Component("stats") 036public class DbRepositoryStatsImpl implements RepositoryStats { 037 038 private static final String SELECT_COUNT_FROM_SIMPLE_SEARCH = "select count(*) from simple_search"; 039 040 @Inject 041 private DataSource dataSource; 042 043 private NamedParameterJdbcTemplate jdbcTemplate; 044 045 /** 046 * Setup template 047 */ 048 @PostConstruct 049 public void setup() { 050 this.jdbcTemplate = new NamedParameterJdbcTemplate(this.dataSource); 051 } 052 053 054 @Override 055 public RepositoryStatsResult getResourceCount(final RepositoryStatsParameters statsParams) { 056 final var parameterSource = new MapSqlParameterSource(); 057 final var results = jdbcTemplate.queryForRowSet(SELECT_COUNT_FROM_SIMPLE_SEARCH, parameterSource); 058 results.first(); 059 final var result = new RepositoryStatsResult(); 060 result.setResourceCount(results.getLong(1)); 061 return result; 062 } 063 064 @Override 065 public RepositoryStatsByMimeTypeResults getByMimeTypes(final RepositoryStatsParameters statsParams) { 066 final var results = new RepositoryStatsByMimeTypeResults(); 067 final var mimeTypes = statsParams.getMimeTypes(); 068 final var parameterSource = new MapSqlParameterSource(); 069 final var mimeTypesQuery = formatMimetypeQuery(mimeTypes, parameterSource); 070 final var mimetypeResults = jdbcTemplate.queryForRowSet(mimeTypesQuery, parameterSource); 071 marshallMimeTypeResults(results, mimetypeResults); 072 return results; 073 } 074 075 @Override 076 public RepositoryStatsByRdfTypeResults getByRdfType(final RepositoryStatsParameters statsParams) { 077 final var results = new RepositoryStatsByRdfTypeResults(); 078 final var parameterSource = new MapSqlParameterSource(); 079 final var query = formatRdfTypeQuery(statsParams.getRdfTypes(), parameterSource); 080 final var rdfTypeResults = jdbcTemplate.queryForRowSet(query, parameterSource); 081 marshallRdfTypeResults(results, rdfTypeResults); 082 return results; 083 } 084 085 private void marshallMimeTypeResults(final RepositoryStatsByMimeTypeResults results, 086 final SqlRowSet mimeTypeResults) { 087 if (mimeTypeResults.first()) { 088 final var mimeTypesResultList = new ArrayList<MimeTypeStatsResult>(); 089 do { 090 final var mimeTypeResult = new MimeTypeStatsResult(); 091 mimeTypeResult.setMimeType(mimeTypeResults.getString(1)); 092 mimeTypeResult.setResourceCount(mimeTypeResults.getLong(2)); 093 mimeTypeResult.setByteCount(mimeTypeResults.getLong(3)); 094 mimeTypesResultList.add(mimeTypeResult); 095 } while (mimeTypeResults.next()); 096 results.setMimeTypes(mimeTypesResultList); 097 } 098 } 099 100 private String formatMimetypeQuery(final List<String> mimeTypes, final MapSqlParameterSource parameterSource) { 101 final var mimeTypesQuery = new StringBuilder("select a.mime_type, count(a.id), sum(a.content_size) "); 102 mimeTypesQuery.append("from simple_search a, search_resource_rdf_type b, search_rdf_type c "); 103 mimeTypesQuery.append("where a.id = b.resource_id and b.rdf_type_id = c.id and c.rdf_type_uri = '"); 104 mimeTypesQuery.append(RdfLexicon.NON_RDF_SOURCE.getURI()); 105 mimeTypesQuery.append("' "); 106 if (!CollectionUtils.isEmpty(mimeTypes)) { 107 mimeTypesQuery.append("and a.mime_type in (:mime_types) "); 108 parameterSource.addValue("mime_types", mimeTypes); 109 } 110 mimeTypesQuery.append("group by a.mime_type order by a.mime_type"); 111 return mimeTypesQuery.toString(); 112 } 113 114 private void marshallRdfTypeResults(final RepositoryStatsByRdfTypeResults results, 115 final SqlRowSet rdfTypeResults) { 116 if (rdfTypeResults.first()) { 117 final var resourceTypeStatsResults = new ArrayList<RdfTypeStatsResult>(); 118 do { 119 final var resourceTypeResult = new RdfTypeStatsResult(); 120 resourceTypeResult.setResourceType(rdfTypeResults.getString(1)); 121 resourceTypeResult.setResourceCount(rdfTypeResults.getLong(2)); 122 resourceTypeResult.setByteCount(rdfTypeResults.getLong(3)); 123 resourceTypeStatsResults.add(resourceTypeResult); 124 } while (rdfTypeResults.next()); 125 results.setRdfTypes(resourceTypeStatsResults); 126 } 127 } 128 129 130 private String formatRdfTypeQuery(final List<String> rdfTypes, final MapSqlParameterSource parameterSource) { 131 final var rdfTypesQuery = new StringBuilder( 132 "select c.rdf_type_uri, count(b.resource_id), sum(a.content_size) "); 133 rdfTypesQuery.append("from simple_search a, search_resource_rdf_type b, search_rdf_type c "); 134 rdfTypesQuery.append("where a.id = b.resource_id and b.rdf_type_id = c.id "); 135 if (!CollectionUtils.isEmpty(rdfTypes)) { 136 rdfTypesQuery.append("and c.rdf_type_uri in (:rdf_types) "); 137 parameterSource.addValue("rdf_types", rdfTypes); 138 } 139 rdfTypesQuery.append("group by c.rdf_type_uri"); 140 return rdfTypesQuery.toString(); 141 } 142}