0001: /*
0002: * File : $Source: /usr/local/cvs/opencms/src/org/opencms/file/CmsResource.java,v $
0003: * Date : $Date: 2008-02-27 12:05:38 $
0004: * Version: $Revision: 1.49 $
0005: *
0006: * This library is part of OpenCms -
0007: * the Open Source Content Management System
0008: *
0009: * Copyright (c) 2002 - 2008 Alkacon Software GmbH (http://www.alkacon.com)
0010: *
0011: * This library is free software; you can redistribute it and/or
0012: * modify it under the terms of the GNU Lesser General Public
0013: * License as published by the Free Software Foundation; either
0014: * version 2.1 of the License, or (at your option) any later version.
0015: *
0016: * This library is distributed in the hope that it will be useful,
0017: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0018: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0019: * Lesser General Public License for more details.
0020: *
0021: * For further information about Alkacon Software GmbH, please see the
0022: * company website: http://www.alkacon.com
0023: *
0024: * For further information about OpenCms, please see the
0025: * project website: http://www.opencms.org
0026: *
0027: * You should have received a copy of the GNU Lesser General Public
0028: * License along with this library; if not, write to the Free Software
0029: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0030: */
0031:
0032: package org.opencms.file;
0033:
0034: import org.opencms.db.CmsResourceState;
0035: import org.opencms.main.CmsIllegalArgumentException;
0036: import org.opencms.util.A_CmsModeIntEnumeration;
0037: import org.opencms.util.CmsStringUtil;
0038: import org.opencms.util.CmsUUID;
0039:
0040: import java.io.Serializable;
0041: import java.util.Comparator;
0042:
0043: /**
0044: * Base class for all OpenCms VFS resources like <code>{@link CmsFile}</code> or <code>{@link CmsFolder}</code>.<p>
0045: *
0046: * The OpenCms VFS resource is an important object for using the OpenCms API.
0047: * Basically, all entries in the OpenCms VFS are considered to be "resources".
0048: * Currently, only two types of resources exists:<ul>
0049: * <li>Files, which are represented by the subclass {@link CmsFile}.
0050: * <li>Folders (also called Directories), which are represented by the subclass {@link CmsFolder}.
0051: * </ul>
0052: *
0053: * If you have a resource, you can use {@link #isFile()} or {@link #isFolder()} to learn what kind of
0054: * subclass you have. Please note that this is usually not required, as the only real difference between a
0055: * {@link CmsFile} and a {@link CmsResource} is that the {@link CmsFile} also has the contents of the file,
0056: * which you can obtain using {@link CmsFile#getContents()}. As long as you don't need the content, you can
0057: * use the {@link CmsResource} for everything else. This is even more true for a {@link CmsFolder}, here you
0058: * will need the subclass only in special cases, since the signature is identical to {@link CmsResource}.<p>
0059: *
0060: * A OpenCms VFS resource can have any number of properties attached, which are represented by a {@link CmsProperty}.
0061: * To read the properties for a resource, use {@link CmsObject#readPropertyObject(CmsResource, String, boolean)}
0062: * or use {@link CmsObject#readPropertyObjects(CmsResource, boolean)} to read all properties of the resource.<p>
0063: *
0064: * @author Alexander Kandzior
0065: * @author Michael Emmerich
0066: *
0067: * @version $Revision: 1.49 $
0068: *
0069: * @since 6.0.0
0070: */
0071: public class CmsResource extends Object implements Cloneable,
0072: Serializable, Comparable {
0073:
0074: /**
0075: * Enumeration class for resource copy modes.<p>
0076: */
0077: public static final class CmsResourceCopyMode extends
0078: A_CmsModeIntEnumeration {
0079:
0080: /** Copy mode for copy resources as new resource. */
0081: protected static final CmsResourceCopyMode MODE_COPY_AS_NEW = new CmsResourceCopyMode(
0082: 1);
0083:
0084: /** Copy mode for copy resources as sibling. */
0085: protected static final CmsResourceCopyMode MODE_COPY_AS_SIBLING = new CmsResourceCopyMode(
0086: 2);
0087:
0088: /** Copy mode to preserve siblings during copy. */
0089: protected static final CmsResourceCopyMode MODE_COPY_PRESERVE_SIBLING = new CmsResourceCopyMode(
0090: 3);
0091:
0092: /** Version id required for safe serialization. */
0093: private static final long serialVersionUID = 9081630878178799137L;
0094:
0095: /**
0096: * Private constructor.<p>
0097: *
0098: * @param mode the copy mode integer representation
0099: */
0100: private CmsResourceCopyMode(int mode) {
0101:
0102: super (mode);
0103: }
0104:
0105: /**
0106: * Returns the copy mode object from the old copy mode integer.<p>
0107: *
0108: * @param mode the old copy mode integer
0109: *
0110: * @return the copy mode object
0111: */
0112: public static CmsResourceCopyMode valueOf(int mode) {
0113:
0114: switch (mode) {
0115: case 1:
0116: return CmsResourceCopyMode.MODE_COPY_AS_NEW;
0117: case 2:
0118: return CmsResourceCopyMode.MODE_COPY_AS_SIBLING;
0119: case 3:
0120: default:
0121: return CmsResourceCopyMode.MODE_COPY_PRESERVE_SIBLING;
0122: }
0123: }
0124: }
0125:
0126: /**
0127: * Enumeration class for resource delete modes.<p>
0128: */
0129: public static final class CmsResourceDeleteMode extends
0130: A_CmsModeIntEnumeration {
0131:
0132: /** Signals that siblings of this resource should not be deleted. */
0133: protected static final CmsResourceDeleteMode MODE_DELETE_PRESERVE_SIBLINGS = new CmsResourceDeleteMode(
0134: 1);
0135:
0136: /** Signals that siblings of this resource should be deleted. */
0137: protected static final CmsResourceDeleteMode MODE_DELETE_REMOVE_SIBLINGS = new CmsResourceDeleteMode(
0138: 2);
0139:
0140: /** Version id required for safe serialization. */
0141: private static final long serialVersionUID = 2010402524576925865L;
0142:
0143: /**
0144: * Private constructor.<p>
0145: *
0146: * @param mode the delete mode integer representation
0147: */
0148: private CmsResourceDeleteMode(int mode) {
0149:
0150: super (mode);
0151: }
0152:
0153: /**
0154: * Returns the delete mode object from the old delete mode integer.<p>
0155: *
0156: * @param mode the old delete mode integer
0157: *
0158: * @return the delete mode object
0159: */
0160: public static CmsResourceDeleteMode valueOf(int mode) {
0161:
0162: switch (mode) {
0163: case 1:
0164: return CmsResourceDeleteMode.MODE_DELETE_PRESERVE_SIBLINGS;
0165: case 2:
0166: default:
0167: return CmsResourceDeleteMode.MODE_DELETE_REMOVE_SIBLINGS;
0168: }
0169: }
0170: }
0171:
0172: /**
0173: * Enumeration class for resource undo changes modes.<p>
0174: */
0175: public static final class CmsResourceUndoMode extends
0176: A_CmsModeIntEnumeration {
0177:
0178: /** Indicates that the undo method will only undo content changes. */
0179: public static final CmsResourceUndoMode MODE_UNDO_CONTENT = new CmsResourceUndoMode(
0180: 1);
0181:
0182: /** Indicates that the undo method will only recursive undo content changes. */
0183: public static final CmsResourceUndoMode MODE_UNDO_CONTENT_RECURSIVE = new CmsResourceUndoMode(
0184: 2);
0185:
0186: /** Indicates that the undo method will undo move operations and content changes. */
0187: public static final CmsResourceUndoMode MODE_UNDO_MOVE_CONTENT = new CmsResourceUndoMode(
0188: 3);
0189:
0190: /** Indicates that the undo method will undo move operations and recursive content changes. */
0191: public static final CmsResourceUndoMode MODE_UNDO_MOVE_CONTENT_RECURSIVE = new CmsResourceUndoMode(
0192: 4);
0193:
0194: /** Version id required for safe serialization. */
0195: private static final long serialVersionUID = 3521620626485212068L;
0196:
0197: /**
0198: * private constructor.<p>
0199: *
0200: * @param mode the undo changes mode integer representation
0201: */
0202: private CmsResourceUndoMode(int mode) {
0203:
0204: super (mode);
0205: }
0206:
0207: /**
0208: * Returns the undo mode object from the old undo mode integer.<p>
0209: *
0210: * @param mode the old undo mode integer
0211: *
0212: * @return the undo mode object
0213: */
0214: public static CmsResourceUndoMode valueOf(int mode) {
0215:
0216: switch (mode) {
0217: case 1:
0218: return CmsResourceUndoMode.MODE_UNDO_CONTENT;
0219: case 2:
0220: return CmsResourceUndoMode.MODE_UNDO_CONTENT_RECURSIVE;
0221: case 3:
0222: return CmsResourceUndoMode.MODE_UNDO_MOVE_CONTENT;
0223: case 4:
0224: default:
0225: return CmsResourceUndoMode.MODE_UNDO_MOVE_CONTENT_RECURSIVE;
0226: }
0227: }
0228:
0229: /**
0230: * Returns a mode that includes the move operation with the same semantic as this mode.<p>
0231: *
0232: * @return a mode that includes the move operation with the same semantic as this mode
0233: */
0234: public CmsResourceUndoMode includeMove() {
0235:
0236: if (!isUndoMove()) {
0237: // keep the same semantic but including move
0238: return CmsResourceUndoMode.valueOf(getMode() + 2);
0239: }
0240: return this ;
0241: }
0242:
0243: /**
0244: * Returns <code>true</code> if this undo operation is recursive.<p>
0245: *
0246: * @return <code>true</code> if this undo operation is recursive
0247: */
0248: public boolean isRecursive() {
0249:
0250: return getMode() > CmsResource.UNDO_CONTENT.getMode();
0251: }
0252:
0253: /**
0254: * Returns <code>true</code> if this undo mode will undo move operations.<p>
0255: *
0256: * @return <code>true</code> if this undo mode will undo move operations
0257: */
0258: public boolean isUndoMove() {
0259:
0260: return getMode() > CmsResource.UNDO_CONTENT_RECURSIVE
0261: .getMode();
0262: }
0263:
0264: /**
0265: * @see java.lang.Object#toString()
0266: */
0267: public String toString() {
0268:
0269: return String.valueOf(getMode());
0270: }
0271: }
0272:
0273: /**
0274: * A comparator for the release date of two resources.<p>
0275: *
0276: * If the release date of a resource is not set, the
0277: * creation date is used instead.<p>
0278: */
0279: public static final Comparator COMPARE_DATE_RELEASED = new Comparator() {
0280:
0281: /**
0282: * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
0283: */
0284: public int compare(Object o1, Object o2) {
0285:
0286: if ((o1 == o2) || !(o1 instanceof CmsResource)
0287: || !(o2 instanceof CmsResource)) {
0288: return 0;
0289: }
0290:
0291: CmsResource r1 = (CmsResource) o1;
0292: CmsResource r2 = (CmsResource) o2;
0293:
0294: long date1 = r1.getDateReleased();
0295: if (date1 == CmsResource.DATE_RELEASED_DEFAULT) {
0296: // use last modification date if release date is not set
0297: date1 = r1.getDateLastModified();
0298: }
0299:
0300: long date2 = r2.getDateReleased();
0301: if (date2 == CmsResource.DATE_RELEASED_DEFAULT) {
0302: // use last modification date if release date is not set
0303: date2 = r2.getDateLastModified();
0304: }
0305:
0306: return (date1 > date2) ? -1 : (date1 < date2) ? 1 : 0;
0307: }
0308: };
0309:
0310: /**
0311: * A comparator for the root path of two resources.<p>
0312: */
0313: public static final Comparator COMPARE_ROOT_PATH = new Comparator() {
0314:
0315: /**
0316: * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
0317: */
0318: public int compare(Object o1, Object o2) {
0319:
0320: if ((o1 == o2) || !(o1 instanceof CmsResource)
0321: || !(o2 instanceof CmsResource)) {
0322: return 0;
0323: }
0324:
0325: CmsResource r1 = (CmsResource) o1;
0326: CmsResource r2 = (CmsResource) o2;
0327:
0328: return r1.getRootPath().compareTo(r2.getRootPath());
0329: }
0330: };
0331:
0332: /**
0333: * A comparator for the root path of two resources ignoring case differences.<p>
0334: */
0335: public static final Comparator COMPARE_ROOT_PATH_IGNORE_CASE = new Comparator() {
0336:
0337: /**
0338: * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
0339: */
0340: public int compare(Object o1, Object o2) {
0341:
0342: if ((o1 == o2) || !(o1 instanceof CmsResource)
0343: || !(o2 instanceof CmsResource)) {
0344: return 0;
0345: }
0346:
0347: CmsResource r1 = (CmsResource) o1;
0348: CmsResource r2 = (CmsResource) o2;
0349:
0350: return r1.getRootPath().compareToIgnoreCase(
0351: r2.getRootPath());
0352: }
0353: };
0354:
0355: /**
0356: * A comparator for the root path of two resources ignoring case differences, putting folders before files.<p>
0357: */
0358: public static final Comparator COMPARE_ROOT_PATH_IGNORE_CASE_FOLDERS_FIRST = new Comparator() {
0359:
0360: /**
0361: * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
0362: */
0363: public int compare(Object o1, Object o2) {
0364:
0365: if ((o1 == o2) || !(o1 instanceof CmsResource)
0366: || !(o2 instanceof CmsResource)) {
0367: return 0;
0368: }
0369:
0370: CmsResource r1 = (CmsResource) o1;
0371: CmsResource r2 = (CmsResource) o2;
0372:
0373: if (r1.isFolder() && !r2.isFolder()) {
0374: return -1;
0375: } else if (r2.isFolder() && !r1.isFolder()) {
0376: return 1;
0377: }
0378: // if same type, compare the name of the resource
0379: return r1.getRootPath().compareToIgnoreCase(
0380: r2.getRootPath());
0381: }
0382: };
0383:
0384: /** Copy mode for copy resources as new resource. */
0385: public static final CmsResourceCopyMode COPY_AS_NEW = CmsResourceCopyMode.MODE_COPY_AS_NEW;
0386:
0387: /** Copy mode for copy resources as sibling. */
0388: public static final CmsResourceCopyMode COPY_AS_SIBLING = CmsResourceCopyMode.MODE_COPY_AS_SIBLING;
0389:
0390: /** Copy mode to preserve siblings during copy. */
0391: public static final CmsResourceCopyMode COPY_PRESERVE_SIBLING = CmsResourceCopyMode.MODE_COPY_PRESERVE_SIBLING;
0392:
0393: /** The default expiration date of a resource, which is: never expires. */
0394: public static final long DATE_EXPIRED_DEFAULT = Long.MAX_VALUE;
0395:
0396: /** The default release date of a resource, which is: always released. */
0397: public static final long DATE_RELEASED_DEFAULT = 0;
0398:
0399: /** A special date that indicates release and expiration information are to be ignored. */
0400: public static final long DATE_RELEASED_EXPIRED_IGNORE = Long.MIN_VALUE;
0401:
0402: /** Signals that siblings of this resource should not be deleted. */
0403: public static final CmsResourceDeleteMode DELETE_PRESERVE_SIBLINGS = CmsResourceDeleteMode.MODE_DELETE_PRESERVE_SIBLINGS;
0404:
0405: /** Signals that siblings of this resource should be deleted. */
0406: public static final CmsResourceDeleteMode DELETE_REMOVE_SIBLINGS = CmsResourceDeleteMode.MODE_DELETE_REMOVE_SIBLINGS;
0407:
0408: /** Flag to indicate that this is an internal resource, that can't be accessed directly. */
0409: public static final int FLAG_INTERNAL = 512;
0410:
0411: /** The resource is linked inside a site folder specified in the OpenCms configuration. */
0412: public static final int FLAG_LABELED = 2;
0413:
0414: /** Flag to indicate that this is a temporary resource. */
0415: public static final int FLAG_TEMPFILE = 1024;
0416:
0417: /** The name constraints when generating new resources. */
0418: public static final String NAME_CONSTRAINTS = "-._~$";
0419:
0420: /** Indicates if a resource has been changed in the offline version when compared to the online version. */
0421: public static final CmsResourceState STATE_CHANGED = CmsResourceState.STATE_CHANGED;
0422:
0423: /** Indicates if a resource has been deleted in the offline version when compared to the online version. */
0424: public static final CmsResourceState STATE_DELETED = CmsResourceState.STATE_DELETED;
0425:
0426: /**
0427: * Special state value that indicates the current state must be kept on a resource,
0428: * this value must never be written to the database.
0429: */
0430: public static final CmsResourceState STATE_KEEP = CmsResourceState.STATE_KEEP;
0431:
0432: /** Indicates if a resource is new in the offline version when compared to the online version. */
0433: public static final CmsResourceState STATE_NEW = CmsResourceState.STATE_NEW;
0434:
0435: /** Indicates if a resource is unchanged in the offline version when compared to the online version. */
0436: public static final CmsResourceState STATE_UNCHANGED = CmsResourceState.STATE_UNCHANGED;
0437:
0438: /** Flag for leaving a date unchanged during a touch operation. */
0439: public static final long TOUCH_DATE_UNCHANGED = -1;
0440:
0441: /** Indicates that the undo method will only undo content changes. */
0442: public static final CmsResourceUndoMode UNDO_CONTENT = CmsResourceUndoMode.MODE_UNDO_CONTENT;
0443:
0444: /** Indicates that the undo method will only recursive undo content changes. */
0445: public static final CmsResourceUndoMode UNDO_CONTENT_RECURSIVE = CmsResourceUndoMode.MODE_UNDO_CONTENT_RECURSIVE;
0446:
0447: /** Indicates that the undo method will undo move operations and content changes. */
0448: public static final CmsResourceUndoMode UNDO_MOVE_CONTENT = CmsResourceUndoMode.MODE_UNDO_MOVE_CONTENT;
0449:
0450: /** Indicates that the undo method will undo move operations and recursive content changes. */
0451: public static final CmsResourceUndoMode UNDO_MOVE_CONTENT_RECURSIVE = CmsResourceUndoMode.MODE_UNDO_MOVE_CONTENT_RECURSIVE;
0452:
0453: /** The vfs path of the sites master folder. */
0454: public static final String VFS_FOLDER_SITES = "/sites";
0455:
0456: /** The vfs path of the system folder. */
0457: public static final String VFS_FOLDER_SYSTEM = "/system";
0458:
0459: /** Serial version UID required for safe serialization. */
0460: private static final long serialVersionUID = 257325098790850498L;
0461:
0462: /** The date of the last modification of the content of this resource. */
0463: protected long m_dateContent = System.currentTimeMillis();
0464:
0465: /** The size of the content. */
0466: protected int m_length;
0467:
0468: /** The creation date of this resource. */
0469: private long m_dateCreated;
0470:
0471: /** The expiration date of this resource. */
0472: private long m_dateExpired;
0473:
0474: /** The date of the last modification of this resource. */
0475: private long m_dateLastModified;
0476:
0477: /** The release date of this resource. */
0478: private long m_dateReleased;
0479:
0480: /** The flags of this resource. */
0481: private int m_flags;
0482:
0483: /** Indicates if this resource is a folder or not. */
0484: private boolean m_isFolder;
0485:
0486: /** Boolean flag whether the timestamp of this resource was modified by a touch command. */
0487: private boolean m_isTouched;
0488:
0489: /** The project id where this resource has been last modified in. */
0490: private CmsUUID m_projectLastModified;
0491:
0492: /** The id of the resource database record. */
0493: private CmsUUID m_resourceId;
0494:
0495: /** The name of a resource with it's full path from the root folder including the current site root. */
0496: private String m_rootPath;
0497:
0498: /** The number of links that point to this resource. */
0499: private int m_siblingCount;
0500:
0501: /** The state of this resource. */
0502: private CmsResourceState m_state;
0503:
0504: /** The id of the structure database record. */
0505: private CmsUUID m_structureId;
0506:
0507: /** The resource type id of this resource. */
0508: private int m_typeId;
0509:
0510: /** The id of the user who created this resource. */
0511: private CmsUUID m_userCreated;
0512:
0513: /** The id of the user who modified this resource last. */
0514: private CmsUUID m_userLastModified;
0515:
0516: /** The version number of this resource. */
0517: private int m_version;
0518:
0519: /**
0520: * Creates a new CmsRecource object.<p>
0521: *
0522: * @param structureId the id of this resources structure record
0523: * @param resourceId the id of this resources resource record
0524: * @param rootPath the root path to the resource
0525: * @param type the type of this resource
0526: * @param isFolder must be true if the resource is a folder, or false if it is a file
0527: * @param flags the flags of this resource
0528: * @param projectId the project id this resource was last modified in
0529: * @param state the state of this resource
0530: * @param dateCreated the creation date of this resource
0531: * @param userCreated the id of the user who created this resource
0532: * @param dateLastModified the date of the last modification of this resource
0533: * @param userLastModified the id of the user who did the last modification of this resource
0534: * @param dateReleased the release date of this resource
0535: * @param dateExpired the expiration date of this resource
0536: * @param linkCount the count of all siblings of this resource
0537: * @param size the size of the file content of this resource
0538: * @param dateContent the date of the last modification of the content of this resource
0539: * @param version the version number of this resource
0540: */
0541: public CmsResource(CmsUUID structureId, CmsUUID resourceId,
0542: String rootPath, int type, boolean isFolder, int flags,
0543: CmsUUID projectId, CmsResourceState state,
0544: long dateCreated, CmsUUID userCreated,
0545: long dateLastModified, CmsUUID userLastModified,
0546: long dateReleased, long dateExpired, int linkCount,
0547: int size, long dateContent, int version) {
0548:
0549: m_structureId = structureId;
0550: m_resourceId = resourceId;
0551: m_rootPath = rootPath;
0552: m_typeId = type;
0553: m_isFolder = isFolder;
0554: m_flags = flags;
0555: m_projectLastModified = projectId;
0556: m_state = state;
0557: m_dateCreated = dateCreated;
0558: m_userCreated = userCreated;
0559: m_dateLastModified = dateLastModified;
0560: m_userLastModified = userLastModified;
0561: m_dateReleased = dateReleased;
0562: m_dateExpired = dateExpired;
0563: m_siblingCount = linkCount;
0564: m_length = size;
0565: m_dateContent = dateContent;
0566: m_version = version;
0567: m_isTouched = false;
0568: }
0569:
0570: /**
0571: * Checks if the provided resource name is a valid resource name,
0572: * that is contains only valid characters.<p>
0573: *
0574: * A resource name can only be composed of digits,
0575: * standard ASCII letters and the symbols defined in {@link #NAME_CONSTRAINTS}.
0576: * A resource name must also not contain only dots.<p>
0577: *
0578: * @param name the resource name to check
0579: *
0580: * @throws CmsIllegalArgumentException if the given resource name is not valid
0581: */
0582: public static void checkResourceName(String name)
0583: throws CmsIllegalArgumentException {
0584:
0585: if (CmsStringUtil.isEmptyOrWhitespaceOnly(name)) {
0586: throw new CmsIllegalArgumentException(Messages.get()
0587: .container(Messages.ERR_BAD_RESOURCENAME_EMPTY_0,
0588: name));
0589: }
0590:
0591: CmsStringUtil.checkName(name, NAME_CONSTRAINTS,
0592: Messages.ERR_BAD_RESOURCENAME_4, Messages.get());
0593:
0594: // check for filenames that have only dots (which will cause issues in the static export)
0595: boolean onlydots = true;
0596: // this must be done only for the last name (not for parent folders)
0597: String lastName = CmsResource.getName(name);
0598: int l = lastName.length();
0599: for (int i = 0; i < l; i++) {
0600: char c = lastName.charAt(i);
0601: if ((c != '.') && (c != '/')) {
0602: onlydots = false;
0603: }
0604: }
0605: if (onlydots) {
0606: throw new CmsIllegalArgumentException(Messages.get()
0607: .container(Messages.ERR_BAD_RESOURCENAME_DOTS_1,
0608: lastName));
0609: }
0610: }
0611:
0612: /**
0613: * Returns the folder path of the resource with the given name.<p>
0614: *
0615: * If the resource name denotes a folder (that is ends with a "/"), the complete path of the folder
0616: * is returned (not the parent folder path).<p>
0617: *
0618: * This is achieved by just cutting of everything behind the last occurrence of a "/" character
0619: * in the String, no check if performed if the resource exists or not in the VFS,
0620: * only resources that end with a "/" are considered to be folders.
0621: *
0622: * Example: Returns <code>/system/def/</code> for the
0623: * resource <code>/system/def/file.html</code> and
0624: * <code>/system/def/</code> for the (folder) resource <code>/system/def/</code>.
0625: *
0626: * @param resource the name of a resource
0627: * @return the folder of the given resource
0628: */
0629: public static String getFolderPath(String resource) {
0630:
0631: return resource.substring(0, resource.lastIndexOf('/') + 1);
0632: }
0633:
0634: /**
0635: * Returns the name of a resource without the path information.<p>
0636: *
0637: * The resource name of a file is the name of the file.
0638: * The resource name of a folder is the folder name with trailing "/".
0639: * The resource name of the root folder is <code>/</code>.<p>
0640: *
0641: * Example: <code>/system/workplace/</code> has the resource name <code>workplace/</code>.
0642: *
0643: * @param resource the resource to get the name for
0644: * @return the name of a resource without the path information
0645: */
0646: public static String getName(String resource) {
0647:
0648: if ("/".equals(resource)) {
0649: return "/";
0650: }
0651: // remove the last char, for a folder this will be "/", for a file it does not matter
0652: String parent = (resource.substring(0, resource.length() - 1));
0653: // now as the name does not end with "/", check for the last "/" which is the parent folder name
0654: return resource.substring(parent.lastIndexOf('/') + 1);
0655: }
0656:
0657: /**
0658: * Returns the absolute parent folder name of a resource.<p>
0659: *
0660: * The parent resource of a file is the folder of the file.
0661: * The parent resource of a folder is the parent folder.
0662: * The parent resource of the root folder is <code>null</code>.<p>
0663: *
0664: * Example: <code>/system/workplace/</code> has the parent <code>/system/</code>.
0665: *
0666: * @param resource the resource to find the parent folder for
0667: * @return the calculated parent absolute folder path, or <code>null</code> for the root folder
0668: */
0669: public static String getParentFolder(String resource) {
0670:
0671: if (CmsStringUtil.isEmptyOrWhitespaceOnly(resource)
0672: || "/".equals(resource)) {
0673: return null;
0674: }
0675: // remove the last char, for a folder this will be "/", for a file it does not matter
0676: String parent = (resource.substring(0, resource.length() - 1));
0677: // now as the name does not end with "/", check for the last "/" which is the parent folder name
0678: return parent.substring(0, parent.lastIndexOf('/') + 1);
0679: }
0680:
0681: /**
0682: * Returns the directory level of a resource.<p>
0683: *
0684: * The root folder "/" has level 0,
0685: * a folder "/foo/" would have level 1,
0686: * a folfer "/foo/bar/" level 2 etc.<p>
0687: *
0688: * @param resource the resource to determine the directory level for
0689: * @return the directory level of a resource
0690: */
0691: public static int getPathLevel(String resource) {
0692:
0693: int level = -1;
0694: int pos = 0;
0695: while (resource.indexOf('/', pos) >= 0) {
0696: pos = resource.indexOf('/', pos) + 1;
0697: level++;
0698: }
0699: return level;
0700: }
0701:
0702: /**
0703: * Returns the name of a parent folder of the given resource,
0704: * that is either minus levels up
0705: * from the current folder, or that is plus levels down from the
0706: * root folder.<p>
0707: *
0708: * @param resource the name of a resource
0709: * @param level of levels to walk up or down
0710: * @return the name of a parent folder of the given resource
0711: */
0712: public static String getPathPart(String resource, int level) {
0713:
0714: resource = getFolderPath(resource);
0715: String result = null;
0716: int pos = 0, count = 0;
0717: if (level >= 0) {
0718: // Walk down from the root folder /
0719: while ((count < level) && (pos > -1)) {
0720: count++;
0721: pos = resource.indexOf('/', pos + 1);
0722: }
0723: } else {
0724: // Walk up from the current folder
0725: pos = resource.length();
0726: while ((count > level) && (pos > -1)) {
0727: count--;
0728: pos = resource.lastIndexOf('/', pos - 1);
0729: }
0730: }
0731: if (pos > -1) {
0732: // To many levels walked
0733: result = resource.substring(0, pos + 1);
0734: } else {
0735: // Add trailing slash
0736: result = (level < 0) ? "/" : resource;
0737: }
0738: return result;
0739: }
0740:
0741: /**
0742: * Returns true if the resource name certainly denotes a folder, that is ends with a "/".<p>
0743: *
0744: * @param resource the resource to check
0745: * @return true if the resource name certainly denotes a folder, that is ends with a "/"
0746: */
0747: public static boolean isFolder(String resource) {
0748:
0749: return CmsStringUtil.isNotEmpty(resource)
0750: && (resource.charAt(resource.length() - 1) == '/');
0751: }
0752:
0753: /**
0754: * Returns a clone of this Objects instance.<p>
0755: *
0756: * @return a clone of this instance
0757: */
0758: public Object clone() {
0759:
0760: CmsResource clone = new CmsResource(m_structureId,
0761: m_resourceId, m_rootPath, m_typeId, m_isFolder,
0762: m_flags, m_projectLastModified, m_state, m_dateCreated,
0763: m_userCreated, m_dateLastModified, m_userLastModified,
0764: m_dateReleased, m_dateExpired, m_siblingCount,
0765: m_length, m_dateContent, m_version);
0766:
0767: if (isTouched()) {
0768: clone.setDateLastModified(m_dateLastModified);
0769: }
0770:
0771: return clone;
0772: }
0773:
0774: /**
0775: * Uses the resource root path to compare two resources.<p>
0776: *
0777: * Please note a number of additional comparators for resources exists as members of this class.<p>
0778: *
0779: * @see java.lang.Comparable#compareTo(java.lang.Object)
0780: *
0781: * @see #COMPARE_DATE_RELEASED
0782: * @see #COMPARE_ROOT_PATH
0783: * @see #COMPARE_ROOT_PATH_IGNORE_CASE
0784: * @see #COMPARE_ROOT_PATH_IGNORE_CASE_FOLDERS_FIRST
0785: */
0786: public int compareTo(Object obj) {
0787:
0788: if (obj == this ) {
0789: return 0;
0790: }
0791: if (obj instanceof CmsResource) {
0792: return m_rootPath.compareTo(((CmsResource) obj).m_rootPath);
0793: }
0794: return 0;
0795: }
0796:
0797: /**
0798: * Two resources are considered equal in case their structure id is equal.<p>
0799: *
0800: * @see java.lang.Object#equals(java.lang.Object)
0801: */
0802: public boolean equals(Object obj) {
0803:
0804: if (obj == this ) {
0805: return true;
0806: }
0807: if (obj instanceof CmsResource) {
0808: return ((CmsResource) obj).m_structureId
0809: .equals(m_structureId);
0810: }
0811: return false;
0812: }
0813:
0814: /**
0815: * Returns the date of the last modification of the content of this resource.<p>
0816: *
0817: * This applies only to resources of type {@link CmsFile}, since a {@link CmsFolder} has no content.
0818: * In case of a folder, <code>-1</code> is always returned as content date.<p>
0819: *
0820: * Any modification of a resource, including changes to the resource properties,
0821: * will increase the "date of last modification" which is returned by {@link #getDateLastModified()}.
0822: * The "date of the content" as returned by this method only changes when the
0823: * file content as returned by {@link CmsFile#getContents()} is changed.<p>
0824: *
0825: * @return the date of the last modification of the content of this resource
0826: *
0827: * @since 7.0.0
0828: */
0829: public long getDateContent() {
0830:
0831: return m_dateContent;
0832: }
0833:
0834: /**
0835: * Returns the date of the creation of this resource.<p>
0836: *
0837: * @return the date of the creation of this resource
0838: */
0839: public long getDateCreated() {
0840:
0841: return m_dateCreated;
0842: }
0843:
0844: /**
0845: * Returns the expiration date this resource.<p>
0846: *
0847: * If the expiration date has not been set, {@link #DATE_EXPIRED_DEFAULT} is returned.
0848: * This means: The resource does never expire.<p>
0849: *
0850: * @return the expiration date of this resource
0851: */
0852: public long getDateExpired() {
0853:
0854: return m_dateExpired;
0855: }
0856:
0857: /**
0858: * Returns the date of the last modification of this resource.<p>
0859: *
0860: * @return the date of the last modification of this resource
0861: */
0862: public long getDateLastModified() {
0863:
0864: return m_dateLastModified;
0865: }
0866:
0867: /**
0868: * Returns the release date this resource.<p>
0869: *
0870: * If the release date has not been set, {@link #DATE_RELEASED_DEFAULT} is returned.
0871: * This means: The resource has always been released.<p>
0872: *
0873: * @return the release date of this resource
0874: */
0875: public long getDateReleased() {
0876:
0877: return m_dateReleased;
0878: }
0879:
0880: /**
0881: * Returns the flags of this resource.<p>
0882: *
0883: * @return the flags of this resource
0884: *
0885: * @see #setFlags(int) for an explanation of the resource flags
0886: */
0887: public int getFlags() {
0888:
0889: return m_flags;
0890: }
0891:
0892: /**
0893: * Returns the length of the resource.<p>
0894: *
0895: * If the resource is a file, then this is the byte size of the file content.
0896: * If the resource is a folder, then the size is always -1.<p>
0897: *
0898: * @return the length of the content
0899: */
0900: public int getLength() {
0901:
0902: // make sure folders always have a -1 size
0903: return m_isFolder ? -1 : m_length;
0904: }
0905:
0906: /**
0907: * Returns the name of this resource without parent folders, for example <code>index.html</code>.<p>
0908: *
0909: * @return the name of this resource without parent folders
0910: */
0911: public String getName() {
0912:
0913: String name = getName(m_rootPath);
0914: if (name.charAt(name.length() - 1) == '/') {
0915: return name.substring(0, name.length() - 1);
0916: } else {
0917: return name;
0918: }
0919: }
0920:
0921: /**
0922: * Returns the id of the project where the resource has been last modified.<p>
0923: *
0924: * @return the id of the project where the resource has been last modified, or <code>null</code>
0925: */
0926: public CmsUUID getProjectLastModified() {
0927:
0928: return m_projectLastModified;
0929: }
0930:
0931: /**
0932: * Returns the id of the resource database entry of this resource.<p>
0933: *
0934: * @return the id of the resource database entry
0935: */
0936: public CmsUUID getResourceId() {
0937:
0938: return m_resourceId;
0939: }
0940:
0941: /**
0942: * Returns the name of a resource with it's full path from the root folder
0943: * including the current site root,
0944: * for example <code>/sites/default/myfolder/index.html</code>.<p>
0945: *
0946: * In a presentation level application usually the current site root must be
0947: * cut of from the root path. Use {@link CmsObject#getSitePath(CmsResource)}
0948: * to get the "absolute" path of a resource in the current site.<p>
0949: *
0950: * @return the name of a resource with it's full path from the root folder
0951: * including the current site root
0952: *
0953: * @see CmsObject#getSitePath(CmsResource)
0954: * @see CmsRequestContext#getSitePath(CmsResource)
0955: * @see CmsRequestContext#removeSiteRoot(String)
0956: */
0957: public String getRootPath() {
0958:
0959: return m_rootPath;
0960: }
0961:
0962: /**
0963: * Returns the number of siblings of this resource, also counting this resource.<p>
0964: *
0965: * If a resource has no sibling, the total sibling count for this resource is <code>1</code>,
0966: * if a resource has <code>n</code> siblings, the sibling count is <code>n + 1</code>.<p>
0967: *
0968: * @return the number of siblings of this resource, also counting this resource
0969: */
0970: public int getSiblingCount() {
0971:
0972: return m_siblingCount;
0973: }
0974:
0975: /**
0976: * Returns the change state of this resource.<p>
0977: *
0978: * This may be {@link CmsResource#STATE_UNCHANGED},
0979: * {@link CmsResource#STATE_CHANGED}, {@link CmsResource#STATE_NEW}
0980: * or {@link CmsResource#STATE_DELETED}.<p>
0981: *
0982: * @return the state of this resource
0983: */
0984: public CmsResourceState getState() {
0985:
0986: return m_state;
0987: }
0988:
0989: /**
0990: * Returns the id of the structure record of this resource.<p>
0991: *
0992: * @return the id of the structure record of this resource
0993: */
0994: public CmsUUID getStructureId() {
0995:
0996: return m_structureId;
0997: }
0998:
0999: /**
1000: * Returns the resource type id for this resource.<p>
1001: *
1002: * @return the resource type id of this resource
1003: */
1004: public int getTypeId() {
1005:
1006: return m_typeId;
1007: }
1008:
1009: /**
1010: * Returns the user id of the {@link CmsUser} who created this resource.<p>
1011: *
1012: * @return the user id of the {@link CmsUser} who created this resource
1013: */
1014: public CmsUUID getUserCreated() {
1015:
1016: return m_userCreated;
1017: }
1018:
1019: /**
1020: * Returns the user id of the {@link CmsUser} who made the last change on this resource.<p>
1021: *
1022: * @return the user id of the {@link CmsUser} who made the last change<p>
1023: */
1024: public CmsUUID getUserLastModified() {
1025:
1026: return m_userLastModified;
1027: }
1028:
1029: /**
1030: * Returns the version number of this resource.<p>
1031: *
1032: * @return the version number of this resource
1033: */
1034: public int getVersion() {
1035:
1036: return m_version;
1037: }
1038:
1039: /**
1040: * @see java.lang.Object#hashCode()
1041: */
1042: public int hashCode() {
1043:
1044: if (m_structureId != null) {
1045: return m_structureId.hashCode();
1046: }
1047:
1048: return CmsUUID.getNullUUID().hashCode();
1049: }
1050:
1051: /**
1052: * Returns <code>true</code> if this resource is expired at the given time according to the
1053: * information stored in {@link #getDateExpired()}.<p>
1054: *
1055: * @param time the time to check the expiration date against
1056: *
1057: * @return <code>true</code> if this resource is expired at the given time
1058: *
1059: * @see #isReleased(long)
1060: * @see #isReleasedAndNotExpired(long)
1061: * @see #DATE_RELEASED_EXPIRED_IGNORE
1062: * @see CmsResource#getDateReleased()
1063: * @see CmsRequestContext#getRequestTime()
1064: */
1065: public boolean isExpired(long time) {
1066:
1067: return (time > m_dateExpired)
1068: && (time != DATE_RELEASED_EXPIRED_IGNORE);
1069: }
1070:
1071: /**
1072: * Returns <code>true</code> if the resource is a {@link CmsFile}, that is not a {@link CmsFolder}.<p>
1073: *
1074: * @return true if this resource is a file, false otherwise
1075: */
1076: public boolean isFile() {
1077:
1078: return !m_isFolder;
1079: }
1080:
1081: /**
1082: * Returns <code>true</code> if the resource is a {@link CmsFolder}, that is not a {@link CmsFile}.<p>
1083: *
1084: * @return true if this resource is a folder, false otherwise
1085: */
1086: public boolean isFolder() {
1087:
1088: return m_isFolder;
1089: }
1090:
1091: /**
1092: * Returns <code>true</code> if the resource is marked as internal.<p>
1093: *
1094: * An internal resource can be read by the OpenCms API, but it can not be delivered
1095: * by a direct request from an outside user.<p>
1096: *
1097: * For example if the resource <code>/internal.xml</code>
1098: * has been set as marked as internal, this resource can not be requested by an HTTP request,
1099: * so when a user enters <code>http:/www.myserver.com/opencms/opencms/internal.xml</code> in the browser
1100: * this will generate a {@link CmsVfsResourceNotFoundException}.<p>
1101: *
1102: * This state is stored as bit 1 in the resource flags.<p>
1103: *
1104: * @return <code>true</code> if the resource is internal
1105: */
1106: public boolean isInternal() {
1107:
1108: return ((m_flags & FLAG_INTERNAL) > 0);
1109: }
1110:
1111: /**
1112: * Returns <code>true</code> if the resource has to be labeled with a special icon in the explorer view.<p>
1113: *
1114: * This state is stored as bit 2 in the resource flags.<p>
1115: *
1116: * @return <code>true</code> if the resource has to be labeled in the explorer view
1117: */
1118: public boolean isLabeled() {
1119:
1120: return ((m_flags & CmsResource.FLAG_LABELED) > 0);
1121: }
1122:
1123: /**
1124: * Returns <code>true</code> if this resource is released at the given time according to the
1125: * information stored in {@link #getDateReleased()}.<p>
1126: *
1127: * @param time the time to check the release date against
1128: *
1129: * @return <code>true</code> if this resource is released at the given time
1130: *
1131: * @see #isExpired(long)
1132: * @see #isReleasedAndNotExpired(long)
1133: * @see #DATE_RELEASED_EXPIRED_IGNORE
1134: * @see CmsResource#getDateReleased()
1135: * @see CmsRequestContext#getRequestTime()
1136: */
1137: public boolean isReleased(long time) {
1138:
1139: return (time > m_dateReleased)
1140: || (time == DATE_RELEASED_EXPIRED_IGNORE);
1141: }
1142:
1143: /**
1144: * Returns <code>true</code> if this resource is valid at the given time according to the
1145: * information stored in {@link #getDateReleased()} and {@link #getDateExpired()}.<p>
1146: *
1147: * A resource is valid if it is released and not yet expired.<p>
1148: *
1149: * @param time the time to check the release and expiration date against
1150: *
1151: * @return <code>true</code> if this resource is valid at the given time
1152: *
1153: * @see #isExpired(long)
1154: * @see #isReleased(long)
1155: * @see #DATE_RELEASED_EXPIRED_IGNORE
1156: * @see CmsResource#getDateReleased()
1157: * @see CmsRequestContext#getRequestTime()
1158: */
1159: public boolean isReleasedAndNotExpired(long time) {
1160:
1161: return ((time < m_dateExpired) && (time > m_dateReleased))
1162: || (time == DATE_RELEASED_EXPIRED_IGNORE);
1163: }
1164:
1165: /**
1166: * Returns <code>true</code> if this resource was touched.<p>
1167: *
1168: * @return <code>true</code> if this resource was touched
1169: */
1170: public boolean isTouched() {
1171:
1172: return m_isTouched;
1173: }
1174:
1175: /**
1176: * Sets the expiration date this resource.<p>
1177: *
1178: * @param time the expiration date to set
1179: */
1180: public void setDateExpired(long time) {
1181:
1182: m_dateExpired = time;
1183: }
1184:
1185: /**
1186: * Sets the date of the last modification of this resource.<p>
1187: *
1188: * @param time the last modification date to set
1189: */
1190: public void setDateLastModified(long time) {
1191:
1192: m_isTouched = true;
1193: m_dateLastModified = time;
1194: }
1195:
1196: /**
1197: * Sets the release date this resource.<p>
1198: *
1199: * @param time the release date to set
1200: */
1201: public void setDateReleased(long time) {
1202:
1203: m_dateReleased = time;
1204: }
1205:
1206: /**
1207: * Sets the flags of this resource.<p>
1208: *
1209: * The resource flags integer is used as bit set that contains special information about the resource.
1210: * The following methods internally use the resource flags:<ul>
1211: * <li>{@link #isInternal()}
1212: * <li>{@link #isLabeled()}
1213: * </ul>
1214: *
1215: * @param flags the flags value to set
1216: */
1217: public void setFlags(int flags) {
1218:
1219: m_flags = flags;
1220: }
1221:
1222: /**
1223: * Sets the state of this resource.<p>
1224: *
1225: * @param state the state to set
1226: */
1227: public void setState(CmsResourceState state) {
1228:
1229: m_state = state;
1230: }
1231:
1232: /**
1233: * Sets the type of this resource.<p>
1234: *
1235: * @param type the type to set
1236: */
1237: public void setType(int type) {
1238:
1239: m_typeId = type;
1240: }
1241:
1242: /**
1243: * Sets the user id of the user who changed this resource.<p>
1244: *
1245: * @param resourceLastModifiedByUserId the user id of the user who changed the resource
1246: */
1247: public void setUserLastModified(CmsUUID resourceLastModifiedByUserId) {
1248:
1249: m_userLastModified = resourceLastModifiedByUserId;
1250: }
1251:
1252: /**
1253: * @see java.lang.Object#toString()
1254: */
1255: public String toString() {
1256:
1257: StringBuffer result = new StringBuffer();
1258:
1259: result.append("[");
1260: result.append(this .getClass().getName());
1261: result.append(", path: ");
1262: result.append(m_rootPath);
1263: result.append(", structure id ");
1264: result.append(m_structureId);
1265: result.append(", resource id: ");
1266: result.append(m_resourceId);
1267: result.append(", type id: ");
1268: result.append(m_typeId);
1269: result.append(", folder: ");
1270: result.append(m_isFolder);
1271: result.append(", flags: ");
1272: result.append(m_flags);
1273: result.append(", project: ");
1274: result.append(m_projectLastModified);
1275: result.append(", state: ");
1276: result.append(m_state);
1277: result.append(", date created: ");
1278: result.append(new java.util.Date(m_dateCreated));
1279: result.append(", user created: ");
1280: result.append(m_userCreated);
1281: result.append(", date lastmodified: ");
1282: result.append(new java.util.Date(m_dateLastModified));
1283: result.append(", user lastmodified: ");
1284: result.append(m_userLastModified);
1285: result.append(", date released: ");
1286: result.append(new java.util.Date(m_dateReleased));
1287: result.append(", date expired: ");
1288: result.append(new java.util.Date(m_dateExpired));
1289: result.append(", date content: ");
1290: result.append(new java.util.Date(m_dateContent));
1291: result.append(", size: ");
1292: result.append(m_length);
1293: result.append(", sibling count: ");
1294: result.append(m_siblingCount);
1295: result.append(", version: ");
1296: result.append(m_version);
1297: result.append("]");
1298:
1299: return result.toString();
1300: }
1301: }
|