001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH (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, 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; 029 030import org.opencms.db.CmsDriverManager; 031import org.opencms.db.CmsResourceState; 032import org.opencms.main.CmsIllegalArgumentException; 033import org.opencms.util.A_CmsModeIntEnumeration; 034import org.opencms.util.CmsStringUtil; 035import org.opencms.util.CmsUUID; 036 037import java.io.Serializable; 038 039/** 040 * Base class for all OpenCms VFS resources like <code>{@link CmsFile}</code> or <code>{@link CmsFolder}</code>.<p> 041 * 042 * The OpenCms VFS resource is an important object for using the OpenCms API. 043 * Basically, all entries in the OpenCms VFS are considered to be "resources". 044 * Currently, only two types of resources exists:<ul> 045 * <li>Files, which are represented by the subclass {@link CmsFile}. 046 * <li>Folders (also called Directories), which are represented by the subclass {@link CmsFolder}. 047 * </ul> 048 * 049 * If you have a resource, you can use {@link #isFile()} or {@link #isFolder()} to learn what kind of 050 * subclass you have. Please note that this is usually not required, as the only real difference between a 051 * {@link CmsFile} and a {@link CmsResource} is that the {@link CmsFile} also has the contents of the file, 052 * which you can obtain using {@link CmsFile#getContents()}. As long as you don't need the content, you can 053 * use the {@link CmsResource} for everything else. This is even more true for a {@link CmsFolder}, here you 054 * will need the subclass only in special cases, since the signature is identical to {@link CmsResource}.<p> 055 * 056 * A OpenCms VFS resource can have any number of properties attached, which are represented by a {@link CmsProperty}. 057 * To read the properties for a resource, use {@link CmsObject#readPropertyObject(CmsResource, String, boolean)} 058 * or use {@link CmsObject#readPropertyObjects(CmsResource, boolean)} to read all properties of the resource.<p> 059 * 060 * @since 6.0.0 061 */ 062public class CmsResource implements I_CmsResource, Cloneable, Serializable, Comparable<I_CmsResource> { 063 064 /** 065 * Enumeration class for resource copy modes.<p> 066 */ 067 public static final class CmsResourceCopyMode extends A_CmsModeIntEnumeration { 068 069 /** Copy mode for copy resources as new resource. */ 070 protected static final CmsResourceCopyMode MODE_COPY_AS_NEW = new CmsResourceCopyMode(1); 071 072 /** Copy mode for copy resources as sibling. */ 073 protected static final CmsResourceCopyMode MODE_COPY_AS_SIBLING = new CmsResourceCopyMode(2); 074 075 /** Copy mode to preserve siblings during copy. */ 076 protected static final CmsResourceCopyMode MODE_COPY_PRESERVE_SIBLING = new CmsResourceCopyMode(3); 077 078 /** Version id required for safe serialization. */ 079 private static final long serialVersionUID = 9081630878178799137L; 080 081 /** 082 * Private constructor.<p> 083 * 084 * @param mode the copy mode integer representation 085 */ 086 private CmsResourceCopyMode(int mode) { 087 088 super(mode); 089 } 090 091 /** 092 * Returns the copy mode object from the old copy mode integer.<p> 093 * 094 * @param mode the old copy mode integer 095 * 096 * @return the copy mode object 097 */ 098 public static CmsResourceCopyMode valueOf(int mode) { 099 100 switch (mode) { 101 case 1: 102 return CmsResourceCopyMode.MODE_COPY_AS_NEW; 103 case 2: 104 return CmsResourceCopyMode.MODE_COPY_AS_SIBLING; 105 case 3: 106 default: 107 return CmsResourceCopyMode.MODE_COPY_PRESERVE_SIBLING; 108 } 109 } 110 } 111 112 /** 113 * Enumeration class for resource delete modes.<p> 114 */ 115 public static final class CmsResourceDeleteMode extends A_CmsModeIntEnumeration { 116 117 /** Signals that siblings of this resource should not be deleted. */ 118 protected static final CmsResourceDeleteMode MODE_DELETE_PRESERVE_SIBLINGS = new CmsResourceDeleteMode(1); 119 120 /** Signals that siblings of this resource should be deleted. */ 121 protected static final CmsResourceDeleteMode MODE_DELETE_REMOVE_SIBLINGS = new CmsResourceDeleteMode(2); 122 123 /** Version id required for safe serialization. */ 124 private static final long serialVersionUID = 2010402524576925865L; 125 126 /** 127 * Private constructor.<p> 128 * 129 * @param mode the delete mode integer representation 130 */ 131 private CmsResourceDeleteMode(int mode) { 132 133 super(mode); 134 } 135 136 /** 137 * Returns the delete mode object from the old delete mode integer.<p> 138 * 139 * @param mode the old delete mode integer 140 * 141 * @return the delete mode object 142 */ 143 public static CmsResourceDeleteMode valueOf(int mode) { 144 145 switch (mode) { 146 case 1: 147 return CmsResourceDeleteMode.MODE_DELETE_PRESERVE_SIBLINGS; 148 case 2: 149 default: 150 return CmsResourceDeleteMode.MODE_DELETE_REMOVE_SIBLINGS; 151 } 152 } 153 } 154 155 /** 156 * Enumeration class for resource undo changes modes.<p> 157 */ 158 public static final class CmsResourceUndoMode extends A_CmsModeIntEnumeration { 159 160 /** Indicates that the undo method will only undo content changes. */ 161 public static final CmsResourceUndoMode MODE_UNDO_CONTENT = new CmsResourceUndoMode(1); 162 163 /** Indicates that the undo method will only recursive undo content changes. */ 164 public static final CmsResourceUndoMode MODE_UNDO_CONTENT_RECURSIVE = new CmsResourceUndoMode(2); 165 166 /** Indicates that the undo method will undo move operations and content changes. */ 167 public static final CmsResourceUndoMode MODE_UNDO_MOVE_CONTENT = new CmsResourceUndoMode(3); 168 169 /** Indicates that the undo method will undo move operations and recursive content changes. */ 170 public static final CmsResourceUndoMode MODE_UNDO_MOVE_CONTENT_RECURSIVE = new CmsResourceUndoMode(4); 171 172 /** Version id required for safe serialization. */ 173 private static final long serialVersionUID = 3521620626485212068L; 174 175 /** 176 * private constructor.<p> 177 * 178 * @param mode the undo changes mode integer representation 179 */ 180 private CmsResourceUndoMode(int mode) { 181 182 super(mode); 183 } 184 185 /** 186 * Returns the undo mode object from the old undo mode integer.<p> 187 * 188 * @param mode the old undo mode integer 189 * 190 * @return the undo mode object 191 */ 192 public static CmsResourceUndoMode valueOf(int mode) { 193 194 switch (mode) { 195 case 1: 196 return CmsResourceUndoMode.MODE_UNDO_CONTENT; 197 case 2: 198 return CmsResourceUndoMode.MODE_UNDO_CONTENT_RECURSIVE; 199 case 3: 200 return CmsResourceUndoMode.MODE_UNDO_MOVE_CONTENT; 201 case 4: 202 default: 203 return CmsResourceUndoMode.MODE_UNDO_MOVE_CONTENT_RECURSIVE; 204 } 205 } 206 207 /** 208 * Returns a mode that includes the move operation with the same semantic as this mode.<p> 209 * 210 * @return a mode that includes the move operation with the same semantic as this mode 211 */ 212 public CmsResourceUndoMode includeMove() { 213 214 if (!isUndoMove()) { 215 // keep the same semantic but including move 216 return CmsResourceUndoMode.valueOf(getMode() + 2); 217 } 218 return this; 219 } 220 221 /** 222 * Returns <code>true</code> if this undo operation is recursive.<p> 223 * 224 * @return <code>true</code> if this undo operation is recursive 225 */ 226 public boolean isRecursive() { 227 228 return getMode() > CmsResource.UNDO_CONTENT.getMode(); 229 } 230 231 /** 232 * Returns <code>true</code> if this undo mode will undo move operations.<p> 233 * 234 * @return <code>true</code> if this undo mode will undo move operations 235 */ 236 public boolean isUndoMove() { 237 238 return getMode() > CmsResource.UNDO_CONTENT_RECURSIVE.getMode(); 239 } 240 241 /** 242 * @see java.lang.Object#toString() 243 */ 244 @Override 245 public String toString() { 246 247 return String.valueOf(getMode()); 248 } 249 } 250 251 /** Copy mode for copy resources as new resource. */ 252 public static final CmsResourceCopyMode COPY_AS_NEW = CmsResourceCopyMode.MODE_COPY_AS_NEW; 253 254 /** Copy mode for copy resources as sibling. */ 255 public static final CmsResourceCopyMode COPY_AS_SIBLING = CmsResourceCopyMode.MODE_COPY_AS_SIBLING; 256 257 /** Copy mode to preserve siblings during copy. */ 258 public static final CmsResourceCopyMode COPY_PRESERVE_SIBLING = CmsResourceCopyMode.MODE_COPY_PRESERVE_SIBLING; 259 260 /** The default expiration date of a resource, which is: never expires. */ 261 public static final long DATE_EXPIRED_DEFAULT = Long.MAX_VALUE; 262 263 /** The default release date of a resource, which is: always released. */ 264 public static final long DATE_RELEASED_DEFAULT = 0; 265 266 /** A special date that indicates release and expiration information are to be ignored. */ 267 public static final long DATE_RELEASED_EXPIRED_IGNORE = Long.MIN_VALUE; 268 269 /** Signals that siblings of this resource should not be deleted. */ 270 public static final CmsResourceDeleteMode DELETE_PRESERVE_SIBLINGS = CmsResourceDeleteMode.MODE_DELETE_PRESERVE_SIBLINGS; 271 272 /** Signals that siblings of this resource should be deleted. */ 273 public static final CmsResourceDeleteMode DELETE_REMOVE_SIBLINGS = CmsResourceDeleteMode.MODE_DELETE_REMOVE_SIBLINGS; 274 275 /** Flag to indicate that this is an internal resource, that can't be accessed directly. */ 276 public static final int FLAG_INTERNAL = 512; 277 278 /** The resource is linked inside a site folder specified in the OpenCms configuration. */ 279 public static final int FLAG_LABELED = 2; 280 281 /** Flag to indicate that this is a temporary resource. */ 282 public static final int FLAG_TEMPFILE = 1024; 283 284 /** The name constraints when generating new resources. */ 285 public static final String NAME_CONSTRAINTS = "-._~$"; 286 287 /** Indicates if a resource has been changed in the offline version when compared to the online version. */ 288 public static final CmsResourceState STATE_CHANGED = CmsResourceState.STATE_CHANGED; 289 290 /** Indicates if a resource has been deleted in the offline version when compared to the online version. */ 291 public static final CmsResourceState STATE_DELETED = CmsResourceState.STATE_DELETED; 292 293 /** 294 * Special state value that indicates the current state must be kept on a resource, 295 * this value must never be written to the database. 296 */ 297 public static final CmsResourceState STATE_KEEP = CmsResourceState.STATE_KEEP; 298 299 /** Indicates if a resource is new in the offline version when compared to the online version. */ 300 public static final CmsResourceState STATE_NEW = CmsResourceState.STATE_NEW; 301 302 /** Indicates if a resource is unchanged in the offline version when compared to the online version. */ 303 public static final CmsResourceState STATE_UNCHANGED = CmsResourceState.STATE_UNCHANGED; 304 305 /** 306 * Prefix for temporary files in the VFS. 307 * 308 * @see #isTemporaryFile() 309 * @see #isTemporaryFileName(String) 310 */ 311 public static final String TEMP_FILE_PREFIX = CmsDriverManager.TEMP_FILE_PREFIX; 312 313 /** Flag for leaving a date unchanged during a touch operation. */ 314 public static final long TOUCH_DATE_UNCHANGED = -1; 315 316 /** Indicates that the undo method will only undo content changes. */ 317 public static final CmsResourceUndoMode UNDO_CONTENT = CmsResourceUndoMode.MODE_UNDO_CONTENT; 318 319 /** Indicates that the undo method will only recursive undo content changes. */ 320 public static final CmsResourceUndoMode UNDO_CONTENT_RECURSIVE = CmsResourceUndoMode.MODE_UNDO_CONTENT_RECURSIVE; 321 322 /** Indicates that the undo method will undo move operations and content changes. */ 323 public static final CmsResourceUndoMode UNDO_MOVE_CONTENT = CmsResourceUndoMode.MODE_UNDO_MOVE_CONTENT; 324 325 /** Indicates that the undo method will undo move operations and recursive content changes. */ 326 public static final CmsResourceUndoMode UNDO_MOVE_CONTENT_RECURSIVE = CmsResourceUndoMode.MODE_UNDO_MOVE_CONTENT_RECURSIVE; 327 328 /** The vfs path of the sites master folder. */ 329 public static final String VFS_FOLDER_SITES = "/sites"; 330 331 /** The vfs path of the system folder. */ 332 public static final String VFS_FOLDER_SYSTEM = "/system"; 333 334 /** Serial version UID required for safe serialization. */ 335 private static final long serialVersionUID = 257325098790850498L; 336 337 /** The date of the last modification of the content of this resource. */ 338 protected long m_dateContent = System.currentTimeMillis(); 339 340 /** The size of the content. */ 341 protected int m_length; 342 343 /** The creation date of this resource. */ 344 private long m_dateCreated; 345 346 /** The expiration date of this resource. */ 347 private long m_dateExpired; 348 349 /** The date of the last modification of this resource. */ 350 private long m_dateLastModified; 351 352 /** The release date of this resource. */ 353 private long m_dateReleased; 354 355 /** The flags of this resource. */ 356 private int m_flags; 357 358 /** Indicates if this resource is a folder or not. */ 359 private boolean m_isFolder; 360 361 /** Boolean flag whether the timestamp of this resource was modified by a touch command. */ 362 private boolean m_isTouched; 363 364 /** The project id where this resource has been last modified in. */ 365 private CmsUUID m_projectLastModified; 366 367 /** The id of the resource database record. */ 368 private CmsUUID m_resourceId; 369 370 /** The name of a resource with it's full path from the root folder including the current site root. */ 371 private String m_rootPath; 372 373 /** The number of links that point to this resource. */ 374 private int m_siblingCount; 375 376 /** The state of this resource. */ 377 private CmsResourceState m_state; 378 379 /** The id of the structure database record. */ 380 private CmsUUID m_structureId; 381 382 /** The resource type id of this resource. */ 383 private int m_typeId; 384 385 /** The id of the user who created this resource. */ 386 private CmsUUID m_userCreated; 387 388 /** The id of the user who modified this resource last. */ 389 private CmsUUID m_userLastModified; 390 391 /** The version number of this resource. */ 392 private int m_version; 393 394 /** 395 * Creates a new CmsRecource object.<p> 396 * 397 * @param structureId the id of this resources structure record 398 * @param resourceId the id of this resources resource record 399 * @param rootPath the root path to the resource 400 * @param type the type of this resource 401 * @param isFolder must be true if the resource is a folder, or false if it is a file 402 * @param flags the flags of this resource 403 * @param projectId the project id this resource was last modified in 404 * @param state the state of this resource 405 * @param dateCreated the creation date of this resource 406 * @param userCreated the id of the user who created this resource 407 * @param dateLastModified the date of the last modification of this resource 408 * @param userLastModified the id of the user who did the last modification of this resource 409 * @param dateReleased the release date of this resource 410 * @param dateExpired the expiration date of this resource 411 * @param linkCount the count of all siblings of this resource 412 * @param size the size of the file content of this resource 413 * @param dateContent the date of the last modification of the content of this resource 414 * @param version the version number of this resource 415 */ 416 public CmsResource( 417 CmsUUID structureId, 418 CmsUUID resourceId, 419 String rootPath, 420 int type, 421 boolean isFolder, 422 int flags, 423 CmsUUID projectId, 424 CmsResourceState state, 425 long dateCreated, 426 CmsUUID userCreated, 427 long dateLastModified, 428 CmsUUID userLastModified, 429 long dateReleased, 430 long dateExpired, 431 int linkCount, 432 int size, 433 long dateContent, 434 int version) { 435 436 m_structureId = structureId; 437 m_resourceId = resourceId; 438 m_rootPath = rootPath; 439 m_typeId = type; 440 m_isFolder = isFolder; 441 m_flags = flags; 442 m_projectLastModified = projectId; 443 m_state = state; 444 m_dateCreated = dateCreated; 445 m_userCreated = userCreated; 446 m_dateLastModified = dateLastModified; 447 m_userLastModified = userLastModified; 448 m_dateReleased = dateReleased; 449 m_dateExpired = dateExpired; 450 m_siblingCount = linkCount; 451 m_length = size; 452 m_dateContent = dateContent; 453 m_version = version; 454 m_isTouched = false; 455 } 456 457 /** 458 * Checks if the provided resource name is a valid resource name, 459 * that is contains only valid characters.<p> 460 * 461 * A resource name can only be composed of digits, 462 * standard ASCII letters and the symbols defined in {@link #NAME_CONSTRAINTS}. 463 * A resource name must also not contain only dots.<p> 464 * 465 * @param name the resource name to check 466 * 467 * @throws CmsIllegalArgumentException if the given resource name is not valid 468 */ 469 public static void checkResourceName(String name) throws CmsIllegalArgumentException { 470 471 if (CmsStringUtil.isEmptyOrWhitespaceOnly(name)) { 472 throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_BAD_RESOURCENAME_EMPTY_0, name)); 473 } 474 475 CmsStringUtil.checkName(name, NAME_CONSTRAINTS, Messages.ERR_BAD_RESOURCENAME_4, Messages.get()); 476 477 // check for filenames that have only dots (which will cause issues in the static export) 478 boolean onlydots = true; 479 // this must be done only for the last name (not for parent folders) 480 String lastName = CmsResource.getName(name); 481 int l = lastName.length(); 482 for (int i = 0; i < l; i++) { 483 char c = lastName.charAt(i); 484 if ((c != '.') && (c != '/')) { 485 onlydots = false; 486 } 487 } 488 if (onlydots) { 489 throw new CmsIllegalArgumentException(Messages.get().container( 490 Messages.ERR_BAD_RESOURCENAME_DOTS_1, 491 lastName)); 492 } 493 } 494 495 /** 496 * Returns the folder path of the resource with the given name.<p> 497 * 498 * If the resource name denotes a folder (that is ends with a "/"), the complete path of the folder 499 * is returned (not the parent folder path).<p> 500 * 501 * This is achieved by just cutting of everything behind the last occurrence of a "/" character 502 * in the String, no check if performed if the resource exists or not in the VFS, 503 * only resources that end with a "/" are considered to be folders. 504 * 505 * Example: Returns <code>/system/def/</code> for the 506 * resource <code>/system/def/file.html</code> and 507 * <code>/system/def/</code> for the (folder) resource <code>/system/def/</code>. 508 * 509 * @param resource the name of a resource 510 * @return the folder of the given resource 511 */ 512 public static String getFolderPath(String resource) { 513 514 return resource.substring(0, resource.lastIndexOf('/') + 1); 515 } 516 517 /** 518 * Returns the name of a resource without the path information.<p> 519 * 520 * The resource name of a file is the name of the file. 521 * The resource name of a folder is the folder name with trailing "/". 522 * The resource name of the root folder is <code>/</code>.<p> 523 * 524 * Example: <code>/system/workplace/</code> has the resource name <code>workplace/</code>. 525 * 526 * @param resource the resource to get the name for 527 * @return the name of a resource without the path information 528 */ 529 public static String getName(String resource) { 530 531 if ("/".equals(resource)) { 532 return "/"; 533 } 534 // remove the last char, for a folder this will be "/", for a file it does not matter 535 String parent = (resource.substring(0, resource.length() - 1)); 536 // now as the name does not end with "/", check for the last "/" which is the parent folder name 537 return resource.substring(parent.lastIndexOf('/') + 1); 538 } 539 540 /** 541 * Returns the absolute parent folder name of a resource.<p> 542 * 543 * The parent resource of a file is the folder of the file. 544 * The parent resource of a folder is the parent folder. 545 * The parent resource of the root folder is <code>null</code>.<p> 546 * 547 * Example: <code>/system/workplace/</code> has the parent <code>/system/</code>. 548 * 549 * @param resource the resource to find the parent folder for 550 * @return the calculated parent absolute folder path, or <code>null</code> for the root folder 551 */ 552 public static String getParentFolder(String resource) { 553 554 if (CmsStringUtil.isEmptyOrWhitespaceOnly(resource) || "/".equals(resource)) { 555 return null; 556 } 557 // remove the last char, for a folder this will be "/", for a file it does not matter 558 String parent = (resource.substring(0, resource.length() - 1)); 559 // now as the name does not end with "/", check for the last "/" which is the parent folder name 560 return parent.substring(0, parent.lastIndexOf('/') + 1); 561 } 562 563 /** 564 * Returns the directory level of a resource.<p> 565 * 566 * The root folder "/" has level 0, 567 * a folder "/foo/" would have level 1, 568 * a folfer "/foo/bar/" level 2 etc.<p> 569 * 570 * @param resource the resource to determine the directory level for 571 * @return the directory level of a resource 572 */ 573 public static int getPathLevel(String resource) { 574 575 int level = -1; 576 int pos = 0; 577 while (resource.indexOf('/', pos) >= 0) { 578 pos = resource.indexOf('/', pos) + 1; 579 level++; 580 } 581 return level; 582 } 583 584 /** 585 * Returns the name of a parent folder of the given resource, 586 * that is either minus levels up 587 * from the current folder, or that is plus levels down from the 588 * root folder.<p> 589 * 590 * @param resource the name of a resource 591 * @param level of levels to walk up or down 592 * @return the name of a parent folder of the given resource 593 */ 594 public static String getPathPart(String resource, int level) { 595 596 resource = getFolderPath(resource); 597 String result = null; 598 int pos = 0, count = 0; 599 if (level >= 0) { 600 // Walk down from the root folder / 601 while ((count < level) && (pos > -1)) { 602 count++; 603 pos = resource.indexOf('/', pos + 1); 604 } 605 } else { 606 // Walk up from the current folder 607 pos = resource.length(); 608 while ((count > level) && (pos > -1)) { 609 count--; 610 pos = resource.lastIndexOf('/', pos - 1); 611 } 612 } 613 if (pos > -1) { 614 // To many levels walked 615 result = resource.substring(0, pos + 1); 616 } else { 617 // Add trailing slash 618 result = (level < 0) ? "/" : resource; 619 } 620 return result; 621 } 622 623 /** 624 * Returns true if the resource name certainly denotes a folder, that is ends with a "/".<p> 625 * 626 * @param resource the resource to check 627 * @return true if the resource name certainly denotes a folder, that is ends with a "/" 628 */ 629 public static boolean isFolder(String resource) { 630 631 return CmsStringUtil.isNotEmpty(resource) && (resource.charAt(resource.length() - 1) == '/'); 632 } 633 634 /** 635 * Returns <code>true</code> if the given resource path points to a temporary file name.<p> 636 * 637 * A resource name is considered a temporary file name if the name of the file 638 * (without parent folders) starts with the prefix char <code>'~'</code> (tilde). 639 * Existing parent folder elements are removed from the path before the file name is checked.<p> 640 * 641 * @param path the resource path to check 642 * 643 * @return <code>true</code> if the given resource name is a temporary file name 644 * 645 * @see #isTemporaryFile() 646 */ 647 public static boolean isTemporaryFileName(String path) { 648 649 return (path != null) && getName(path).startsWith(TEMP_FILE_PREFIX); 650 } 651 652 /** 653 * Returns a clone of this Objects instance.<p> 654 * 655 * @return a clone of this instance 656 */ 657 @Override 658 public Object clone() { 659 660 return getCopy(); 661 } 662 663 /** 664 * Uses the resource root path to compare two resources.<p> 665 * 666 * Please note a number of additional comparators for resources exists as members of this class.<p> 667 * 668 * @see java.lang.Comparable#compareTo(java.lang.Object) 669 * 670 * @see #COMPARE_DATE_RELEASED 671 * @see #COMPARE_ROOT_PATH 672 * @see #COMPARE_ROOT_PATH_IGNORE_CASE 673 * @see #COMPARE_ROOT_PATH_IGNORE_CASE_FOLDERS_FIRST 674 */ 675 public int compareTo(I_CmsResource obj) { 676 677 if (obj == this) { 678 return 0; 679 } 680 return m_rootPath.compareTo(obj.getRootPath()); 681 } 682 683 /** 684 * Two resources are considered equal in case their structure id is equal.<p> 685 * 686 * @see java.lang.Object#equals(java.lang.Object) 687 */ 688 @Override 689 public boolean equals(Object obj) { 690 691 if (obj == null) { 692 return false; 693 } 694 695 if (obj == this) { 696 return true; 697 } 698 if (obj instanceof CmsResource) { 699 return ((CmsResource)obj).m_structureId.equals(m_structureId); 700 } 701 return false; 702 } 703 704 /** 705 * Creates a copy of this resource.<p> 706 * 707 * This is useful in case you want to create a copy of a resource and 708 * really make sure won't get a {@link CmsFile} or {@link CmsFolder}, which may happen 709 * if you just call {@link #clone()}.<p> 710 * 711 * @return a copy of this resource 712 */ 713 public CmsResource getCopy() { 714 715 CmsResource result = new CmsResource( 716 m_structureId, 717 m_resourceId, 718 m_rootPath, 719 m_typeId, 720 m_isFolder, 721 m_flags, 722 m_projectLastModified, 723 m_state, 724 m_dateCreated, 725 m_userCreated, 726 m_dateLastModified, 727 m_userLastModified, 728 m_dateReleased, 729 m_dateExpired, 730 m_siblingCount, 731 m_length, 732 m_dateContent, 733 m_version); 734 735 if (isTouched()) { 736 result.setDateLastModified(m_dateLastModified); 737 } 738 739 return result; 740 } 741 742 /** 743 * Returns the date of the last modification of the content of this resource.<p> 744 * 745 * This applies only to resources of type {@link CmsFile}, since a {@link CmsFolder} has no content. 746 * In case of a folder, <code>-1</code> is always returned as content date.<p> 747 * 748 * Any modification of a resource, including changes to the resource properties, 749 * will increase the "date of last modification" which is returned by {@link #getDateLastModified()}. 750 * The "date of the content" as returned by this method only changes when the 751 * file content as returned by {@link CmsFile#getContents()} is changed.<p> 752 * 753 * @return the date of the last modification of the content of this resource 754 * 755 * @since 7.0.0 756 */ 757 public long getDateContent() { 758 759 return m_dateContent; 760 } 761 762 /** 763 * Returns the date of the creation of this resource.<p> 764 * 765 * @return the date of the creation of this resource 766 */ 767 public long getDateCreated() { 768 769 return m_dateCreated; 770 } 771 772 /** 773 * Returns the expiration date this resource.<p> 774 * 775 * If the expiration date has not been set, {@link #DATE_EXPIRED_DEFAULT} is returned. 776 * This means: The resource does never expire.<p> 777 * 778 * @return the expiration date of this resource 779 */ 780 public long getDateExpired() { 781 782 return m_dateExpired; 783 } 784 785 /** 786 * Returns the date of the last modification of this resource.<p> 787 * 788 * @return the date of the last modification of this resource 789 */ 790 public long getDateLastModified() { 791 792 return m_dateLastModified; 793 } 794 795 /** 796 * Returns the release date this resource.<p> 797 * 798 * If the release date has not been set, {@link #DATE_RELEASED_DEFAULT} is returned. 799 * This means: The resource has always been released.<p> 800 * 801 * @return the release date of this resource 802 */ 803 public long getDateReleased() { 804 805 return m_dateReleased; 806 } 807 808 /** 809 * Returns the flags of this resource.<p> 810 * 811 * @return the flags of this resource 812 * 813 * @see #setFlags(int) for an explanation of the resource flags 814 */ 815 public int getFlags() { 816 817 return m_flags; 818 } 819 820 /** 821 * Returns the content length of this resource.<p> 822 * 823 * If the resource is a file, then this is the byte size of the file content. 824 * If the resource is a folder, then the size is always -1.<p> 825 * 826 * @return the content length of the content 827 */ 828 public int getLength() { 829 830 // make sure folders always have a -1 size 831 return m_isFolder ? -1 : m_length; 832 } 833 834 /** 835 * Returns the file name of this resource without parent folders, for example <code>index.html</code>.<p> 836 * 837 * @return the file name of this resource without parent folders 838 */ 839 public String getName() { 840 841 String name = getName(m_rootPath); 842 if (name.charAt(name.length() - 1) == '/') { 843 return name.substring(0, name.length() - 1); 844 } else { 845 return name; 846 } 847 } 848 849 /** 850 * Returns the id of the {@link CmsProject} where this resource has been last modified.<p> 851 * 852 * @return the id of the {@link CmsProject} where this resource has been last modified, or <code>null</code> 853 */ 854 public CmsUUID getProjectLastModified() { 855 856 return m_projectLastModified; 857 } 858 859 /** 860 * Returns the id of the database content record of this resource.<p> 861 * 862 * @return the id of the database content record of this resource 863 */ 864 public CmsUUID getResourceId() { 865 866 return m_resourceId; 867 } 868 869 /** 870 * Returns the name of this resource with it's full path from the top level root folder, 871 * for example <code>/sites/default/myfolder/index.html</code>.<p> 872 * 873 * In a presentation level application usually the current site root must be 874 * cut of from the root path. Use {@link CmsObject#getSitePath(CmsResource)} 875 * to get the "absolute" path of a resource in the current site.<p> 876 * 877 * @return the name of this resource with it's full path from the top level root folder 878 * 879 * @see CmsObject#getSitePath(CmsResource) 880 * @see CmsRequestContext#getSitePath(CmsResource) 881 * @see CmsRequestContext#removeSiteRoot(String) 882 */ 883 public String getRootPath() { 884 885 return m_rootPath; 886 } 887 888 /** 889 * Returns the number of siblings of this resource, also counting this resource.<p> 890 * 891 * If a resource has no sibling, the total sibling count for this resource is <code>1</code>, 892 * if a resource has <code>n</code> siblings, the sibling count is <code>n + 1</code>.<p> 893 * 894 * @return the number of siblings of this resource, also counting this resource 895 */ 896 public int getSiblingCount() { 897 898 return m_siblingCount; 899 } 900 901 /** 902 * Returns the state of this resource.<p> 903 * 904 * This may be {@link CmsResource#STATE_UNCHANGED}, 905 * {@link CmsResource#STATE_CHANGED}, {@link CmsResource#STATE_NEW} 906 * or {@link CmsResource#STATE_DELETED}.<p> 907 * 908 * @return the state of this resource 909 */ 910 public CmsResourceState getState() { 911 912 return m_state; 913 } 914 915 /** 916 * Returns the id of the database structure record of this resource.<p> 917 * 918 * @return the id of the database structure record of this resource 919 */ 920 public CmsUUID getStructureId() { 921 922 return m_structureId; 923 } 924 925 /** 926 * Returns the resource type id for this resource.<p> 927 * 928 * @return the resource type id of this resource 929 */ 930 public int getTypeId() { 931 932 return m_typeId; 933 } 934 935 /** 936 * Returns the user id of the {@link CmsUser} who created this resource.<p> 937 * 938 * @return the user id of the {@link CmsUser} who created this resource 939 */ 940 public CmsUUID getUserCreated() { 941 942 return m_userCreated; 943 } 944 945 /** 946 * Returns the id of the {@link CmsUser} who made the last modification on this resource.<p> 947 * 948 * @return the id of the {@link CmsUser} who made the last modification on this resource 949 */ 950 public CmsUUID getUserLastModified() { 951 952 return m_userLastModified; 953 } 954 955 /** 956 * Returns the current version number of this resource.<p> 957 * 958 * @return the current version number of this resource 959 */ 960 public int getVersion() { 961 962 return m_version; 963 } 964 965 /** 966 * @see java.lang.Object#hashCode() 967 */ 968 @Override 969 public int hashCode() { 970 971 if (m_structureId != null) { 972 return m_structureId.hashCode(); 973 } 974 975 return CmsUUID.getNullUUID().hashCode(); 976 } 977 978 /** 979 * Returns <code>true</code> if this resource is expired at the given time according to the 980 * information stored in {@link #getDateExpired()}.<p> 981 * 982 * @param time the time to check the expiration date against 983 * 984 * @return <code>true</code> if this resource is expired at the given time 985 * 986 * @see #isReleased(long) 987 * @see #isReleasedAndNotExpired(long) 988 * @see #DATE_RELEASED_EXPIRED_IGNORE 989 * @see CmsResource#getDateReleased() 990 * @see CmsRequestContext#getRequestTime() 991 */ 992 public boolean isExpired(long time) { 993 994 return (time > m_dateExpired) && (time != DATE_RELEASED_EXPIRED_IGNORE); 995 } 996 997 /** 998 * Returns <code>true</code> if the resource is a {@link CmsFile}, that is not a {@link CmsFolder}.<p> 999 * 1000 * @return true if this resource is a file, false otherwise 1001 */ 1002 public boolean isFile() { 1003 1004 return !m_isFolder; 1005 } 1006 1007 /** 1008 * Returns <code>true</code> if the resource is a {@link CmsFolder}, that is not a {@link CmsFile}.<p> 1009 * 1010 * @return true if this resource is a folder, false otherwise 1011 */ 1012 public boolean isFolder() { 1013 1014 return m_isFolder; 1015 } 1016 1017 /** 1018 * Returns <code>true</code> if the resource is marked as internal.<p> 1019 * 1020 * An internal resource can be read by the OpenCms API, but it can not be delivered 1021 * by a direct request from an outside user.<p> 1022 * 1023 * For example if the resource <code>/internal.xml</code> 1024 * has been set as marked as internal, this resource can not be requested by an HTTP request, 1025 * so when a user enters <code>http:/www.myserver.com/opencms/opencms/internal.xml</code> in the browser 1026 * this will generate a {@link CmsVfsResourceNotFoundException}.<p> 1027 * 1028 * This state is stored as bit 1 in the resource flags.<p> 1029 * 1030 * @return <code>true</code> if the resource is internal 1031 */ 1032 public boolean isInternal() { 1033 1034 return ((m_flags & FLAG_INTERNAL) > 0); 1035 } 1036 1037 /** 1038 * Returns <code>true</code> if the resource has to be labeled with a special icon in the explorer view.<p> 1039 * 1040 * This state is stored as bit 2 in the resource flags.<p> 1041 * 1042 * @return <code>true</code> if the resource has to be labeled in the explorer view 1043 */ 1044 public boolean isLabeled() { 1045 1046 return ((m_flags & CmsResource.FLAG_LABELED) > 0); 1047 } 1048 1049 /** 1050 * Returns <code>true</code> if this resource is released at the given time according to the 1051 * information stored in {@link #getDateReleased()}.<p> 1052 * 1053 * @param time the time to check the release date against 1054 * 1055 * @return <code>true</code> if this resource is released at the given time 1056 * 1057 * @see #isExpired(long) 1058 * @see #isReleasedAndNotExpired(long) 1059 * @see #DATE_RELEASED_EXPIRED_IGNORE 1060 * @see CmsResource#getDateReleased() 1061 * @see CmsRequestContext#getRequestTime() 1062 */ 1063 public boolean isReleased(long time) { 1064 1065 return (time > m_dateReleased) || (time == DATE_RELEASED_EXPIRED_IGNORE); 1066 } 1067 1068 /** 1069 * Returns <code>true</code> if this resource is valid at the given time according to the 1070 * information stored in {@link #getDateReleased()} and {@link #getDateExpired()}.<p> 1071 * 1072 * A resource is valid if it is released and not yet expired.<p> 1073 * 1074 * @param time the time to check the release and expiration date against 1075 * 1076 * @return <code>true</code> if this resource is valid at the given time 1077 * 1078 * @see #isExpired(long) 1079 * @see #isReleased(long) 1080 * @see #DATE_RELEASED_EXPIRED_IGNORE 1081 * @see CmsResource#getDateReleased() 1082 * @see CmsRequestContext#getRequestTime() 1083 */ 1084 public boolean isReleasedAndNotExpired(long time) { 1085 1086 return ((time < m_dateExpired) && (time > m_dateReleased)) || (time == DATE_RELEASED_EXPIRED_IGNORE); 1087 } 1088 1089 /** 1090 * Returns <code>true</code> if this resource is a temporary file.<p> 1091 * 1092 * A resource is considered a temporary file it is a file where the 1093 * {@link CmsResource#FLAG_TEMPFILE} flag has been set, or if the file name (without parent folders) 1094 * starts with the prefix char <code>'~'</code> (tilde).<p> 1095 * 1096 * @return <code>true</code> if the given resource name is a temporary file 1097 * 1098 * @see #isTemporaryFileName(String) 1099 */ 1100 public boolean isTemporaryFile() { 1101 1102 return isFile() && (((getFlags() & CmsResource.FLAG_TEMPFILE) > 0) || isTemporaryFileName(getName())); 1103 } 1104 1105 /** 1106 * Returns <code>true</code> if this resource was touched.<p> 1107 * 1108 * @return <code>true</code> if this resource was touched 1109 */ 1110 public boolean isTouched() { 1111 1112 return m_isTouched; 1113 } 1114 1115 /** 1116 * Sets the expiration date this resource.<p> 1117 * 1118 * @param time the expiration date to set 1119 */ 1120 public void setDateExpired(long time) { 1121 1122 m_dateExpired = time; 1123 } 1124 1125 /** 1126 * Sets the date of the last modification of this resource.<p> 1127 * 1128 * @param time the last modification date to set 1129 */ 1130 public void setDateLastModified(long time) { 1131 1132 m_isTouched = true; 1133 m_dateLastModified = time; 1134 } 1135 1136 /** 1137 * Sets the release date this resource.<p> 1138 * 1139 * @param time the release date to set 1140 */ 1141 public void setDateReleased(long time) { 1142 1143 m_dateReleased = time; 1144 } 1145 1146 /** 1147 * Sets the flags of this resource.<p> 1148 * 1149 * The resource flags integer is used as bit set that contains special information about the resource. 1150 * The following methods internally use the resource flags:<ul> 1151 * <li>{@link #isInternal()} 1152 * <li>{@link #isLabeled()} 1153 * </ul> 1154 * 1155 * @param flags the flags value to set 1156 */ 1157 public void setFlags(int flags) { 1158 1159 m_flags = flags; 1160 } 1161 1162 /** 1163 * Sets the state of this resource.<p> 1164 * 1165 * @param state the state to set 1166 */ 1167 public void setState(CmsResourceState state) { 1168 1169 m_state = state; 1170 } 1171 1172 /** 1173 * Sets the type of this resource.<p> 1174 * 1175 * @param type the type to set 1176 */ 1177 public void setType(int type) { 1178 1179 m_typeId = type; 1180 } 1181 1182 /** 1183 * Sets the user id of the user who changed this resource.<p> 1184 * 1185 * @param resourceLastModifiedByUserId the user id of the user who changed the resource 1186 */ 1187 public void setUserLastModified(CmsUUID resourceLastModifiedByUserId) { 1188 1189 m_userLastModified = resourceLastModifiedByUserId; 1190 } 1191 1192 /** 1193 * @see java.lang.Object#toString() 1194 */ 1195 @Override 1196 public String toString() { 1197 1198 StringBuffer result = new StringBuffer(); 1199 1200 result.append("["); 1201 result.append(this.getClass().getName()); 1202 result.append(", path: "); 1203 result.append(m_rootPath); 1204 result.append(", structure id "); 1205 result.append(m_structureId); 1206 result.append(", resource id: "); 1207 result.append(m_resourceId); 1208 result.append(", type id: "); 1209 result.append(m_typeId); 1210 result.append(", folder: "); 1211 result.append(m_isFolder); 1212 result.append(", flags: "); 1213 result.append(m_flags); 1214 result.append(", project: "); 1215 result.append(m_projectLastModified); 1216 result.append(", state: "); 1217 result.append(m_state); 1218 result.append(", date created: "); 1219 result.append(new java.util.Date(m_dateCreated)); 1220 result.append(", user created: "); 1221 result.append(m_userCreated); 1222 result.append(", date lastmodified: "); 1223 result.append(new java.util.Date(m_dateLastModified)); 1224 result.append(", user lastmodified: "); 1225 result.append(m_userLastModified); 1226 result.append(", date released: "); 1227 result.append(new java.util.Date(m_dateReleased)); 1228 result.append(", date expired: "); 1229 result.append(new java.util.Date(m_dateExpired)); 1230 result.append(", date content: "); 1231 result.append(new java.util.Date(m_dateContent)); 1232 result.append(", size: "); 1233 result.append(m_length); 1234 result.append(", sibling count: "); 1235 result.append(m_siblingCount); 1236 result.append(", version: "); 1237 result.append(m_version); 1238 result.append("]"); 1239 1240 return result.toString(); 1241 } 1242}