001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: https://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: https://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.file.collectors; 029 030import org.opencms.file.CmsDataAccessException; 031import org.opencms.file.CmsObject; 032import org.opencms.file.CmsResource; 033import org.opencms.file.CmsResourceFilter; 034import org.opencms.file.types.I_CmsResourceType; 035import org.opencms.loader.CmsLoaderException; 036import org.opencms.main.CmsException; 037import org.opencms.main.CmsLog; 038import org.opencms.main.CmsRuntimeException; 039import org.opencms.main.OpenCms; 040import org.opencms.util.CmsStringUtil; 041 042import java.util.ArrayList; 043import java.util.Arrays; 044import java.util.Collections; 045import java.util.List; 046import java.util.Map; 047 048import org.apache.commons.logging.Log; 049 050/** 051 * A resource collector that collects resources changed in a given time frame and supports flexible sorting based on resource dates.<p> 052 * 053 * @since 8.0 054 */ 055public class CmsChangedResourceCollector extends A_CmsResourceCollector { 056 057 /** The collector parameter key for the maximum number of resources to return. */ 058 public static final String PARAM_KEY_COUNT = "count"; 059 060 /** The collector parameter key for the date from which a resource should be changed. */ 061 public static final String PARAM_KEY_DATEFROM = "datefrom"; 062 063 /** The collector parameter key for the date to which a resource should be changed. */ 064 public static final String PARAM_KEY_DATETO = "dateto"; 065 066 /** The collector parameter key for the name of the resource type to exclude from the result. */ 067 public static final String PARAM_KEY_EXCLUDETYPE = "excludetype"; 068 069 /** The collector parameter key for the resource, i.e. the parent folder from which the subscribed or visited resources should be read from. */ 070 public static final String PARAM_KEY_RESOURCE = "resource"; 071 072 /** The collector parameter key for the sort attribute that should be used to sort the result. */ 073 public static final String PARAM_KEY_SORTBY = "sortby"; 074 075 /** Static array of the collectors implemented by this class. */ 076 private static final String[] COLLECTORS = { 077 "allChangedInFolderDateDesc", 078 "allChangedInFolderDateAsc", 079 "allChangedInSubTreeDateDesc", 080 "allChangedInSubTreeDateAsc"}; 081 082 /** Array list for fast collector name lookup. */ 083 private static final List<String> COLLECTORS_LIST = Collections.unmodifiableList(Arrays.asList(COLLECTORS)); 084 085 /** The log object for this class. */ 086 private static final Log LOG = CmsLog.getLog(CmsChangedResourceCollector.class); 087 088 /** 089 * @see org.opencms.file.collectors.I_CmsResourceCollector#getCollectorNames() 090 */ 091 public List<String> getCollectorNames() { 092 093 return COLLECTORS_LIST; 094 } 095 096 /** 097 * @see org.opencms.file.collectors.I_CmsResourceCollector#getCreateLink(org.opencms.file.CmsObject, java.lang.String, java.lang.String) 098 */ 099 public String getCreateLink(CmsObject cms, String collectorName, String param) { 100 101 // this collector does not support creation of new resources 102 return null; 103 } 104 105 /** 106 * @see org.opencms.file.collectors.I_CmsResourceCollector#getCreateParam(org.opencms.file.CmsObject, java.lang.String, java.lang.String) 107 */ 108 public String getCreateParam(CmsObject cms, String collectorName, String param) { 109 110 // this collector does not support creation of new resources 111 return null; 112 } 113 114 /** 115 * @see org.opencms.file.collectors.I_CmsResourceCollector#getResults(org.opencms.file.CmsObject, java.lang.String, java.lang.String) 116 */ 117 public List<CmsResource> getResults(CmsObject cms, String collectorName, String param) 118 throws CmsDataAccessException, CmsException { 119 120 return getResults(cms, collectorName, param, -1); 121 } 122 123 /** 124 * @see org.opencms.file.collectors.I_CmsResourceCollector#getResults(org.opencms.file.CmsObject, java.lang.String, java.lang.String) 125 */ 126 public List<CmsResource> getResults(CmsObject cms, String collectorName, String param, int numResults) 127 throws CmsDataAccessException, CmsException { 128 129 // if action is not set use default 130 if (collectorName == null) { 131 collectorName = COLLECTORS[0]; 132 } 133 134 switch (COLLECTORS_LIST.indexOf(collectorName)) { 135 case 0: 136 // "allChangedInFolderDateDesc" 137 return allChangedInFolderDate(cms, param, false, false, numResults); 138 case 1: 139 // "allChangedInFolderDateAsc" 140 return allChangedInFolderDate(cms, param, false, true, numResults); 141 case 2: 142 // "allChangedInSubTreeDateDesc" 143 return allChangedInFolderDate(cms, param, true, false, numResults); 144 case 3: 145 // "allChangedInSubTreeDateAsc" 146 return allChangedInFolderDate(cms, param, true, true, numResults); 147 default: 148 throw new CmsDataAccessException( 149 Messages.get().container(Messages.ERR_COLLECTOR_NAME_INVALID_1, collectorName)); 150 } 151 } 152 153 /** 154 * Returns a List of all changed resources in the folder pointed to by the parameter 155 * sorted by the date attributes specified in the parameter.<p> 156 * 157 * @param cms the current CmsObject 158 * @param param must contain an extended collector parameter set as described by {@link CmsExtendedCollectorData} 159 * @param tree if true, look in folder and all child folders, if false, look only in given folder 160 * @param asc if <code>true</code>, the sort is ascending (old dates first), otherwise it is descending 161 * (new dates first) 162 * @param numResults number of results 163 * 164 * @return a List of all resources in the folder pointed to by the parameter sorted by the selected dates 165 * 166 * @throws CmsException if something goes wrong 167 */ 168 protected List<CmsResource> allChangedInFolderDate( 169 CmsObject cms, 170 String param, 171 boolean tree, 172 boolean asc, 173 int numResults) 174 throws CmsException { 175 176 Map<String, String> params = getParameters(param); 177 178 String foldername = "/"; 179 if (params.containsKey(PARAM_KEY_RESOURCE)) { 180 foldername = CmsResource.getFolderPath(params.get(PARAM_KEY_RESOURCE)); 181 } 182 183 long dateFrom = 0L; 184 long dateTo = Long.MAX_VALUE; 185 if (params.containsKey(PARAM_KEY_DATEFROM)) { 186 try { 187 dateFrom = Long.parseLong(params.get(PARAM_KEY_DATEFROM)); 188 } catch (NumberFormatException e) { 189 // error parsing from date 190 LOG.error( 191 Messages.get().getBundle().key( 192 Messages.ERR_COLLECTOR_PARAM_INVALID_1, 193 PARAM_KEY_DATEFROM + "=" + params.get(PARAM_KEY_DATEFROM))); 194 throw e; 195 } 196 } 197 if (params.containsKey(PARAM_KEY_DATETO)) { 198 try { 199 dateTo = Long.parseLong(params.get(PARAM_KEY_DATETO)); 200 } catch (NumberFormatException e) { 201 // error parsing to date 202 LOG.error( 203 Messages.get().getBundle().key( 204 Messages.ERR_COLLECTOR_PARAM_INVALID_1, 205 PARAM_KEY_DATETO + "=" + params.get(PARAM_KEY_DATETO))); 206 throw e; 207 } 208 } 209 210 // create the filter to read the resources 211 CmsResourceFilter filter = CmsResourceFilter.DEFAULT_FILES.addExcludeFlags( 212 CmsResource.FLAG_TEMPFILE).addRequireLastModifiedAfter(dateFrom).addRequireLastModifiedBefore(dateTo); 213 214 // check if a resource type has to be excluded 215 if (params.containsKey(PARAM_KEY_EXCLUDETYPE)) { 216 String excludeType = params.get(PARAM_KEY_EXCLUDETYPE); 217 int typeId = -1; 218 try { 219 // try to look up the resource type 220 I_CmsResourceType resourceType = OpenCms.getResourceManager().getResourceType(excludeType); 221 typeId = resourceType.getTypeId(); 222 } catch (CmsLoaderException e1) { 223 // maybe the int ID is directly used? 224 try { 225 int typeInt = Integer.parseInt(excludeType); 226 I_CmsResourceType resourceType = OpenCms.getResourceManager().getResourceType(typeInt); 227 typeId = resourceType.getTypeId(); 228 if (LOG.isWarnEnabled()) { 229 LOG.warn( 230 Messages.get().getBundle().key( 231 Messages.LOG_RESTYPE_INTID_2, 232 resourceType.getTypeName(), 233 Integer.valueOf(resourceType.getTypeId()))); 234 } 235 } catch (NumberFormatException e2) { 236 // bad number format used for type 237 throw new CmsRuntimeException( 238 Messages.get().container( 239 Messages.ERR_COLLECTOR_PARAM_INVALID_1, 240 PARAM_KEY_EXCLUDETYPE + "=" + params.get(PARAM_KEY_EXCLUDETYPE)), 241 e2); 242 } catch (CmsLoaderException e2) { 243 // this resource type does not exist 244 throw new CmsRuntimeException( 245 Messages.get().container(Messages.ERR_UNKNOWN_RESTYPE_1, excludeType), 246 e2); 247 } 248 } 249 if (typeId != -1) { 250 filter = filter.addExcludeType(typeId); 251 } 252 } 253 254 // read the resources using the configured filter 255 List<CmsResource> result = cms.readResources(foldername, filter, tree); 256 257 // determine which attribute should be used to sort the result 258 String sortBy = CmsDateResourceComparator.DATE_ATTRIBUTES_LIST.get(1); 259 if (params.containsKey(PARAM_KEY_SORTBY)) { 260 sortBy = params.get(PARAM_KEY_SORTBY); 261 } 262 List<String> dateIdentifiers = new ArrayList<String>(1); 263 dateIdentifiers.add(sortBy); 264 265 // a special date comparator is used to sort the resources 266 CmsDateResourceComparator comparator = new CmsDateResourceComparator(cms, dateIdentifiers, asc); 267 Collections.sort(result, comparator); 268 269 int count = -1; 270 if (params.containsKey(PARAM_KEY_COUNT)) { 271 try { 272 count = Integer.parseInt(params.get(PARAM_KEY_COUNT)); 273 } catch (NumberFormatException e) { 274 // error parsing the count 275 LOG.error( 276 Messages.get().getBundle().key( 277 Messages.ERR_COLLECTOR_PARAM_INVALID_1, 278 PARAM_KEY_COUNT + "=" + params.get(PARAM_KEY_COUNT))); 279 throw e; 280 } 281 } 282 if ((count > 0) || (numResults > 0)) { 283 return shrinkToFit(result, count, numResults); 284 } else { 285 return result; 286 } 287 } 288 289 /** 290 * Returns the collector parameters.<p> 291 * 292 * @param param the collector parameter 293 * 294 * @return the collector parameters 295 */ 296 private Map<String, String> getParameters(String param) { 297 298 if (CmsStringUtil.isNotEmpty(param)) { 299 return CmsStringUtil.splitAsMap(param, "|", "="); 300 } 301 return Collections.emptyMap(); 302 } 303}