/** * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Apereo * 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 the * following location: * * <p>http://www.apache.org/licenses/LICENSE-2.0 * * <p>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.apereo.portal.portlets.activity; import com.google.visualization.datasource.base.TypeMismatchException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.portlet.PortletPreferences; import javax.portlet.PortletRequest; import org.apereo.portal.events.aggr.AggregationInterval; import org.apereo.portal.events.aggr.action.SearchRequestAggregation; import org.apereo.portal.events.aggr.action.SearchRequestAggregationDao; import org.apereo.portal.events.aggr.action.SearchRequestAggregationImpl; import org.apereo.portal.events.aggr.concuser.ConcurrentUserAggregation; import org.apereo.portal.events.aggr.concuser.ConcurrentUserAggregationDao; import org.apereo.portal.events.aggr.concuser.ConcurrentUserAggregationKey; import org.apereo.portal.events.aggr.concuser.ConcurrentUserAggregationKeyImpl; import org.apereo.portal.events.aggr.groups.AggregatedGroupLookupDao; import org.apereo.portal.events.aggr.groups.AggregatedGroupMapping; import org.apereo.portal.events.aggr.login.LoginAggregation; import org.apereo.portal.events.aggr.login.LoginAggregationDao; import org.apereo.portal.events.aggr.login.LoginAggregationKey; import org.apereo.portal.events.aggr.login.LoginAggregationKeyImpl; import org.apereo.portal.groups.IEntityGroup; import org.apereo.portal.security.IPerson; import org.apereo.portal.services.GroupService; import org.joda.time.DateMidnight; import org.joda.time.DateTime; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.portlet.bind.annotation.RenderMapping; import org.springframework.web.servlet.ModelAndView; @Controller @RequestMapping("VIEW") public class ActivityController { private static final String PREFERENCE_PREFIX = "PortalActivity." + ActivityController.class.getSimpleName() + "."; private static final String PREFERENCE_MASTER_GROUP = PREFERENCE_PREFIX + "masterGroup"; private static final String PREFERENCE_DISPLAY_GROUPS = PREFERENCE_PREFIX + "displayGroups"; private static final String PREFERENCE_DISPLAY_OTHER = PREFERENCE_PREFIX + "displayOther"; private static final String PREFERENCE_UNIQUE_LOGINS = PREFERENCE_PREFIX + "uniqueLogins"; private static final String PREFERENCE_SHOW_SEACHES = PREFERENCE_PREFIX + "showSearches"; private static final String DEFAULT_PREFERENCE_MASTER_GROUP = "Everyone"; private static final String[] DEFAULT_PREFERENCE_DISPLAY_GROUPS = new String[] {}; private static final String DEFAULT_PREFERENCE_DISPLAY_OTHER = "true"; private static final String DEFAULT_PREFERENCE_UNIQUE_LOGINS = "true"; private static final String DEFAULT_PREFERENCE_SHOW_SEARCHES = "true"; private static final int NOW = 1; private static final int TODAY = 2; private static final int YESTERDAY = 3; private AggregatedGroupLookupDao aggregatedGroupLookupDao; private SearchRequestAggregationDao<SearchRequestAggregation> searchRequestAggregationDao; private ConcurrentUserAggregationDao<ConcurrentUserAggregation> concurrentUserAggregationDao; private LoginAggregationDao<LoginAggregation> loginAggregationDao; @Autowired public void setAggregatedGroupLookupDao(AggregatedGroupLookupDao aggregatedGroupLookupDao) { this.aggregatedGroupLookupDao = aggregatedGroupLookupDao; } @Autowired public void setSearchRequestAggregationDao( SearchRequestAggregationDao<SearchRequestAggregation> searchRequestAggregationDao) { this.searchRequestAggregationDao = searchRequestAggregationDao; } @Autowired public void setConcurrentUserAggregationDao( ConcurrentUserAggregationDao<ConcurrentUserAggregation> concurrentUserAggregationDao) { this.concurrentUserAggregationDao = concurrentUserAggregationDao; } @Autowired public void setLoginAggregationDao(LoginAggregationDao<LoginAggregation> loginAggregationDao) { this.loginAggregationDao = loginAggregationDao; } @RenderMapping public ModelAndView summary(PortletRequest request) throws TypeMismatchException { final Map<String, Object> model = new HashMap<String, Object>(); final PortalActivity now = buildPortalActivity(request, NOW); final PortalActivity today = buildPortalActivity(request, TODAY); final PortalActivity yesterday = buildPortalActivity(request, YESTERDAY); model.put("usageNow", now); model.put("usageToday", today); model.put("usageYesterday", yesterday); // Searches List<SearchInfo> popularSearchTerms = Collections.emptyList(); // default final PortletPreferences prefs = request.getPreferences(); final Boolean showSearches = Boolean.valueOf( prefs.getValue(PREFERENCE_SHOW_SEACHES, DEFAULT_PREFERENCE_SHOW_SEARCHES)); if (showSearches) { popularSearchTerms = getPopularSearchTerms(); } model.put("showSearches", showSearches); model.put("popularSearchTerms", popularSearchTerms); return new ModelAndView("jsp/Activity/activity", model); } private PortalActivity buildPortalActivity(PortletRequest request, int timeframe) { PortletPreferences prefs = request.getPreferences(); DateTime begin, end; final AggregationInterval interval; final List<PortalGroupActivity> groupActivities = new ArrayList<PortalGroupActivity>(); switch (timeframe) { case NOW: { end = new DateTime(); begin = end.minusHours(1); interval = AggregationInterval.FIVE_MINUTE; break; } case TODAY: { begin = new DateMidnight().toDateTime(); end = begin.plusDays(1); interval = AggregationInterval.DAY; break; } case YESTERDAY: { end = new DateMidnight().toDateTime().minusSeconds(1); begin = end.minusDays(1); interval = AggregationInterval.DAY; break; } default: { end = new DateTime(); begin = end.minusHours(1); interval = AggregationInterval.HOUR; break; } } String masterGroup = prefs.getValue(PREFERENCE_MASTER_GROUP, DEFAULT_PREFERENCE_MASTER_GROUP); List<String> displayGroups = Arrays.asList( prefs.getValues( PREFERENCE_DISPLAY_GROUPS, DEFAULT_PREFERENCE_DISPLAY_GROUPS)); boolean displayOther = Boolean.valueOf( prefs.getValue(PREFERENCE_DISPLAY_OTHER, DEFAULT_PREFERENCE_DISPLAY_OTHER)); int masterTotal = 0; int absTotal = 0; int subTotal = 0; switch (timeframe) { case NOW: for (AggregatedGroupMapping group : concurrentUserAggregationDao.getAggregatedGroupMappings()) { ConcurrentUserAggregationKey key = new ConcurrentUserAggregationKeyImpl(interval, group); final List<ConcurrentUserAggregation> aggregations = concurrentUserAggregationDao.getAggregations(begin, end, key); // NB: We only care about the most recent entry (??) if (aggregations.size() != 0) { final ConcurrentUserAggregation aggregation = aggregations.get(0); int groupTotal = aggregation.getConcurrentUsers(); absTotal += aggregation.getConcurrentUsers(); if (group.getGroupName().equalsIgnoreCase(masterGroup)) { masterTotal = groupTotal; } else { subTotal += groupTotal; } if (!group.getGroupName().equals(masterGroup)) { if (displayGroups.isEmpty() || displayGroups.contains(group.getGroupName())) { final PortalGroupActivity groupActivity = new PortalGroupActivity(group.getGroupName(), groupTotal); groupActivities.add(groupActivity); } } } } break; default: String uniqueLoginsPref = prefs.getValue(PREFERENCE_UNIQUE_LOGINS, DEFAULT_PREFERENCE_UNIQUE_LOGINS); Boolean uniqueLogins = Boolean.valueOf(uniqueLoginsPref); for (AggregatedGroupMapping group : loginAggregationDao.getAggregatedGroupMappings()) { final LoginAggregationKey key = new LoginAggregationKeyImpl(interval, group); final List<LoginAggregation> aggregations = loginAggregationDao.getAggregations(begin, end, key); // NB: We only care about the most recent entry (??) if (aggregations.size() != 0) { final LoginAggregation aggregation = aggregations.get(0); int groupTotal = getAggregationLoginCount(aggregation, uniqueLogins); absTotal += groupTotal; if (group.getGroupName().equalsIgnoreCase(masterGroup)) { masterTotal = groupTotal; } else { subTotal += groupTotal; } if (!group.getGroupName().equals(masterGroup)) { if (displayGroups.isEmpty() || displayGroups.contains(group.getGroupName())) { PortalGroupActivity groupActivity = new PortalGroupActivity(group.getGroupName(), groupTotal); groupActivities.add(groupActivity); } } } } break; } if (displayOther) { int otherTotal = masterTotal - subTotal; if (otherTotal > 0) { PortalGroupActivity otherGroup = new PortalGroupActivity("Other", otherTotal); groupActivities.add(otherGroup); } } Collections.sort(groupActivities); Collections.reverse(groupActivities); int total = masterTotal > 0 ? masterTotal : absTotal; final PortalActivity activity = new PortalActivity(total, groupActivities); return activity; } private List<SearchInfo> getPopularSearchTerms() { DateTime end = new DateTime(); DateTime begin = end.minusDays(1); final IEntityGroup everyone = GroupService.getRootGroup(IPerson.class); final AggregatedGroupMapping group = aggregatedGroupLookupDao.getGroupMapping(everyone.getKey()); List<SearchRequestAggregationImpl> aggregations = searchRequestAggregationDao.getAggregations( begin, end, AggregationInterval.FIVE_MINUTE, group); Map<String, SearchInfo> resultBuilder = new HashMap<String, SearchInfo>(); for (SearchRequestAggregationImpl aggregation : aggregations) { SearchInfo info = resultBuilder.get(aggregation.getSearchTerm()); if (info == null) { info = new SearchInfo(aggregation.getSearchTerm(), aggregation.getCount()); resultBuilder.put(aggregation.getSearchTerm(), info); } else { info.incrementCount(aggregation.getCount()); } } List<SearchInfo> results = new ArrayList<SearchInfo>(resultBuilder.values()); Collections.sort(results); Collections.reverse(results); return results.size() > 10 ? results.subList(0, 9) : results; } private int getAggregationLoginCount(LoginAggregation aggregation, boolean unique) { return unique ? aggregation.getUniqueLoginCount() : aggregation.getLoginCount(); } }