/* * Copyright (c) 2010-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.Date; import java.util.List; import org.apache.commons.logging.Log; import org.eurekastreams.commons.actions.TaskHandlerExecutionStrategy; import org.eurekastreams.commons.actions.context.ActionContext; import org.eurekastreams.commons.actions.context.TaskHandlerActionContext; import org.eurekastreams.commons.date.DateDayExtractor; import org.eurekastreams.commons.date.DayOfWeekStrategy; import org.eurekastreams.commons.date.GetDateFromDaysAgoStrategy; import org.eurekastreams.commons.exceptions.ExecutionException; import org.eurekastreams.commons.logging.LogFactory; import org.eurekastreams.server.domain.DailyUsageSummary; import org.eurekastreams.server.domain.dto.StreamDiscoverListsDTO; import org.eurekastreams.server.persistence.mappers.DomainMapper; import org.eurekastreams.server.persistence.mappers.requests.PersistenceRequest; import org.eurekastreams.server.service.actions.requests.UsageMetricDailyStreamInfoRequest; import org.eurekastreams.server.service.actions.requests.UsageMetricStreamSummaryRequest; /** * Execution strategy to generate the daily usage summary for the previous day. */ public class GenerateDailyUsageSummaryExecution implements TaskHandlerExecutionStrategy<ActionContext> { /** * Logger. */ private final Log logger = LogFactory.make(); /** * strategy to get a date from N days ago. */ private final GetDateFromDaysAgoStrategy daysAgoDateStrategy; /** * Number of days of data to generate. */ private final int daysToGenerate; // mappers that apply to the whole system /** * Mapper to get a day's page view count - for the whole system. */ private final DomainMapper<Date, Long> getDailyPageViewCountMapper; /** * Mapper to get a day's unique visitor count - for whole system. */ private final DomainMapper<Date, Long> getDailyUniqueVisitorCountMapper; // mappers that may be scoped to a particular thread /** * Mapper to get a single day's DailyUsageSummary - for a stream or the whole system. */ private final DomainMapper<UsageMetricDailyStreamInfoRequest, DailyUsageSummary> // getDailyUsageSummaryByDateMapper; /** * Mapper to get a day's message count - for a stream or the whole system. */ private final DomainMapper<UsageMetricDailyStreamInfoRequest, Long> getDailyMessageCountMapper; /** * Mapper to get a day's stream contributor count - for a stream or the whole system. */ private final DomainMapper<UsageMetricDailyStreamInfoRequest, Long> getDailyStreamContributorCountMapper; /** * Mapper to get a day's stream view count - for a stream or the whole system. */ private final DomainMapper<UsageMetricDailyStreamInfoRequest, Long> getDailyStreamViewCountMapper; /** * Mapper to get a day's stream viewer count - for a stream or the whole system. */ private final DomainMapper<UsageMetricDailyStreamInfoRequest, Long> getDailyStreamViewerCountMapper; /** * Mapper to get the total number of activities posted to a stream. */ private final DomainMapper<UsageMetricDailyStreamInfoRequest, Long> getTotalActivityCountMapper; /** * Mapper to get the total number of comments posted to a stream. */ private final DomainMapper<UsageMetricDailyStreamInfoRequest, Long> getTotalCommentCountMapper; /** * Mapper to get the total number of contributors to a stream by stream scope id. */ private final DomainMapper<UsageMetricDailyStreamInfoRequest, Long> getTotalStreamContributorMapper; /** * Mapper to get day's average activity response time (for those that had responses) - for a stream or the whole * system. */ private final DomainMapper<Date, Long> getDailyMessageResponseTimeMapper; // helpers /** * Mapper to get all the ids for the stream scopes to generate data for. */ private final DomainMapper<Date, List<Long>> streamScopeIdsMapper; /** * Mapper to delete old UsageMetric data. */ private final DomainMapper<Serializable, Serializable> usageMetricDataCleanupMapper; /** * Mapper to insert the DailyUsageSummary entity. */ private final DomainMapper<PersistenceRequest<DailyUsageSummary>, Boolean> insertMapper; /** * Mapper to clear the entity manager. */ private final DomainMapper<Serializable, Boolean> clearEntityManagerMapper; /** * Mapper to get the summary data for a stream, or all streams - used for caching. */ private final DomainMapper<UsageMetricStreamSummaryRequest, List<DailyUsageSummary>> summaryDataMapper; /** * Mapper to get the lists for the discover page - this should be a cache refreshing mapper, b/c that's how it's * used. */ private final DomainMapper<Serializable, StreamDiscoverListsDTO> discoverPageListsCacheRefreshingMapper; /** * The number of days to cache summary data for. */ private final int numberOfDaysToCacheSummaryDataFor; /** * Strategy to determine if a day is a weekday. */ private final DayOfWeekStrategy dayOfWeekStrategy; /** * Constructor. * * @param inDaysToGenerate * the number of days to generate data for * @param inDaysAgoDateStrategy * strategy to get a date from yesterday * @param inGetDailyUsageSummaryByDateMapper * Mapper to get a single day's DailyUsageSummary * * @param inGetDailyMessageCountMapper * Mapper to get a day's message count * @param inGetDailyPageViewCountMapper * Mapper to get a day's page view count. * @param inGetDailyStreamContributorCountMapper * Mapper to get a day's stream contributor count. * @param inGetDailyStreamViewCountMapper * Mapper to get a day's stream view count. * @param inGetDailyStreamViewerCountMapper * Mapper to get a day's stream viewer count. * @param inGetDailyUniqueVisitorCountMapper * Mapper to get a day's unique visitor count. * @param inGetDailyMessageResponseTimeMapper * Mapper to get day's average activity response time (for those that had responses). * @param inInsertMapper * mapper to insert DailyUsageSummary * @param inUsageMetricDataCleanupMapper * mapper to delete old UsageMetric data * @param inDayOfWeekStrategy * dayOfWeekStrategy strategy to determine if a day is a weekday * @param inStreamScopeIdsMapper * mapper to get all the ids of the stream scopes to generate data for * @param inGetTotalActivityCountMapper * mapper to get the total activities for a stream * @param inGetTotalCommentCountMapper * mapper to get the total comments for a stream * @param inGetTotalStreamContributorMapper * mapper to get the total number of contributors to a stream * @param inClearEntityManagerMapper * mapper to clear entity manager * @param inSummaryDataMapper * mapper to fetch & cache the stream scope's summary data * @param inDiscoverPageListsCacheRefreshingMapper * mapper to fetch and refresh the discover page lists in cache * @param inNumberOfDaysToCacheSummaryDataFor * the number of days to cache the summary data for */ public GenerateDailyUsageSummaryExecution( final int inDaysToGenerate, final GetDateFromDaysAgoStrategy inDaysAgoDateStrategy, final DomainMapper<UsageMetricDailyStreamInfoRequest, DailyUsageSummary> inGetDailyUsageSummaryByDateMapper, final DomainMapper<UsageMetricDailyStreamInfoRequest, Long> inGetDailyMessageCountMapper, final DomainMapper<Date, Long> inGetDailyPageViewCountMapper, final DomainMapper<UsageMetricDailyStreamInfoRequest, Long> inGetDailyStreamContributorCountMapper, final DomainMapper<UsageMetricDailyStreamInfoRequest, Long> inGetDailyStreamViewCountMapper, final DomainMapper<UsageMetricDailyStreamInfoRequest, Long> inGetDailyStreamViewerCountMapper, final DomainMapper<Date, Long> inGetDailyUniqueVisitorCountMapper, final DomainMapper<Date, Long> inGetDailyMessageResponseTimeMapper, final DomainMapper<PersistenceRequest<DailyUsageSummary>, Boolean> inInsertMapper, final DomainMapper<Serializable, Serializable> inUsageMetricDataCleanupMapper, final DayOfWeekStrategy inDayOfWeekStrategy, final DomainMapper<Date, List<Long>> inStreamScopeIdsMapper, final DomainMapper<UsageMetricDailyStreamInfoRequest, Long> inGetTotalActivityCountMapper, final DomainMapper<UsageMetricDailyStreamInfoRequest, Long> inGetTotalCommentCountMapper, final DomainMapper<UsageMetricDailyStreamInfoRequest, Long> inGetTotalStreamContributorMapper, final DomainMapper<Serializable, Boolean> inClearEntityManagerMapper, final DomainMapper<UsageMetricStreamSummaryRequest, List<DailyUsageSummary>> inSummaryDataMapper, final DomainMapper<Serializable, StreamDiscoverListsDTO> inDiscoverPageListsCacheRefreshingMapper, final int inNumberOfDaysToCacheSummaryDataFor) { daysToGenerate = inDaysToGenerate; daysAgoDateStrategy = inDaysAgoDateStrategy; getDailyUsageSummaryByDateMapper = inGetDailyUsageSummaryByDateMapper; getDailyMessageCountMapper = inGetDailyMessageCountMapper; getDailyPageViewCountMapper = inGetDailyPageViewCountMapper; getDailyStreamContributorCountMapper = inGetDailyStreamContributorCountMapper; getDailyStreamViewCountMapper = inGetDailyStreamViewCountMapper; getDailyStreamViewerCountMapper = inGetDailyStreamViewerCountMapper; getDailyUniqueVisitorCountMapper = inGetDailyUniqueVisitorCountMapper; getDailyMessageResponseTimeMapper = inGetDailyMessageResponseTimeMapper; insertMapper = inInsertMapper; usageMetricDataCleanupMapper = inUsageMetricDataCleanupMapper; dayOfWeekStrategy = inDayOfWeekStrategy; streamScopeIdsMapper = inStreamScopeIdsMapper; getTotalActivityCountMapper = inGetTotalActivityCountMapper; getTotalCommentCountMapper = inGetTotalCommentCountMapper; getTotalStreamContributorMapper = inGetTotalStreamContributorMapper; clearEntityManagerMapper = inClearEntityManagerMapper; summaryDataMapper = inSummaryDataMapper; discoverPageListsCacheRefreshingMapper = inDiscoverPageListsCacheRefreshingMapper; numberOfDaysToCacheSummaryDataFor = inNumberOfDaysToCacheSummaryDataFor; } /** * Generate the daily usage summary for the previous day. * * @param inActionContext * the action context * @return true if data was inserted, false if already existed * @throws ExecutionException * when something really, really bad happens */ @Override public Serializable execute(final TaskHandlerActionContext<ActionContext> inActionContext) throws ExecutionException { long start = System.currentTimeMillis(); for (int i = daysToGenerate; i >= 1; i--) { logger.info("Generating metric data for " + i + " days ago."); generateDailyUsageSummaryForDay(i); } // delete old data logger.info("Deleting old daily usage metric data older than 2 days"); usageMetricDataCleanupMapper.execute(null); logger.info("Completed generating usage metrics in " + (System.currentTimeMillis() - start) + "ms"); // now ask for the discover page lists from the refresh mapper, which will cause the cache to update logger.info("Updating the Discover Page cache."); discoverPageListsCacheRefreshingMapper.execute(null); logger.info("Completed generating Discover Page cache."); return Boolean.TRUE; } /** * Generate the daily usage summary for all streams for a specific day. * * @param inDaysAgo * the number of days ago to generate data for */ private void generateDailyUsageSummaryForDay(final int inDaysAgo) { Date reportDate = DateDayExtractor.getStartOfDay(daysAgoDateStrategy.execute(inDaysAgo)); if (!dayOfWeekStrategy.isWeekday(reportDate)) { logger.info("Ignoring " + reportDate + " - it's a weekend"); return; } logger.info("Checking id daily usage summary data exists for " + reportDate); DailyUsageSummary existingSummary = getDailyUsageSummaryByDateMapper .execute(new UsageMetricDailyStreamInfoRequest(reportDate, null)); clearEntityManagerMapper.execute(null); if (existingSummary != null) { logger.info("Data already exists for " + reportDate); return; } // generate data for all streams generateDailyUsageSummaryForStreamScope(reportDate, null); // now generate data for each stream List<Long> streamScopeIds = streamScopeIdsMapper.execute(reportDate); for (Long streamScopeId : streamScopeIds) { generateDailyUsageSummaryForStreamScope(reportDate, streamScopeId); } logger.info("Inserted Daily Summary metrics for " + reportDate); } /** * Generate the daily usage summary for the stream scope with the input id, and for the given date. * * @param inDate * the date to generate for * @param inStreamScopeId * the streamscope id to generate stats for */ private void generateDailyUsageSummaryForStreamScope(final Date inDate, final Long inStreamScopeId) { try { UsageMetricDailyStreamInfoRequest streamInfoRequest = new UsageMetricDailyStreamInfoRequest(inDate, inStreamScopeId); String timerLog = "TimerData:" + inStreamScopeId; long start; long totalStart = System.currentTimeMillis(); long uniqueVisitorCount = 0; long pageViewCount = 0; long streamViewCount = 0; long streamViewerCount = 0; long streamContributorCount = 0; long messageCount = 0; long avgActvityResponeTime = 0; Long totalActivityCount = null; Long totalCommentCount = null; Long totalContributorCount = null; // get the stream view count - logger.info("Generating number of stream views for " + inDate); start = System.currentTimeMillis(); clearEntityManagerMapper.execute(null); streamViewCount = getDailyStreamViewCountMapper.execute(streamInfoRequest); timerLog += "\t1: " + (System.currentTimeMillis() - start); if (inStreamScopeId == null) { // doesn't make sense on a per-stream basis logger.info("Generating number of unique visitors for " + inDate); clearEntityManagerMapper.execute(null); uniqueVisitorCount = getDailyUniqueVisitorCountMapper.execute(inDate); logger.info("Generating number of page views for " + inDate); clearEntityManagerMapper.execute(null); pageViewCount = getDailyPageViewCountMapper.execute(inDate); logger.info("Generating average activity comment time (for those with comments on the same day) for " + inDate); clearEntityManagerMapper.execute(null); avgActvityResponeTime = getDailyMessageResponseTimeMapper.execute(inDate); } else { // these are only generated for individual streams start = System.currentTimeMillis(); clearEntityManagerMapper.execute(null); totalActivityCount = getTotalActivityCountMapper.execute(streamInfoRequest); timerLog += "\t2: " + (System.currentTimeMillis() - start); start = System.currentTimeMillis(); clearEntityManagerMapper.execute(null); totalCommentCount = getTotalCommentCountMapper.execute(streamInfoRequest); timerLog += "\t3: " + (System.currentTimeMillis() - start); start = System.currentTimeMillis(); clearEntityManagerMapper.execute(null); totalContributorCount = getTotalStreamContributorMapper.execute(streamInfoRequest); timerLog += "\t4: " + (System.currentTimeMillis() - start); } logger.info("Generating number of stream viewers for " + inDate); start = System.currentTimeMillis(); clearEntityManagerMapper.execute(null); streamViewerCount = getDailyStreamViewerCountMapper.execute(streamInfoRequest); timerLog += "\t6: " + (System.currentTimeMillis() - start); logger.info("Generating number of stream contributors for " + inDate); start = System.currentTimeMillis(); clearEntityManagerMapper.execute(null); streamContributorCount = getDailyStreamContributorCountMapper.execute(streamInfoRequest); timerLog += "\t7: " + (System.currentTimeMillis() - start); logger.info("Generating number of messages (activities and comments) for " + inDate); start = System.currentTimeMillis(); clearEntityManagerMapper.execute(null); messageCount = getDailyMessageCountMapper.execute(streamInfoRequest); timerLog += "\t8: " + (System.currentTimeMillis() - start); DailyUsageSummary data = new DailyUsageSummary(uniqueVisitorCount, pageViewCount, streamViewerCount, streamViewCount, streamContributorCount, messageCount, avgActvityResponeTime, inDate, inDate.getTime(), inStreamScopeId, totalActivityCount, totalCommentCount, totalContributorCount); // store this logger.info("Inserting daily usage metric data for " + inDate); start = System.currentTimeMillis(); clearEntityManagerMapper.execute(null); insertMapper.execute(new PersistenceRequest<DailyUsageSummary>(data)); timerLog += "\t9: " + (System.currentTimeMillis() - start); // fetch the stream's data, which should be configured to force a cache refresh start = System.currentTimeMillis(); clearEntityManagerMapper.execute(null); summaryDataMapper.execute(new UsageMetricStreamSummaryRequest(numberOfDaysToCacheSummaryDataFor, inStreamScopeId)); timerLog += "\t10: " + (System.currentTimeMillis() - start); timerLog += "\tTOTAL: " + (System.currentTimeMillis() - totalStart); logger.trace(timerLog); } catch (Exception e) { logger.error("Error generating daily usage summary for date: " + inDate + " and stream scope id " + inStreamScopeId); } } }