/* * Copyright (c) 2011 Lockheed Martin Corporation * * Licensed 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. */ package org.eurekastreams.server.action.execution; import java.io.Serializable; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.commons.logging.Log; import org.eurekastreams.commons.actions.ExecutionStrategy; import org.eurekastreams.commons.actions.context.PrincipalActionContext; import org.eurekastreams.commons.date.DateDayExtractor; import org.eurekastreams.commons.date.DayOfWeekStrategy; import org.eurekastreams.commons.date.WeekdaysInDateRangeStrategy; import org.eurekastreams.commons.logging.LogFactory; import org.eurekastreams.server.domain.DailyUsageSummary; import org.eurekastreams.server.persistence.mappers.DomainMapper; import org.eurekastreams.server.search.modelview.UsageMetricSummaryDTO; import org.eurekastreams.server.service.actions.requests.UsageMetricStreamSummaryRequest; import com.ibm.icu.util.Calendar; /** * Execution strategy to get the usage metric information for a stream or for all streams. */ public class GetUsageMetricSummaryExecution implements ExecutionStrategy<PrincipalActionContext> { /** * Logger. */ private final Log logger = LogFactory.make(); /** * Mapper to get the summary data for a stream, or all streams. */ private final DomainMapper<UsageMetricStreamSummaryRequest, List<DailyUsageSummary>> summaryDataMapper; /** * Strategy to get the number of weekdays between two dates. */ private final WeekdaysInDateRangeStrategy weekdaysInDateRangeStrategy; /** * Strategy to determine if a date is a weekday. */ private final DayOfWeekStrategy dayOfWeekStrategy; /** * Constructor. * * @param inSummaryDataMapper * mapper to get the summary data for a stream, or all streams * @param inWeekdaysInDateRangeStrategy * strategy to get the number of weekdays between two dates * @param inDayOfWeekStrategy * strategy to determine if a date is a weekday */ public GetUsageMetricSummaryExecution( final DomainMapper<UsageMetricStreamSummaryRequest, List<DailyUsageSummary>> inSummaryDataMapper, final WeekdaysInDateRangeStrategy inWeekdaysInDateRangeStrategy, final DayOfWeekStrategy inDayOfWeekStrategy) { summaryDataMapper = inSummaryDataMapper; weekdaysInDateRangeStrategy = inWeekdaysInDateRangeStrategy; dayOfWeekStrategy = inDayOfWeekStrategy; } /** * Get the daily usage summary for all streams or for a specific stream. * * @param inActionContext * the action context containing the UsageMetricDailyStreamInfoRequest * @return the UsageMetricSummaryDTO */ @Override public Serializable execute(final PrincipalActionContext inActionContext) { UsageMetricStreamSummaryRequest request = (UsageMetricStreamSummaryRequest) inActionContext.getParams(); List<DailyUsageSummary> results = summaryDataMapper.execute(request); logger.info("Found " + results.size() + " summary results"); UsageMetricSummaryDTO result = new UsageMetricSummaryDTO(); // can't build the list directly - build up a temporary list so we can fill in the holes later List<DailyUsageSummary> dailyStats = new ArrayList<DailyUsageSummary>(); // short-circuit if no results. if (results.size() == 0) { return result; } long msgCount = 0; long pageViewCount = 0; long streamContributorCount = 0; long streamViewCount = 0; long streamViewerCount = 0; long uniqueVisitorCount = 0; long avgActivityResponseTime = 0; long startingCommentCount = 0, finalCommentCount = 0; long startingActivityCount = 0, finalActivityCount = 0; Long totalActivityCount = null; Long totalCommentCount = null; Long totalContributorCount = null; Calendar day = Calendar.getInstance(); day.add(Calendar.DATE, -request.getNumberOfDays()); Date oldestAllowableReportDate = DateDayExtractor.getStartOfDay(new Date(day.getTimeInMillis())); day = Calendar.getInstance(); day.add(Calendar.DATE, -1); Date latestReportDate = DateDayExtractor.getStartOfDay(new Date(day.getTimeInMillis())); Date summaryDate; Date oldestAvailableReportDate = null; Date newestAvailableReportDate = null; logger.debug("Looking for data between " + oldestAllowableReportDate + " and " + latestReportDate); for (DailyUsageSummary dus : results) { summaryDate = DateDayExtractor.getStartOfDay(dus.getUsageDate()); if (summaryDate.before(oldestAllowableReportDate) || summaryDate.after(latestReportDate)) { // can't use this data logger.debug("Can't use data for " + summaryDate); continue; } // set the normalized date, add the date to the list dus.setUsageDate(summaryDate); dailyStats.add(dus); if (newestAvailableReportDate == null || summaryDate.after(newestAvailableReportDate)) { newestAvailableReportDate = summaryDate; // this is currently the most recent record - store the totals totalActivityCount = dus.getTotalActivityCount(); totalCommentCount = dus.getTotalCommentCount(); totalContributorCount = dus.getTotalContributorCount(); finalCommentCount = dus.getTotalCommentCount() == null ? 0 : dus.getTotalCommentCount(); finalActivityCount = dus.getTotalActivityCount() == null ? 0 : dus.getTotalActivityCount(); } if (oldestAvailableReportDate == null || summaryDate.before(oldestAvailableReportDate)) { // this is the earliest reporting date we've seen oldestAvailableReportDate = summaryDate; startingCommentCount = dus.getTotalCommentCount() == null ? 0 : dus.getTotalCommentCount(); startingActivityCount = dus.getTotalActivityCount() == null ? 0 : dus.getTotalActivityCount(); } msgCount += dus.getMessageCount(); pageViewCount += dus.getPageViewCount(); streamContributorCount += dus.getStreamContributorCount(); streamViewCount += dus.getStreamViewCount(); streamViewerCount += dus.getStreamViewerCount(); uniqueVisitorCount += dus.getUniqueVisitorCount(); avgActivityResponseTime += dus.getAvgActivityResponseTime(); } // number of weekdays between the two dates long weekdaysCount = 0; if (oldestAvailableReportDate != null) { weekdaysCount = weekdaysInDateRangeStrategy.getWeekdayCountBetweenDates(oldestAvailableReportDate, DateDayExtractor.getStartOfDay(new Date())); } result.setWeekdayRecordCount(weekdaysCount); result.setTotalActivityCount(totalActivityCount); result.setTotalCommentCount(totalCommentCount); result.setTotalContributorCount(totalContributorCount); logger.debug("Found " + weekdaysCount + " weekdays between " + oldestAvailableReportDate + " and " + latestReportDate); if (weekdaysCount > 0) { result.setAverageDailyMessageCount(Math.round(Math.ceil(msgCount * 1.0 / weekdaysCount))); result.setAverageDailyPageViewCount(Math.round(Math.ceil(pageViewCount * 1.0 / weekdaysCount))); result.setAverageDailyStreamContributorCount(Math.round(Math.ceil(streamContributorCount * 1.0 / weekdaysCount))); result.setAverageDailyStreamViewCount(Math.round(Math.ceil(streamViewCount * 1.0 / weekdaysCount))); result.setAverageDailyStreamViewerCount(Math.round(Math.ceil(streamViewerCount * 1.0 / weekdaysCount))); result.setAverageDailyUniqueVisitorCount(Math.round(Math.ceil(uniqueVisitorCount * 1.0 / weekdaysCount))); result.setAverageDailyActivityResponseTime(Math.round(Math.ceil(avgActivityResponseTime * 1.0 / weekdaysCount))); long averageCommentPerActivity = 0; if (weekdaysCount > 1) { double top = (finalCommentCount - startingCommentCount) * 1.0; double bottom = (finalActivityCount - startingActivityCount) * 1.0; if (bottom > 0) { // Note: this is average comments per activity per day = (delta comments)/(delta activities) divided // by weekdaysCount-1. The -1 is necessary because we calculate this number by subtracting oldest // day from newest averageCommentPerActivity = Math.round(Math.ceil(top / (bottom * (weekdaysCount - 1)))); } } result.setAverageDailyCommentPerActivityCount(averageCommentPerActivity); } result.setDailyStatistics(new ArrayList<DailyUsageSummary>()); if (dailyStats.size() > 0) { // Loop through every date from the start of reporting for this stream to now, filling in records for // weekdays // that have none to make the client-side logic easier Calendar cal = Calendar.getInstance(); cal.setTime(oldestAvailableReportDate); Date reportDate; long lastDateInMs = latestReportDate.getTime(); int dataIndex = 0; // the current index in the data list // when looping, include a check to make sure we don't add more records than expected - this is a safeguard // in case there's an unexpected daylight savings time condition that'll cause an infinite loop for (reportDate = cal.getTime(); reportDate.getTime() <= lastDateInMs && result.getDailyStatistics().size() < weekdaysCount; cal.add(Calendar.DATE, 1), reportDate = cal .getTime()) { if (!dayOfWeekStrategy.isWeekday(reportDate)) { // we don't include weekend data continue; } // it's a weekday - we need a record for this date if (dataIndex < dailyStats.size()) { // there's still data records to look for DailyUsageSummary record = dailyStats.get(dataIndex); if (DateDayExtractor.getStartOfDay(record.getUsageDate()).getTime() == reportDate.getTime()) { // this is the data we're looking for - add it to the result list result.getDailyStatistics().add(record); // bump up the position index for the next loop iteration dataIndex++; } else { // we don't have data for that weekday - add a null to the result list result.getDailyStatistics().add(null); } } else { // no more data to look for - we're just adding nulls until the end result.getDailyStatistics().add(null); } } } return result; } }