/*
* This library is part of OpenCms -
* the Open Source Content Management System
*
* Copyright (c) Alkacon Software GmbH (http://www.alkacon.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* For further information about Alkacon Software, please see the
* company website: http://www.alkacon.com
*
* For further information about OpenCms, please see the
* project website: http://www.opencms.org
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.opencms.ade.publish;
import org.opencms.file.CmsResource;
import org.opencms.main.CmsLog;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.commons.logging.Log;
/**
* Helper class for splitting a publish list into publish groups.<p>
*
* @since 8.0.0
*/
public class CmsPublishGroupHelper {
/** An enum representing the age of a publish list resource. */
public enum GroupAge {
/** group age constant. */
medium,
/** group age constant. */
old,
/** group age constant. */
young
}
/** The log instance for this class. */
private static final Log LOG = CmsLog.getLog(CmsPublishGroupHelper.class);
/** The gap between session groups. */
protected static final int GROUP_SESSIONS_GAP = 8 * 60 * 60 * 1000;
/** The current locale. */
private Locale m_locale;
/**
* Creates a new publish group helper for a given locale.<p>
*
* @param locale the locale to use
*/
public CmsPublishGroupHelper(Locale locale) {
m_locale = locale;
}
/**
* Given a descending list of dates represented as longs, this method computes a map from the dates
* to their age in (local) days.<p>
*
* @param sortedDates a descending list of dates represented as longs
*
* @return a map from dates to ages (measured in days)
*/
public Map<Long, Integer> computeDays(List<Long> sortedDates) {
if (sortedDates.isEmpty()) {
return Collections.<Long, Integer> emptyMap();
}
Map<Long, Integer> days = new HashMap<Long, Integer>();
long lastDate = System.currentTimeMillis();
int dayCounter = 0;
for (Long dateObj : sortedDates) {
long date = dateObj.longValue();
long dayDifference = getDayDifference(lastDate, date);
dayCounter += dayDifference;
lastDate = date;
days.put(dateObj, new Integer(dayCounter));
}
return days;
}
/**
* Computes a map from modification date to number of (local) days since the modification date.<p>
*
* @param resources a list of resources
*
* @return a map from modification dates to the number of days since the modification date
*/
public Map<Long, Integer> computeDaysForResources(List<CmsResource> resources) {
Map<Long, Integer> result = computeDays(getModificationDates(resources));
if (LOG.isDebugEnabled()) {
for (CmsResource res : resources) {
LOG.debug("Resource "
+ res.getRootPath()
+ " is "
+ result.get(new Long(res.getDateLastModified()))
+ " days old.");
}
}
return result;
}
/**
* Gets the difference in days between to dates given as longs.<p>
*
* The first date must be later than the second date.
*
* @param first the first date
* @param second the second date
*
* @return the difference between the two dates in days
*/
public int getDayDifference(long first, long second) {
if (first < second) {
throw new IllegalArgumentException();
}
Calendar firstDay = getStartOfDay(first);
Calendar secondDay = getStartOfDay(second);
int result = 0;
while (firstDay.after(secondDay)) {
firstDay.add(Calendar.DAY_OF_MONTH, -1);
result += 1;
}
return result;
}
/**
* Given a list of resources, this method returns a list of their modification dates.<p>
*
* @param resources a list of resources
*
* @return the modification dates of the resources, in the same order as the resources
*/
public List<Long> getModificationDates(List<CmsResource> resources) {
List<Long> result = new ArrayList<Long>();
for (CmsResource res : resources) {
result.add(new Long(res.getDateLastModified()));
}
return result;
}
/**
* Returns the localized name for a given publish group based on its age.<p>
*
* @param resources the resources of the publish group
* @param age the age of the publish group
*
* @return the localized name of the publish group
*/
public String getPublishGroupName(List<CmsResource> resources, GroupAge age) {
long groupDate = resources.get(0).getDateLastModified();
String groupName;
switch (age) {
case young:
groupName = Messages.get().getBundle(m_locale).key(
Messages.GUI_GROUPNAME_SESSION_1,
new Date(groupDate));
break;
case medium:
groupName = Messages.get().getBundle(m_locale).key(Messages.GUI_GROUPNAME_DAY_1, new Date(groupDate));
break;
case old:
default:
groupName = Messages.get().getBundle(m_locale).key(Messages.GUI_GROUPNAME_EVERYTHING_ELSE_0);
break;
}
return groupName;
}
/**
* Returns a calendar object representing the start of the day in which a given time lies.<p>
*
* @param time a long representing a time
*
* @return a calendar object which represents the day in which the time lies
*/
public Calendar getStartOfDay(long time) {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(time);
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH);
int day = cal.get(Calendar.DAY_OF_MONTH);
Calendar result = Calendar.getInstance();
result.set(Calendar.YEAR, year);
result.set(Calendar.MONTH, month);
result.set(Calendar.DAY_OF_MONTH, day);
return result;
}
/**
* Computes publish groups for a list of resources with age "medium".<p>
*
* @param resources the list of resources
* @param days a map from modification dates to the number of days since the modification
*
* @return a list of publish groups
*/
public List<List<CmsResource>> partitionMediumResources(List<CmsResource> resources, Map<Long, Integer> days) {
if (resources.isEmpty()) {
return Collections.<List<CmsResource>> emptyList();
}
CmsResource firstRes = resources.get(0);
int lastDay = days.get(new Long(firstRes.getDateLastModified())).intValue();
List<List<CmsResource>> result = new ArrayList<List<CmsResource>>();
List<CmsResource> currentGroup = new ArrayList<CmsResource>();
result.add(currentGroup);
for (CmsResource res : resources) {
LOG.debug("Processing medium-aged resource " + res.getRootPath());
int day = days.get(new Long(res.getDateLastModified())).intValue();
if (day != lastDay) {
LOG.debug("=== new group ===");
currentGroup = new ArrayList<CmsResource>();
result.add(currentGroup);
}
lastDay = day;
currentGroup.add(res);
}
return result;
}
/**
* Partitions a list of resources by their age in (local) days since the last modification.<p>
*
* @param resources the list of resources to partition
* @param days the map from modification dates to the number of (local) days since the modification
*
* @return a map from age enum values to the list of resources which fall into the corresponding age group
*/
public Map<GroupAge, List<CmsResource>> partitionPublishResourcesByAge(
List<CmsResource> resources,
Map<Long, Integer> days) {
List<CmsResource> youngRes = new ArrayList<CmsResource>();
List<CmsResource> mediumRes = new ArrayList<CmsResource>();
List<CmsResource> oldRes = new ArrayList<CmsResource>();
for (CmsResource res : resources) {
int day = days.get(new Long(res.getDateLastModified())).intValue();
List<CmsResource> listToAddTo = null;
if (day < 7) {
listToAddTo = youngRes;
LOG.debug("Classifying publish resource " + res.getRootPath() + " as young");
} else if (day < 28) {
listToAddTo = mediumRes;
LOG.debug("Classifying publish resource " + res.getRootPath() + " as medium-aged");
} else {
listToAddTo = oldRes;
LOG.debug("Classifying publish resource " + res.getRootPath() + " as old");
}
listToAddTo.add(res);
}
Map<GroupAge, List<CmsResource>> result = new HashMap<GroupAge, List<CmsResource>>();
result.put(GroupAge.young, youngRes);
result.put(GroupAge.medium, mediumRes);
result.put(GroupAge.old, oldRes);
return result;
}
/**
* Partitions the list of young resources into publish groups.<p>
*
* @param resources the list of resources to partition
*
* @return a partition of the resources into publish groups
*/
public List<List<CmsResource>> partitionYoungResources(List<CmsResource> resources) {
if (resources.isEmpty()) {
return Collections.<List<CmsResource>> emptyList();
}
List<List<CmsResource>> result = new ArrayList<List<CmsResource>>();
List<CmsResource> currentGroup = new ArrayList<CmsResource>();
result.add(currentGroup);
long lastDate = resources.get(0).getDateLastModified();
for (CmsResource res : resources) {
LOG.debug("Processing young resource " + res.getRootPath());
long resDate = res.getDateLastModified();
if (lastDate - resDate > GROUP_SESSIONS_GAP) {
LOG.debug("=== new group ===");
currentGroup = new ArrayList<CmsResource>();
result.add(currentGroup);
}
lastDate = resDate;
currentGroup.add(res);
}
return result;
}
}