001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://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: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://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.ade.contenteditor.shared.CmsEditorConstants; 031import org.opencms.ade.publish.CmsCollectorPublishListHelper; 032import org.opencms.file.CmsDataAccessException; 033import org.opencms.file.CmsFile; 034import org.opencms.file.CmsObject; 035import org.opencms.file.CmsRequestContext; 036import org.opencms.file.CmsResource; 037import org.opencms.file.CmsResourceFilter; 038import org.opencms.gwt.shared.CmsGwtConstants; 039import org.opencms.gwt.shared.I_CmsContentLoadCollectorInfo; 040import org.opencms.main.CmsException; 041import org.opencms.main.CmsIllegalArgumentException; 042import org.opencms.main.CmsLog; 043import org.opencms.main.OpenCms; 044import org.opencms.util.CmsPair; 045import org.opencms.util.CmsStringUtil; 046import org.opencms.xml.content.CmsXmlContent; 047import org.opencms.xml.content.CmsXmlContentFactory; 048 049import java.util.List; 050import java.util.Locale; 051import java.util.Set; 052 053import org.apache.commons.lang3.StringUtils; 054import org.apache.commons.lang3.math.NumberUtils; 055import org.apache.commons.logging.Log; 056 057/** 058 * Provides some helpful base implementations for resource collector classes.<p> 059 * 060 * @since 6.0.0 061 */ 062public abstract class A_CmsResourceCollector implements I_CmsResourceCollector { 063 064 /** The template file separator string for creating a new resource in direct edit mode, 065 * can be used to append an explicit template file name in {@link #getCreateParam(CmsObject, String, String)}. */ 066 public static final String SEPARATOR_TEMPLATEFILE = "::"; 067 068 /** Logger instance for this class. */ 069 private static final Log LOG = CmsLog.getLog(A_CmsResourceCollector.class); 070 071 /** The collector order of this collector. */ 072 protected int m_order; 073 074 /** The name of the configured default collector. */ 075 private String m_defaultCollectorName; 076 077 /** The default collector parameters. */ 078 private String m_defaultCollectorParam; 079 080 /** The hash code of this collector. */ 081 private int m_hashcode; 082 083 /** 084 * Constructor to initialize some default values.<p> 085 */ 086 public A_CmsResourceCollector() { 087 088 m_hashcode = getClass().getName().hashCode(); 089 } 090 091 /** 092 * Creates a new content collector resource.<p> 093 * 094 * @param cms the cms context 095 * @param newLink the new resource link 096 * @param locale the content locale 097 * @param referenceResource the reference resource 098 * @param modelFile the model file 099 * @param mode the optional creation mode (can be null) 100 * @param postCreateHandler optional class name of an {@link I_CmsCollectorPostCreateHandler} which is invoked after the content has been created. 101 * The fully qualified class name can be followed by a "|" symbol and a handler specific configuration string. 102 * @return the new file name 103 * 104 * @throws CmsException if something goes wrong 105 */ 106 public static String createResourceForCollector( 107 CmsObject cms, 108 String newLink, 109 Locale locale, 110 String referenceResource, 111 String modelFile, 112 String mode, 113 String postCreateHandler) 114 throws CmsException { 115 116 // get the collector used to create the new content 117 int pos = newLink.indexOf('|'); 118 String collectorName = newLink.substring(0, pos); 119 String collectorParams = newLink.substring(pos + 1); 120 121 String param; 122 String templateFileName; 123 124 pos = collectorParams.indexOf(A_CmsResourceCollector.SEPARATOR_TEMPLATEFILE); 125 if (pos != -1) { 126 // found an explicit template file name to use for the new resource, use it 127 param = collectorParams.substring(0, pos); 128 templateFileName = collectorParams.substring(pos + A_CmsResourceCollector.SEPARATOR_TEMPLATEFILE.length()); 129 } else { 130 // no template file name was specified, use given resource name as template file 131 param = collectorParams; 132 templateFileName = referenceResource; 133 } 134 135 // get the collector used for calculating the next file name 136 I_CmsResourceCollector collector = OpenCms.getResourceManager().getContentCollector(collectorName); 137 String newFileName = ""; 138 // one resource serves as a "template" for the new resource 139 CmsResource templateResource = cms.readResource(templateFileName, CmsResourceFilter.IGNORE_EXPIRATION); 140 CmsXmlContent newContent = null; 141 int typeId; 142 CmsObject cloneCms = OpenCms.initCmsObject(cms); 143 cloneCms.getRequestContext().setRequestTime(CmsResource.DATE_RELEASED_EXPIRED_IGNORE); 144 // the reference resource may be a folder in case of creating for an empty collector list 145 if (!templateResource.isFolder()) { 146 typeId = templateResource.getTypeId(); 147 CmsFile templateFile = cms.readFile(templateResource); 148 CmsXmlContent template = CmsXmlContentFactory.unmarshal(cloneCms, templateFile); 149 // now create a new XML content based on the templates content definition 150 newContent = CmsXmlContentFactory.createDocument( 151 cms, 152 locale, 153 template.getEncoding(), 154 template.getContentDefinition()); 155 } else { 156 typeId = collector.getCreateTypeId(cloneCms, collectorName, collectorParams); 157 } 158 // IMPORTANT: calculation of the name MUST be done here so the file name is ensured to be valid 159 newFileName = collector.getCreateLink(cms, collectorName, param); 160 161 boolean isCopy = StringUtils.equalsIgnoreCase(mode, CmsEditorConstants.MODE_COPY); 162 if (isCopy) { 163 modelFile = referenceResource; 164 } 165 boolean useModelFile = false; 166 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(modelFile)) { 167 cms.getRequestContext().setAttribute(CmsRequestContext.ATTRIBUTE_MODEL, modelFile); 168 useModelFile = true; 169 } 170 // now create the resource, fill it with the marshalled XML and write it back to the VFS 171 cms.createResource(newFileName, typeId); 172 // re-read the created resource 173 CmsFile newFile = cms.readFile(newFileName, CmsResourceFilter.ALL); 174 if (!useModelFile && (newContent != null)) { 175 newFile.setContents(newContent.marshal()); 176 // write the file with the updated content 177 cloneCms.writeFile(newFile); 178 } 179 CmsPair<String, String> handlerParameter = I_CmsCollectorPostCreateHandler.splitClassAndConfig( 180 postCreateHandler); 181 I_CmsCollectorPostCreateHandler handler = getPostCreateHandler(handlerParameter.getFirst()); 182 handler.onCreate(cms, newFile, isCopy, handlerParameter.getSecond()); 183 return newFileName; 184 185 } 186 187 /** 188 * Instantiates a post-create handler given a class name (which may actually be null).<p> 189 * 190 * If the given name is null or does not refer to a valid post-create handler class, a default implementation 191 * will be returned.<p> 192 * 193 * @param className the class name of the post-create handler class 194 * 195 * @return a post-create handler instance 196 */ 197 public static I_CmsCollectorPostCreateHandler getPostCreateHandler(String className) { 198 199 if (CmsStringUtil.isEmptyOrWhitespaceOnly(className)) { 200 return new CmsDefaultPostCreateHandler(); 201 } 202 try { 203 Class<?> handlerClass = Class.forName(className); 204 if (I_CmsCollectorPostCreateHandler.class.isAssignableFrom(handlerClass)) { 205 I_CmsCollectorPostCreateHandler handler = (I_CmsCollectorPostCreateHandler)handlerClass.newInstance(); 206 return handler; 207 } else { 208 LOG.error("Post-create handler class does not implement I_CmsPostCreateHandler: '" + className + "'"); 209 return new CmsDefaultPostCreateHandler(); 210 } 211 } catch (Exception e) { 212 LOG.error("Problem using post-create handler: '" + className + "'," + e.getLocalizedMessage(), e); 213 return new CmsDefaultPostCreateHandler(); 214 } 215 } 216 217 /** 218 * @see java.lang.Comparable#compareTo(java.lang.Object) 219 */ 220 public int compareTo(I_CmsResourceCollector obj) { 221 222 if (obj == this) { 223 return 0; 224 } 225 return getOrder() - obj.getOrder(); 226 } 227 228 /** 229 * Two collectors are considered to be equal if they are sharing the same 230 * implementation class.<p> 231 * 232 * @see java.lang.Object#equals(java.lang.Object) 233 */ 234 @Override 235 public boolean equals(Object obj) { 236 237 if (obj == this) { 238 return true; 239 } 240 if (obj instanceof I_CmsResourceCollector) { 241 return getClass().getName().equals(obj.getClass().getName()); 242 } 243 return false; 244 } 245 246 /** 247 * @see org.opencms.file.collectors.I_CmsResourceCollector#getCreateLink(org.opencms.file.CmsObject) 248 */ 249 public String getCreateLink(CmsObject cms) throws CmsException, CmsDataAccessException { 250 251 checkParams(); 252 return getCreateLink(cms, getDefaultCollectorName(), getDefaultCollectorParam()); 253 } 254 255 /** 256 * @see org.opencms.file.collectors.I_CmsResourceCollector#getCreateParam(org.opencms.file.CmsObject) 257 */ 258 public String getCreateParam(CmsObject cms) throws CmsDataAccessException { 259 260 checkParams(); 261 return getCreateParam(cms, getDefaultCollectorName(), getDefaultCollectorParam()); 262 } 263 264 /** 265 * @see org.opencms.file.collectors.I_CmsResourceCollector#getCreateTypeId(org.opencms.file.CmsObject, java.lang.String, java.lang.String) 266 */ 267 @SuppressWarnings("unused") 268 public int getCreateTypeId(CmsObject cms, String collectorName, String param) throws CmsException { 269 270 // overwrite to allow creation of new items 271 return -1; 272 } 273 274 /** 275 * @see org.opencms.file.collectors.I_CmsResourceCollector#getDefaultCollectorName() 276 */ 277 public String getDefaultCollectorName() { 278 279 return m_defaultCollectorName; 280 } 281 282 /** 283 * @see org.opencms.file.collectors.I_CmsResourceCollector#getDefaultCollectorParam() 284 */ 285 public String getDefaultCollectorParam() { 286 287 return m_defaultCollectorParam; 288 } 289 290 /** 291 * @see org.opencms.file.collectors.I_CmsResourceCollector#getOrder() 292 */ 293 public int getOrder() { 294 295 return m_order; 296 } 297 298 /** 299 * @see org.opencms.file.collectors.I_CmsCollectorPublishListProvider#getPublishResources(org.opencms.file.CmsObject, org.opencms.gwt.shared.I_CmsContentLoadCollectorInfo) 300 */ 301 public Set<CmsResource> getPublishResources(final CmsObject cms, final I_CmsContentLoadCollectorInfo info) 302 throws CmsException { 303 304 int collectorLimit = NumberUtils.toInt( 305 OpenCms.getADEManager().getParameters(cms).get(CmsGwtConstants.COLLECTOR_PUBLISH_LIST_LIMIT), 306 DEFAULT_LIMIT); 307 CmsCollectorPublishListHelper helper = new CmsCollectorPublishListHelper(cms, info, collectorLimit); 308 return helper.getPublishListFiles(); 309 310 } 311 312 /** 313 * @see org.opencms.file.collectors.I_CmsResourceCollector#getResults(org.opencms.file.CmsObject) 314 */ 315 public List<CmsResource> getResults(CmsObject cms) throws CmsDataAccessException, CmsException { 316 317 checkParams(); 318 return getResults(cms, getDefaultCollectorName(), getDefaultCollectorParam()); 319 } 320 321 /** 322 * @see java.lang.Object#hashCode() 323 */ 324 @Override 325 public int hashCode() { 326 327 return m_hashcode; 328 } 329 330 /** 331 * @see org.opencms.file.collectors.I_CmsResourceCollector#setDefaultCollectorName(java.lang.String) 332 */ 333 public void setDefaultCollectorName(String collectorName) { 334 335 m_defaultCollectorName = collectorName; 336 } 337 338 /** 339 * @see org.opencms.file.collectors.I_CmsResourceCollector#setDefaultCollectorParam(java.lang.String) 340 */ 341 public void setDefaultCollectorParam(String param) { 342 343 m_defaultCollectorParam = param; 344 } 345 346 /** 347 * @see org.opencms.file.collectors.I_CmsResourceCollector#setOrder(int) 348 */ 349 public void setOrder(int order) { 350 351 m_order = order; 352 } 353 354 /** 355 * Checks if the required parameters have been set.<p> 356 * 357 * @see #setDefaultCollectorName(String) 358 * @see #setDefaultCollectorParam(String) 359 */ 360 protected void checkParams() { 361 362 if ((m_defaultCollectorName == null) || (m_defaultCollectorParam == null)) { 363 throw new CmsIllegalArgumentException( 364 Messages.get().container( 365 Messages.ERR_COLLECTOR_DEFAULTS_INVALID_2, 366 m_defaultCollectorName, 367 m_defaultCollectorParam)); 368 } 369 } 370 371 /** 372 * Returns the link to create a new XML content item in the folder pointed to by the parameter.<p> 373 * 374 * @param cms the current CmsObject 375 * @param data the collector data to use 376 * 377 * @return the link to create a new XML content item in the folder 378 * 379 * @throws CmsException if something goes wrong 380 * 381 * @since 7.0.2 382 */ 383 protected String getCreateInFolder(CmsObject cms, CmsCollectorData data) throws CmsException { 384 385 return OpenCms.getResourceManager().getNameGenerator().getNewFileName(cms, data.getFileName(), 4); 386 } 387 388 /** 389 * Returns the link to create a new XML content item in the folder pointed to by the parameter.<p> 390 * 391 * @param cms the current CmsObject 392 * @param param the folder name to use 393 * 394 * @return the link to create a new XML content item in the folder 395 * 396 * @throws CmsException if something goes wrong 397 */ 398 protected String getCreateInFolder(CmsObject cms, String param) throws CmsException { 399 400 return getCreateInFolder(cms, new CmsCollectorData(param)); 401 } 402 403 /** 404 * Shrinks a List to fit a maximum size.<p> 405 * 406 * @param result a List 407 * @param maxSize the maximum size of the List 408 * 409 * @return the reduced list 410 */ 411 protected List<CmsResource> shrinkToFit(List<CmsResource> result, int maxSize) { 412 413 if ((maxSize > 0) && (result.size() > maxSize)) { 414 // cut off all items > count 415 result = result.subList(0, maxSize); 416 } 417 418 return result; 419 } 420 421 /** 422 * Shrinks a List to fit a maximum size.<p> 423 * 424 * @param result a List 425 * @param maxSize the maximum size of the List 426 * @param explicitNumResults the value of the numResults parameter given to the getResults method (this overrides maxSize if it is positive) 427 * 428 * @return the reduced list 429 */ 430 protected List<CmsResource> shrinkToFit(List<CmsResource> result, int maxSize, int explicitNumResults) { 431 432 return shrinkToFit(result, explicitNumResults > 0 ? explicitNumResults : maxSize); 433 } 434}