All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nl.info.webdav.locking.LockedObject Maven / Gradle / Ivy

There is a newer version: 1.2.73
Show newest version
package nl.info.webdav.locking;

import java.util.UUID;

/**
 * a helper class for ResourceLocks, represents the Locks
 * 
 * @author re
 * 
 */
public class LockedObject {
    private final ResourceLocks _resourceLocks;
    private final String _path;
    private final String _id;

    /**
     * Describing the depth of a locked collection. If the locked resource is
     * not a collection, depth is 0 / doesn't matter.
     */
    protected int _lockDepth;

    /**
     * Describing the timeout of a locked object (ms)
     */
    protected long _expiresAt;

    /**
     * owner of the lock. shared locks can have multiple owners. is null if no
     * owner is present
     */
    protected String[] _owner = null;

    /**
     * children of that lock
     */
    protected LockedObject[] _children = null;

    protected LockedObject _parent = null;

    /**
     * weather the lock is exclusive or not. if owner=null the exclusive value
     * doesn't matter
     */
    protected boolean _exclusive = false;

    /**
     * weather the lock is a write or read lock
     */
    protected String _type = null;

    /**
     * @param resourceLocks
     *                      the resourceLocks where locks are stored
     * @param path
     *                      the path to the locked object
     * @param isTemporary
     *                      indicates if the LockedObject should be temporary or not
     */
    public LockedObject(ResourceLocks resourceLocks, String path, boolean isTemporary) {
        _path = path;
        _id = UUID.randomUUID().toString();
        _resourceLocks = resourceLocks;

        if (!isTemporary) {
            _resourceLocks._locks.put(path, this);
            _resourceLocks._locksByID.put(_id, this);
        } else {
            _resourceLocks._tempLocks.put(path, this);
            _resourceLocks._tempLocksByID.put(_id, this);
        }
        _resourceLocks._cleanupCounter++;
    }

    /**
     * adds a new owner to a lock
     * 
     * @param owner
     *              string that represents the owner
     * @return true if the owner was added, false otherwise
     */
    public boolean addLockedObjectOwner(String owner) {
        if (_owner == null) {
            _owner = new String[1];
        } else {

            int size = _owner.length;
            String[] newLockObjectOwner = new String[size + 1];

            // check if the owner is already here (that should actually not
            // happen)
            for (String s : _owner) {
                if (s.equals(owner)) {
                    return false;
                }
            }

            System.arraycopy(_owner, 0, newLockObjectOwner, 0, size);
            _owner = newLockObjectOwner;
        }

        _owner[_owner.length - 1] = owner;
        return true;
    }

    /**
     * tries to remove the owner from the lock
     * 
     * @param owner
     *              string that represents the owner
     */
    public void removeLockedObjectOwner(String owner) {
        try {
            if (_owner != null) {
                int size = _owner.length;
                for (int i = 0; i < size; i++) {
                    // check every owner if it is the requested one
                    if (_owner[i].equals(owner)) {
                        // remove the owner
                        size -= 1;
                        String[] newLockedObjectOwner = new String[size];
                        for (int j = 0; j < size; j++) {
                            if (j < i) {
                                newLockedObjectOwner[j] = _owner[j];
                            } else {
                                newLockedObjectOwner[j] = _owner[j + 1];
                            }
                        }
                        _owner = newLockedObjectOwner;

                    }
                }
                if (_owner.length == 0) {
                    _owner = null;
                }
            }
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("LockedObject.removeLockedObjectOwner()");
            System.out.println(e.toString());
        }
    }

    /**
     * adds a new child lock to this lock
     * 
     * @param newChild
     *                 new child
     */
    public void addChild(LockedObject newChild) {
        if (_children == null) {
            _children = new LockedObject[0];
        }
        int size = _children.length;
        LockedObject[] newChildren = new LockedObject[size + 1];
        System.arraycopy(_children, 0, newChildren, 0, size);
        newChildren[size] = newChild;
        _children = newChildren;
    }

    /**
     * deletes this Lock object. assumes that it has no children and no owners
     * (does not check this itself)
     * 
     */
    public void removeLockedObject() {
        if (this != _resourceLocks._root && !this.getPath().equals("/")) {

            int size = _parent._children.length;
            for (int i = 0; i < size; i++) {
                if (_parent._children[i].equals(this)) {
                    LockedObject[] newChildren = new LockedObject[size - 1];
                    for (int i2 = 0; i2 < (size - 1); i2++) {
                        if (i2 < i) {
                            newChildren[i2] = _parent._children[i2];
                        } else {
                            newChildren[i2] = _parent._children[i2 + 1];
                        }
                    }
                    if (newChildren.length != 0) {
                        _parent._children = newChildren;
                    } else {
                        _parent._children = null;
                    }
                    break;
                }
            }

            // removing from hashtable
            _resourceLocks._locksByID.remove(getID());
            _resourceLocks._locks.remove(getPath());

            // now the garbage collector has some work to do
        }
    }

    /**
     * deletes this Lock object. assumes that it has no children and no owners
     * (does not check this itself)
     * 
     */
    public void removeTempLockedObject() {
        if (this != _resourceLocks._tempRoot) {
            // removing from tree
            if (_parent != null && _parent._children != null) {
                int size = _parent._children.length;
                for (int i = 0; i < size; i++) {
                    if (_parent._children[i].equals(this)) {
                        LockedObject[] newChildren = new LockedObject[size - 1];
                        for (int i2 = 0; i2 < (size - 1); i2++) {
                            if (i2 < i) {
                                newChildren[i2] = _parent._children[i2];
                            } else {
                                newChildren[i2] = _parent._children[i2 + 1];
                            }
                        }
                        if (newChildren.length != 0) {
                            _parent._children = newChildren;
                        } else {
                            _parent._children = null;
                        }
                        break;
                    }
                }

                // removing from hashtable
                _resourceLocks._tempLocksByID.remove(getID());
                _resourceLocks._tempLocks.remove(getPath());

                // now the garbage collector has some work to do
            }
        }
    }

    /**
     * checks if a lock of the given exclusivity can be placed, only considering
     * children up to "depth"
     * 
     * @param exclusive
     *                  wheather the new lock should be exclusive
     * @param depth
     *                  the depth to which should be checked
     * @return true if the lock can be placed
     */
    public boolean checkLocks(boolean exclusive, int depth) {
        if (checkParents(exclusive) && checkChildren(exclusive, depth)) {
            return true;
        }
        return false;
    }

    /**
     * helper of checkLocks(). looks if the parents are locked
     * 
     * @param exclusive
     *                  wheather the new lock should be exclusive
     * @return true if no locks at the parent path are forbidding a new lock
     */
    private boolean checkParents(boolean exclusive) {
        if (_path.equals("/")) {
            return true;
        } else {
            if (_owner == null) {
                // no owner, checking parents
                return _parent != null && _parent.checkParents(exclusive);
            } else {
                // there already is a owner
                return !(_exclusive || exclusive) && _parent.checkParents(exclusive);
            }
        }
    }

    /**
     * helper of checkLocks(). looks if the children are locked
     * 
     * @param exclusive
     *                  wheather the new lock should be exclusive
     * @return true if no locks at the children paths are forbidding a new lock
     * @param depth
     *              depth
     */
    private boolean checkChildren(boolean exclusive, int depth) {
        if (_children == null) {
            // a file

            return _owner == null || !(_exclusive || exclusive);
        } else {
            // a folder

            if (_owner == null) {
                // no owner, checking children

                if (depth != 0) {
                    boolean canLock = true;
                    int limit = _children.length;
                    for (int i = 0; i < limit; i++) {
                        if (!_children[i].checkChildren(exclusive, depth - 1)) {
                            canLock = false;
                        }
                    }
                    return canLock;
                } else {
                    // depth == 0 -> we don't care for children
                    return true;
                }
            } else {
                // there already is a owner
                return !(_exclusive || exclusive);
            }
        }

    }

    /**
     * Sets a new timeout for the LockedObject
     * 
     * @param timeout
     */
    public void refreshTimeout(int timeout) {
        _expiresAt = System.currentTimeMillis() + (timeout * 1000);
    }

    /**
     * Gets the timeout for the LockedObject
     * 
     * @return timeout
     */
    public long getTimeoutMillis() {
        return (_expiresAt - System.currentTimeMillis());
    }

    /**
     * Return true if the lock has expired.
     * 
     * @return true if timeout has passed
     */
    public boolean hasExpired() {
        if (_expiresAt != 0) {
            return (System.currentTimeMillis() > _expiresAt);
        } else {
            return true;
        }
    }

    /**
     * Gets the LockID (locktoken) for the LockedObject
     * 
     * @return locktoken
     */
    public String getID() {
        return _id;
    }

    /**
     * Gets the owners for the LockedObject
     * 
     * @return owners
     */
    public String[] getOwner() {
        return _owner;
    }

    /**
     * Gets the path for the LockedObject
     * 
     * @return path
     */
    public String getPath() {
        return _path;
    }

    /**
     * Sets the exclusivity for the LockedObject
     * 
     * @param exclusive
     */
    public void setExclusive(boolean exclusive) {
        _exclusive = exclusive;
    }

    /**
     * Gets the exclusivity for the LockedObject
     * 
     * @return exclusivity
     */
    public boolean isExclusive() {
        return _exclusive;
    }

    /**
     * Gets the exclusivity for the LockedObject
     * 
     * @return exclusivity
     */
    public boolean isShared() {
        return !_exclusive;
    }

    /**
     * Gets the type of the lock
     * 
     * @return type
     */
    public String getType() {
        return _type;
    }

    /**
     * Gets the depth of the lock
     * 
     * @return depth
     */
    public int getLockDepth() {
        return _lockDepth;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy