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.types; 029 030import org.opencms.db.CmsSecurityManager; 031import org.opencms.file.CmsDataNotImplementedException; 032import org.opencms.file.CmsObject; 033import org.opencms.file.CmsProperty; 034import org.opencms.file.CmsResource; 035import org.opencms.file.CmsResourceFilter; 036import org.opencms.file.CmsVfsException; 037import org.opencms.file.CmsVfsResourceNotFoundException; 038import org.opencms.lock.CmsLockType; 039import org.opencms.main.CmsException; 040import org.opencms.main.CmsIllegalArgumentException; 041import org.opencms.main.OpenCms; 042import org.opencms.util.CmsStringUtil; 043 044import java.util.List; 045 046/** 047 * Resource type descriptor for the type "folder".<p> 048 * 049 * @since 6.0.0 050 */ 051public abstract class A_CmsResourceTypeFolderBase extends A_CmsResourceType { 052 053 /** Attribute to control shallow copying. */ 054 public static final String ATTR_SHALLOW_FOLDER_COPY = "shallow_folder_copy"; 055 056 /** The serial version id. */ 057 private static final long serialVersionUID = -698470184142645873L; 058 059 /** 060 * Default constructor, used to initialize member variables.<p> 061 */ 062 public A_CmsResourceTypeFolderBase() { 063 064 super(); 065 } 066 067 /** 068 * @see org.opencms.file.types.I_CmsResourceType#chtype(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, int) 069 */ 070 @Override 071 public void chtype(CmsObject cms, CmsSecurityManager securityManager, CmsResource filename, int newType) 072 throws CmsException, CmsDataNotImplementedException { 073 074 if (!OpenCms.getResourceManager().getResourceType(newType).isFolder()) { 075 // it is not possible to change the type of a folder to a file type 076 throw new CmsDataNotImplementedException( 077 Messages.get().container(Messages.ERR_CHTYPE_FOLDER_1, cms.getSitePath(filename))); 078 } 079 super.chtype(cms, securityManager, filename, newType); 080 } 081 082 /** 083 * @see org.opencms.file.types.I_CmsResourceType#copyResource(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, java.lang.String, CmsResource.CmsResourceCopyMode) 084 */ 085 @Override 086 public void copyResource( 087 CmsObject cms, 088 CmsSecurityManager securityManager, 089 CmsResource source, 090 String destination, 091 CmsResource.CmsResourceCopyMode siblingMode) 092 throws CmsIllegalArgumentException, CmsException { 093 094 // first validate the destination name 095 destination = validateFoldername(destination); 096 097 // collect all resources in the folder (but exclude deleted ones) 098 List<CmsResource> resources = securityManager.readChildResources( 099 cms.getRequestContext(), 100 source, 101 CmsResourceFilter.IGNORE_EXPIRATION, 102 true, 103 true); 104 105 // handle the folder itself 106 super.copyResource(cms, securityManager, source, destination, siblingMode); 107 Boolean shallow = (Boolean)(cms.getRequestContext().getAttribute(ATTR_SHALLOW_FOLDER_COPY)); 108 if ((shallow == null) || !shallow.booleanValue()) { 109 // now walk through all sub-resources in the folder 110 for (int i = 0; i < resources.size(); i++) { 111 CmsResource childResource = resources.get(i); 112 String childDestination = destination.concat(childResource.getName()); 113 // handle child resources 114 getResourceType( 115 childResource).copyResource(cms, securityManager, childResource, childDestination, siblingMode); 116 } 117 } 118 } 119 120 /** 121 * @see org.opencms.file.types.I_CmsResourceType#createResource(org.opencms.file.CmsObject, CmsSecurityManager, java.lang.String, byte[], List) 122 */ 123 @Override 124 public CmsResource createResource( 125 CmsObject cms, 126 CmsSecurityManager securityManager, 127 String resourcename, 128 byte[] content, 129 List<CmsProperty> properties) 130 throws CmsException { 131 132 resourcename = validateFoldername(resourcename); 133 return super.createResource(cms, securityManager, resourcename, content, properties); 134 } 135 136 /** 137 * @see org.opencms.file.types.I_CmsResourceType#getLoaderId() 138 */ 139 @Override 140 public int getLoaderId() { 141 142 // folders have no loader 143 return -1; 144 } 145 146 /** 147 * @see org.opencms.file.types.A_CmsResourceType#isFolder() 148 */ 149 @Override 150 public boolean isFolder() { 151 152 return true; 153 } 154 155 /** 156 * @see org.opencms.file.types.I_CmsResourceType#moveResource(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, org.opencms.file.CmsResource, java.lang.String) 157 */ 158 @Override 159 public void moveResource( 160 CmsObject cms, 161 CmsSecurityManager securityManager, 162 CmsResource resource, 163 String destination) 164 throws CmsException, CmsIllegalArgumentException { 165 166 String dest = cms.getRequestContext().addSiteRoot(destination); 167 if (!CmsResource.isFolder(dest)) { 168 // ensure folder name end's with a / (required for the following comparison) 169 dest = dest.concat("/"); 170 } 171 if (resource.getRootPath().equals(dest)) { 172 // move to target with same name is not allowed 173 throw new CmsVfsException( 174 org.opencms.file.Messages.get().container(org.opencms.file.Messages.ERR_MOVE_SAME_NAME_1, destination)); 175 } 176 if (dest.startsWith(resource.getRootPath())) { 177 // move of folder inside itself is not allowed 178 throw new CmsVfsException( 179 org.opencms.file.Messages.get().container( 180 org.opencms.file.Messages.ERR_MOVE_SAME_FOLDER_2, 181 cms.getSitePath(resource), 182 destination)); 183 } 184 185 // check the destination 186 try { 187 securityManager.readResource(cms.getRequestContext(), dest, CmsResourceFilter.ALL); 188 throw new CmsVfsException( 189 org.opencms.file.Messages.get().container( 190 org.opencms.file.Messages.ERR_OVERWRITE_RESOURCE_2, 191 cms.getRequestContext().removeSiteRoot(resource.getRootPath()), 192 destination)); 193 } catch (CmsVfsResourceNotFoundException e) { 194 // ok 195 } 196 197 // first validate the destination name 198 dest = validateFoldername(dest); 199 String targetName = CmsResource.getName(destination).replace("/", ""); 200 CmsResource.checkResourceName(targetName); 201 202 securityManager.moveResource(cms.getRequestContext(), resource, dest); 203 } 204 205 /** 206 * @see org.opencms.file.types.I_CmsResourceType#replaceResource(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, int, byte[], List) 207 */ 208 @Override 209 public void replaceResource( 210 CmsObject cms, 211 CmsSecurityManager securityManager, 212 CmsResource resource, 213 int type, 214 byte[] content, 215 List<CmsProperty> properties) 216 throws CmsException, CmsDataNotImplementedException { 217 218 if (type != getTypeId()) { 219 // it is not possible to replace a folder with a different type 220 throw new CmsDataNotImplementedException( 221 Messages.get().container(Messages.ERR_REPLACE_RESOURCE_FOLDER_1, cms.getSitePath(resource))); 222 } 223 // properties of a folder can be replaced, content is ignored 224 super.replaceResource(cms, securityManager, resource, getTypeId(), null, properties); 225 } 226 227 /** 228 * @see org.opencms.file.types.I_CmsResourceType#setDateExpired(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, long, boolean) 229 */ 230 @Override 231 public void setDateExpired( 232 CmsObject cms, 233 CmsSecurityManager securityManager, 234 CmsResource resource, 235 long dateLastModified, 236 boolean recursive) 237 throws CmsException { 238 239 // handle the folder itself 240 super.setDateExpired(cms, securityManager, resource, dateLastModified, recursive); 241 242 if (recursive) { 243 // collect all resources in the folder (but exclude deleted ones) 244 List<CmsResource> resources = securityManager.readChildResources( 245 cms.getRequestContext(), 246 resource, 247 CmsResourceFilter.IGNORE_EXPIRATION, 248 true, 249 true); 250 251 // now walk through all sub-resources in the folder 252 for (int i = 0; i < resources.size(); i++) { 253 CmsResource childResource = resources.get(i); 254 // handle child resources 255 getResourceType( 256 childResource).setDateExpired(cms, securityManager, childResource, dateLastModified, recursive); 257 } 258 } 259 } 260 261 /** 262 * @see org.opencms.file.types.I_CmsResourceType#setDateLastModified(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, long, boolean) 263 */ 264 @Override 265 public void setDateLastModified( 266 CmsObject cms, 267 CmsSecurityManager securityManager, 268 CmsResource resource, 269 long dateLastModified, 270 boolean recursive) 271 throws CmsException { 272 273 // handle the folder itself 274 super.setDateLastModified(cms, securityManager, resource, dateLastModified, recursive); 275 276 if (recursive) { 277 // collect all resources in the folder (but exclude deleted ones) 278 List<CmsResource> resources = securityManager.readChildResources( 279 cms.getRequestContext(), 280 resource, 281 CmsResourceFilter.IGNORE_EXPIRATION, 282 true, 283 true); 284 285 // now walk through all sub-resources in the folder 286 for (int i = 0; i < resources.size(); i++) { 287 CmsResource childResource = resources.get(i); 288 // handle child resources 289 getResourceType(childResource).setDateLastModified( 290 cms, 291 securityManager, 292 childResource, 293 dateLastModified, 294 recursive); 295 } 296 } 297 } 298 299 /** 300 * @see org.opencms.file.types.I_CmsResourceType#setDateReleased(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, long, boolean) 301 */ 302 @Override 303 public void setDateReleased( 304 CmsObject cms, 305 CmsSecurityManager securityManager, 306 CmsResource resource, 307 long dateLastModified, 308 boolean recursive) 309 throws CmsException { 310 311 // handle the folder itself 312 super.setDateReleased(cms, securityManager, resource, dateLastModified, recursive); 313 314 if (recursive) { 315 // collect all resources in the folder (but exclude deleted ones) 316 List<CmsResource> resources = securityManager.readChildResources( 317 cms.getRequestContext(), 318 resource, 319 CmsResourceFilter.IGNORE_EXPIRATION, 320 true, 321 true); 322 323 // now walk through all sub-resources in the folder 324 for (int i = 0; i < resources.size(); i++) { 325 CmsResource childResource = resources.get(i); 326 // handle child resources 327 getResourceType( 328 childResource).setDateReleased(cms, securityManager, childResource, dateLastModified, recursive); 329 } 330 } 331 } 332 333 /** 334 * @see org.opencms.file.types.A_CmsResourceType#undelete(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, org.opencms.file.CmsResource, boolean) 335 */ 336 @Override 337 public void undelete(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource, boolean recursive) 338 throws CmsException { 339 340 // handle the folder itself 341 super.undelete(cms, securityManager, resource, recursive); 342 343 if (recursive) { 344 // collect all resources in the folder (but exclude deleted ones) 345 List<CmsResource> resources = securityManager.readChildResources( 346 cms.getRequestContext(), 347 resource, 348 CmsResourceFilter.ALL, 349 true, 350 true); 351 352 // now walk through all sub-resources in the folder 353 for (int i = 0; i < resources.size(); i++) { 354 CmsResource childResource = resources.get(i); 355 // handle child resources 356 getResourceType(childResource).undelete(cms, securityManager, childResource, recursive); 357 } 358 } 359 } 360 361 /** 362 * @see org.opencms.file.types.I_CmsResourceType#undoChanges(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, CmsResource.CmsResourceUndoMode) 363 */ 364 @Override 365 public void undoChanges( 366 CmsObject cms, 367 CmsSecurityManager securityManager, 368 CmsResource resource, 369 CmsResource.CmsResourceUndoMode mode) 370 throws CmsException { 371 372 boolean recursive = mode.isRecursive(); 373 if (mode == CmsResource.UNDO_MOVE_CONTENT) { 374 // undo move only? 375 String originalPath = securityManager.resourceOriginalPath(cms.getRequestContext(), resource); 376 if (originalPath.equals(resource.getRootPath())) { 377 // resource not moved 378 recursive = false; 379 } 380 } 381 382 List<CmsResource> resources = null; 383 if (recursive) { // recursive? 384 // collect all resources in the folder (including deleted ones) 385 resources = securityManager.readChildResources( 386 cms.getRequestContext(), 387 resource, 388 CmsResourceFilter.ALL, 389 true, 390 true); 391 } 392 393 // handle the folder itself, undo move op 394 super.undoChanges(cms, securityManager, resource, mode); 395 396 // the folder may have been moved back to its original position 397 CmsResource undoneResource2 = securityManager.readResource( 398 cms.getRequestContext(), 399 resource.getStructureId(), 400 CmsResourceFilter.ALL); 401 boolean isMoved = !undoneResource2.getRootPath().equals(resource.getRootPath()); 402 403 if (recursive && (resources != null)) { // recursive? 404 // now walk through all sub-resources in the folder, and undo first 405 for (int i = 0; i < resources.size(); i++) { 406 CmsResource childResource = resources.get(i); 407 408 I_CmsResourceType type = getResourceType(childResource); 409 410 if (isMoved) { 411 securityManager.lockResource(cms.getRequestContext(), childResource, CmsLockType.EXCLUSIVE); 412 } 413 if (!childResource.getState().isNew()) { 414 // can not use undo for new resources 415 if (childResource.isFolder()) { 416 // recurse into this method for subfolders 417 type.undoChanges(cms, securityManager, childResource, mode); 418 } else if (!childResource.getState().isNew()) { 419 // undo changes for changed files 420 securityManager.undoChanges(cms.getRequestContext(), childResource, mode); 421 } else { 422 // undo move for new files? move with the folder 423 if (mode.isUndoMove()) { 424 String newPath = cms.getRequestContext().removeSiteRoot( 425 securityManager.readResource( 426 cms.getRequestContext(), 427 resource.getStructureId(), 428 CmsResourceFilter.ALL).getRootPath() + childResource.getName()); 429 type.moveResource(cms, securityManager, childResource, newPath); 430 } 431 } 432 } else if (isMoved) { 433 // we still need to update the resource path for new resources 434 String newPath = cms.getRequestContext().removeSiteRoot( 435 securityManager.readResource( 436 cms.getRequestContext(), 437 resource.getStructureId(), 438 CmsResourceFilter.ALL).getRootPath() + childResource.getName()); 439 type.moveResource(cms, securityManager, childResource, newPath); 440 } 441 } 442 443 // now iterate again all sub-resources in the folder, and actualize the relations 444 for (int i = 0; i < resources.size(); i++) { 445 CmsResource childResource = resources.get(i); 446 updateRelationForUndo(cms, securityManager, childResource); 447 } 448 } 449 } 450 451 /** 452 * Checks if there are at least one character in the folder name, 453 * also ensures that it starts and ends with a '/'.<p> 454 * 455 * @param resourcename folder name to check (complete path) 456 * 457 * @return the validated folder name 458 * 459 * @throws CmsIllegalArgumentException if the folder name is empty or <code>null</code> 460 */ 461 private String validateFoldername(String resourcename) throws CmsIllegalArgumentException { 462 463 if (CmsStringUtil.isEmpty(resourcename)) { 464 throw new CmsIllegalArgumentException( 465 org.opencms.db.Messages.get().container(org.opencms.db.Messages.ERR_BAD_RESOURCENAME_1, resourcename)); 466 } 467 if (!CmsResource.isFolder(resourcename)) { 468 resourcename = resourcename.concat("/"); 469 } 470 if (resourcename.charAt(0) != '/') { 471 resourcename = "/".concat(resourcename); 472 } 473 return resourcename; 474 } 475}