/** * 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.statistics; import com.google.visualization.datasource.base.TypeMismatchException; import com.google.visualization.datasource.datatable.ColumnDescription; import com.google.visualization.datasource.datatable.value.NumberValue; import com.google.visualization.datasource.datatable.value.Value; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import org.apereo.portal.events.aggr.AggregationInterval; import org.apereo.portal.events.aggr.BaseAggregationDao; import org.apereo.portal.events.aggr.BaseAggregationDateTimeComparator; import org.apereo.portal.events.aggr.groups.AggregatedGroupLookupDao; import org.apereo.portal.events.aggr.groups.AggregatedGroupMapping; import org.apereo.portal.events.aggr.portletexec.PortletExecutionAggregation; import org.apereo.portal.events.aggr.portletexec.PortletExecutionAggregationDao; import org.apereo.portal.events.aggr.portletexec.PortletExecutionAggregationDiscriminator; import org.apereo.portal.events.aggr.portletexec.PortletExecutionAggregationDiscriminatorImpl; import org.apereo.portal.events.aggr.portletexec.PortletExecutionAggregationKey; import org.apereo.portal.events.aggr.portletexec.PortletExecutionAggregationKey.ExecutionType; import org.apereo.portal.events.aggr.portletexec.PortletExecutionAggregationKeyImpl; import org.apereo.portal.events.aggr.portlets.AggregatedPortletLookupDao; import org.apereo.portal.events.aggr.portlets.AggregatedPortletMapping; import org.apereo.portal.events.aggr.portlets.AggregatedPortletMappingNameComparator; import org.apereo.portal.portlets.statistics.ReportTitleAndColumnDescriptionStrategy.TitleAndCount; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.portlet.ModelAndView; import org.springframework.web.portlet.bind.annotation.RenderMapping; import org.springframework.web.portlet.bind.annotation.ResourceMapping; /** * Portlet Execution reports * */ @Controller @RequestMapping(value = "VIEW") public class PortletExecutionStatisticsController extends BaseStatisticsReportController< PortletExecutionAggregation, PortletExecutionAggregationKey, PortletExecutionAggregationDiscriminator, PortletExecutionReportForm> { private static final String DATA_TABLE_RESOURCE_ID = "portletExecutionData"; private static final String REPORT_NAME = "portletExecution.totals"; @Autowired private ReportTitleAndColumnDescriptionStrategy titleAndColumnDescriptionStrategy; @Autowired @Qualifier(value = "jpaPortletExecutionAggregationDao") private PortletExecutionAggregationDao<PortletExecutionAggregation> portletExecutionDao; @Autowired private AggregatedGroupLookupDao aggregatedGroupLookupDao; @Autowired private AggregatedPortletLookupDao aggregatedPortletLookupDao; public void setTitleAndColumnDescriptionStrategy( ReportTitleAndColumnDescriptionStrategy titleAndColumnDescriptionStrategy) { this.titleAndColumnDescriptionStrategy = titleAndColumnDescriptionStrategy; } @RenderMapping(value = "MAXIMIZED", params = "report=" + REPORT_NAME) public String getLoginView() throws TypeMismatchException { return "jsp/Statistics/reportGraph"; } @ResourceMapping(DATA_TABLE_RESOURCE_ID) public ModelAndView renderPortletExecutionAggregationReport(PortletExecutionReportForm form) throws TypeMismatchException { return renderAggregationReport(form); } @Override protected void initReportForm(PortletExecutionReportForm report) { selectFormDefaultPortlet(report); selectFormExecutionType(report); } /** Select the first portlet name by default for the form */ private void selectFormDefaultPortlet(final PortletExecutionReportForm report) { if (!report.getPortlets().isEmpty()) { //Portlets already selected, do nothin return; } final Set<AggregatedPortletMapping> portlets = this.getPortlets(); if (!portlets.isEmpty()) { report.getPortlets().add(portlets.iterator().next().getFname()); } } /** @return List of Portlets that exist for the aggregation */ @ModelAttribute("portlets") public Set<AggregatedPortletMapping> getPortlets() { final Set<AggregatedPortletMapping> groupMappings = aggregatedPortletLookupDao.getPortletMappings(); final Set<AggregatedPortletMapping> sortedGroupMappings = new TreeSet<AggregatedPortletMapping>( AggregatedPortletMappingNameComparator.INSTANCE); sortedGroupMappings.addAll(groupMappings); return sortedGroupMappings; } @ModelAttribute("executionTypes") public ExecutionType[] getExecutionTypes() { return ExecutionType.values(); } /** Select the XXXX execution type by default for the form */ private void selectFormExecutionType(final PortletExecutionReportForm report) { if (!report.getExecutionTypeNames().isEmpty()) { //Already execution types set, do nothing return; } report.getExecutionTypeNames().add(ExecutionType.RENDER.name()); } @Override public String getReportName() { return REPORT_NAME; } @Override public String getReportDataResourceId() { return DATA_TABLE_RESOURCE_ID; } @Override protected BaseAggregationDao<PortletExecutionAggregation, PortletExecutionAggregationKey> getBaseAggregationDao() { return this.portletExecutionDao; } @Override protected Set<PortletExecutionAggregationKey> createAggregationsQueryKeyset( Set<PortletExecutionAggregationDiscriminator> columnDiscriminators, PortletExecutionReportForm form) { // Create keys (that exclude the temporal date/time information) from the interval // and the data in the column discriminators. final AggregationInterval interval = form.getInterval(); final HashSet<PortletExecutionAggregationKey> keys = new HashSet<PortletExecutionAggregationKey>(); for (PortletExecutionAggregationDiscriminator discriminator : columnDiscriminators) { keys.add( new PortletExecutionAggregationKeyImpl( interval, discriminator.getAggregatedGroup(), discriminator.getPortletMapping(), discriminator.getExecutionType())); } return keys; } @Override protected Comparator<? super PortletExecutionAggregationDiscriminator> getDiscriminatorComparator() { return PortletExecutionAggregationDiscriminatorImpl.Comparator.INSTANCE; } protected Map<PortletExecutionAggregationDiscriminator, SortedSet<PortletExecutionAggregation>> createColumnDiscriminatorMap(PortletExecutionReportForm form) { //Collections used to track the queried groups and the results final Map<PortletExecutionAggregationDiscriminator, SortedSet<PortletExecutionAggregation>> groupedAggregations = new TreeMap< PortletExecutionAggregationDiscriminator, SortedSet<PortletExecutionAggregation>>( PortletExecutionAggregationDiscriminatorImpl.Comparator.INSTANCE); //Get concrete group mapping objects that are being queried for List<Long> groups = form.getGroups(); Set<String> portletFNames = form.getPortlets(); Set<String> executionTypes = form.getExecutionTypeNames(); for (final Long queryGroupId : groups) { AggregatedGroupMapping groupMapping = this.aggregatedGroupLookupDao.getGroupMapping(queryGroupId); for (final String portletFName : portletFNames) { AggregatedPortletMapping tabMapping = this.aggregatedPortletLookupDao.getMappedPortletForFname(portletFName); for (String executionType : executionTypes) { final PortletExecutionAggregationDiscriminator mapping = new PortletExecutionAggregationDiscriminatorImpl( groupMapping, tabMapping, ExecutionType.valueOf(executionType)); //Create the set the aggregations for this report column will be stored in, sorted chronologically final SortedSet<PortletExecutionAggregation> aggregations = new TreeSet<PortletExecutionAggregation>( BaseAggregationDateTimeComparator.INSTANCE); //Map the group to the set groupedAggregations.put(mapping, aggregations); } } } return groupedAggregations; } /** * Create report title. Criteria that have a single value selected are put into the title. * Format and possible options are: * * <ul> * <li>null (no change needed) * <li>portlet * <li>portlet (execution) * <li>group * <li>group (execution) * <li>execution * <li>portlet - group (also displayed if one of each criteria selected) * </ul> * * @param form the form * @return report title */ @Override protected String getReportTitleAugmentation(PortletExecutionReportForm form) { int groupSize = form.getGroups().size(); int portletSize = form.getPortlets().size(); int executionTypeSize = form.getExecutionTypeNames().size(); // Look up names in case we need them. They should be in cache so no real performance hit. String firstPortletName = this.aggregatedPortletLookupDao .getMappedPortletForFname(form.getPortlets().iterator().next()) .getFname(); Long firstGroupId = form.getGroups().iterator().next().longValue(); String firstGroupName = this.aggregatedGroupLookupDao.getGroupMapping(firstGroupId).getGroupName(); String firstExecutionType = form.getExecutionTypeNames().iterator().next(); TitleAndCount[] items = new TitleAndCount[] { new TitleAndCount(firstPortletName, portletSize), new TitleAndCount(firstExecutionType, executionTypeSize), new TitleAndCount(firstGroupName, groupSize) }; return titleAndColumnDescriptionStrategy.getReportTitleAugmentation(items); } /** * Create column descriptions for the portlet report using the configured report labelling * strategy. * * @param reportColumnDiscriminator * @param form The original query form * @return */ @Override protected List<ColumnDescription> getColumnDescriptions( PortletExecutionAggregationDiscriminator reportColumnDiscriminator, PortletExecutionReportForm form) { int groupSize = form.getGroups().size(); int portletSize = form.getPortlets().size(); int executionTypeSize = form.getExecutionTypeNames().size(); String portletName = reportColumnDiscriminator.getPortletMapping().getFname(); String groupName = reportColumnDiscriminator.getAggregatedGroup().getGroupName(); String executionTypeName = reportColumnDiscriminator.getExecutionType().getName(); TitleAndCount[] items = new TitleAndCount[] { new TitleAndCount(portletName, portletSize), new TitleAndCount(executionTypeName, executionTypeSize), new TitleAndCount(groupName, groupSize) }; return titleAndColumnDescriptionStrategy.getColumnDescriptions( items, showFullColumnHeaderDescriptions(form), form); } @Override protected List<Value> createRowValues( PortletExecutionAggregation aggr, PortletExecutionReportForm form) { int count = aggr != null ? aggr.getExecutionCount() : 0; return Collections.<Value>singletonList(new NumberValue(count)); } }