package com.ejie.x38.webdav.locking;
import java.util.List;
import java.util.UUID;
/**
* a helper class for ResourceLocks, represents the Locks
*
* @author re
*
*/
public class DataBaseLockedObject extends LockedObject<DataBaseResourceLocks> {
// private IResourceLocks _resourceLocks;
// private String _path;
// private 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;protected
/**
* 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;
// protected String[] _owner = null;
/**
* children of that lock
*/
protected DataBaseLockedObject[] _children = null;
//
protected DataBaseLockedObject _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 resLocks
* the resourceLocks where locks are stored
* @param path
* the path to the locked object
* @param temporary
* indicates if the LockedObject should be temporary or not
*/
public DataBaseLockedObject(DataBaseResourceLocks resLocks, String path, boolean temporary) {
_path = path;
_id = UUID.randomUUID().toString();
_resourceLocks = resLocks;
}
public DataBaseLockedObject(List<DataBaseModel> listdataBaseModel){
this(listdataBaseModel.get(0));
}
public DataBaseLockedObject(DataBaseModel listdataBaseModel){
this._id = listdataBaseModel.getId();
this._path = listdataBaseModel.getPath();
this._exclusive = listdataBaseModel.getExclusiveLock();
this._expiresAt = listdataBaseModel.getExpiresAt();
this._lockDepth = listdataBaseModel.getLockDepth();
this._owner = new String[]{listdataBaseModel.getOwner()};
this._type = listdataBaseModel.getLockType();
}
/**
* 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 (int i = 0; i < size; i++) {
if (_owner[i].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
String[] newLockedObjectOwner = new String[size - 1];
for (int j = 0; j < (size - 1); 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(DataBaseLockedObject newChild) {
if (_children == null) {
_children = new DataBaseLockedObject[0];
}
int size = _children.length;
DataBaseLockedObject[] newChildren = new DataBaseLockedObject[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)) {
// DataBaseLockedObject[] newChildren = new DataBaseLockedObject[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() {
}
/**
* 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;
}
public DataBaseModel getDataBaseModel(){
DataBaseModel dataBaseModel = new DataBaseModel();
dataBaseModel.setId(this._id);
dataBaseModel.setPath(this._path);
dataBaseModel.setExclusiveLock(this._exclusive);
dataBaseModel.setLockDepth(this._lockDepth);
dataBaseModel.setExpiresAt(this._expiresAt);
dataBaseModel.setLockType(this._type);
if(this._owner!= null && this._owner.length>0){
dataBaseModel.setOwner(this._owner[0]);
}
if ("read".equals(this._type)){
dataBaseModel.setTempLock(Boolean.TRUE);
}else{
dataBaseModel.setTempLock(Boolean.FALSE);
}
return dataBaseModel;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof DataBaseLockedObject){
DataBaseLockedObject dblo = (DataBaseLockedObject)obj;
if (this._id.equals(dblo.getID())
&& this._path.equals(dblo.getPath())){
return true;
}
}
return false;
}
}