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