001: package com.ibm.webdav;
002:
003: /*
004: * (C) Copyright IBM Corp. 2000 All rights reserved.
005: *
006: * The program is provided "AS IS" without any warranty express or
007: * implied, including the warranty of non-infringement and the implied
008: * warranties of merchantibility and fitness for a particular purpose.
009: * IBM will not be liable for any damages suffered by you as a result
010: * of using the Program. In no event will IBM be liable for any
011: * special, indirect or consequential damages or lost profits even if
012: * IBM has been advised of the possibility of their occurrence. IBM
013: * will not be liable for any third party claims against you.
014: *
015: * Portions Copyright (C) Simulacra Media Ltd, 2004.
016: */
017:
018: import java.util.*;
019: import java.util.logging.*;
020:
021: import javax.xml.parsers.*;
022:
023: import org.w3c.dom.*;
024:
025: /**
026: * ActiveLock contains information about locks on this resourece. The
027: * information can be used to provide details when obtaining locks, or for
028: * holding results from lock queries. It combines the activelock DAV element
029: * with the principal, and the lock expiration date.
030: *
031: * @author Jim Amsden <jamsden@us.ibm.com>
032: */
033: public class ActiveLock extends Object {
034:
035: /**
036: * Only one exclusive lock can be granted at any time on a resource.
037: *
038: */
039: public static final String exclusive = "exclusive";
040:
041: /**
042: * A resource may have many concurrent shared locks which indicate an
043: * intention to change the resource in some way. It is the responsibilty of
044: * the shared lock owners to coordinate their updates appropriately through
045: * other means.
046: */
047: public static final String shared = "shared";
048:
049: /**
050: * Write locks allow a resource to be updated or deleted.
051: *
052: */
053: public static final String writeLock = "write";
054:
055: //---------------------------------------------------------------------------------
056:
057: // headers
058: private String timeout = "Infinite";
059:
060: private String depth = Collection.deep;
061:
062: // from the request entity
063: private String scope = ActiveLock.exclusive;
064:
065: private String lockType = ActiveLock.writeLock;
066:
067: private Element owner = null;
068:
069: private String sOwner = null;
070:
071: // from the response entity
072: private String lockToken = null;
073:
074: // useful extensions:
075: private Date expiration = null; // when the lock will expire
076:
077: private String principal = null; // the userid of the lock owner
078:
079: /**
080: * Logger for this class
081: */
082: private static final Logger m_logger = Logger
083: .getLogger(ActiveLock.class.getName());
084:
085: /**
086: * The default constructor.
087: *
088: */
089: public ActiveLock() {
090: }
091:
092: /**
093: * Convert an activelock Element into a ActiveLock instance for convenient
094: * access to the lock information. This method uses two IBM extensions to
095: * the WebDAV activelock element, one for the principal, and onother for the
096: * lock expiration time.
097: *
098: * @param an
099: * activelock Element containing information about the lock
100: * @exception com.ibm.webdav.WebDAVException
101: */
102: public ActiveLock(Element activeLock) throws WebDAVException {
103:
104: Element lockScope = (Element) activeLock
105: .getElementsByTagNameNS("DAV:", "lockscope").item(0);
106: setScope(((Element) lockScope.getFirstChild()).getLocalName());
107:
108: Element lockType = (Element) activeLock.getElementsByTagNameNS(
109: "DAV:", "locktype").item(0);
110: setLockType(((Element) lockType.getFirstChild()).getLocalName());
111:
112: Element depth = (Element) activeLock.getElementsByTagNameNS(
113: "DAV:", "depth").item(0);
114: setDepth(((Text) depth.getFirstChild()).getData());
115:
116: Element owner = (Element) activeLock.getElementsByTagNameNS(
117: "DAV:", "owner").item(0);
118: if (owner != null) {
119: setOwner(owner);
120: }
121: Element timeout = (Element) activeLock.getElementsByTagNameNS(
122: "DAV:", "timeout").item(0);
123: if (timeout != null) {
124: this .timeout = ((Text) timeout.getFirstChild()).getData();
125: }
126:
127: // TODO: There may be many locktokens all identifying the same lock
128: Element lockToken = (Element) activeLock
129: .getElementsByTagNameNS("DAV:", "locktoken").item(0);
130: if (lockToken != null) {
131: Element href = (Element) lockToken.getElementsByTagNameNS(
132: "DAV:", "href").item(0);
133: if (href != null) {
134: this .lockToken = ((Text) href.getFirstChild())
135: .getData();
136: }
137: }
138:
139: // IBM extensions:
140:
141: Element principal = (Element) activeLock
142: .getElementsByTagNameNS("DAV:", "principal").item(0);
143: if (principal != null) {
144: setPrincipal(((Text) principal.getFirstChild()).getData());
145: }
146:
147: // Element principal =
148: // (Element)activeLock.getElementsByTagName("principal").item(0);
149: // if (principal != null) {
150: // setPrincipal(((Text) principal.getFirstChild()).getData());
151: // }
152:
153: // Element expiration =
154: // (Element)activeLock.getElementsByTagName("expiration").item(0);
155: // if (expiration != null) {
156: // Date d = null;
157: // try {
158: // DateFormat df = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
159: // d = df.parse(((Text) expiration.getFirstChild()).getData());
160: // } catch (ParseException exc) {
161: // System.err.print("Unable to parse lock expiration date: " + exc);
162: // }
163: // setExpiration(d);
164: // }
165: }
166:
167: /**
168: * Translate this ActiveLock instance into an activelock XML element. The
169: * activelock element will include two IBM extensions, one for the principal
170: * owning the lock (the authorization id), and another containing the
171: * expiration date for the lock.
172: *
173: * @return the DOM representation of an activelock XML element
174: */
175: public Element asXML() {
176: String sPrefix = "D";
177: // the document is only used create elements
178: Document document = null;
179:
180: try {
181: document = DocumentBuilderFactory.newInstance()
182: .newDocumentBuilder().newDocument();
183: } catch (Exception e) {
184: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
185: }
186: //document.setVersion(Resource.XMLVersion);
187: //document.setEncoding(Resource.defaultXMLEncoding);
188:
189: Element activelock = document.createElementNS("DAV:",
190: "D:activelock");
191:
192: activelock.setAttribute("xmlns:D", "DAV:");
193:
194: Element lockscope = document.createElementNS("DAV:",
195: "D:lockscope");
196:
197: Element scopeEl = document.createElementNS("DAV:", "D:"
198: + this .scope);
199:
200: lockscope.appendChild(scopeEl);
201: activelock.appendChild(lockscope);
202:
203: Element locktype = document.createElementNS("DAV:",
204: "D:locktype");
205:
206: Element locktypeEl = document.createElementNS("DAV:", "D:"
207: + this .lockType);
208:
209: locktype.appendChild(locktypeEl);
210: activelock.appendChild(locktype);
211:
212: Element depth = document.createElementNS("DAV:", "D:depth");
213:
214: depth.appendChild(document.createTextNode(this .depth));
215: activelock.appendChild(depth);
216:
217: if (this .owner != null) {
218: if (owner.getPrefix() == null
219: || owner.getPrefix().equals("D") == false) {
220:
221: Element ownerEl = document.createElementNS("DAV:",
222: "D:owner");
223: Element hrefEl = document.createElementNS("DAV:",
224: "D:href");
225:
226: String sOwnerVal = owner.getChildNodes().item(0)
227: .getChildNodes().item(0).getNodeValue();
228:
229: Text txtOwnerVal = document.createTextNode(sOwnerVal);
230:
231: hrefEl.appendChild(txtOwnerVal);
232:
233: ownerEl.appendChild(hrefEl);
234: activelock.appendChild(ownerEl);
235: owner = ownerEl;
236: } else {
237: activelock
238: .appendChild(document.importNode(owner, true));
239: }
240: } else if (sOwner != null) {
241: Element ownerEl = document.createElementNS("DAV:",
242: "D:owner");
243: Element hrefEl = document.createElementNS("DAV:", "D:href");
244:
245: hrefEl.appendChild(document.createTextNode(sOwner));
246: ownerEl.appendChild(hrefEl);
247: activelock.appendChild(ownerEl);
248: }
249:
250: Element timeout = document.createElementNS("DAV:", "D:timeout");
251:
252: timeout.appendChild(document.createTextNode(this .timeout));
253: activelock.appendChild(timeout);
254:
255: if (this .lockToken != null) {
256: Element locktoken = document.createElementNS("DAV:",
257: "D:locktoken");
258:
259: Element href = document.createElementNS("DAV:", "D:href");
260:
261: href.appendChild(document.createTextNode(this .lockToken));
262: locktoken.appendChild(href);
263: activelock.appendChild(locktoken);
264: }
265:
266: if (getPrincipal() != null) {
267: Element principal = (Element) document.createElementNS(
268: "DAV:", "D:principal");
269: principal.appendChild(document
270: .createTextNode(getPrincipal()));
271: activelock.appendChild(principal);
272: }
273:
274: // if (getPrincipal() != null) {
275: // Element principal = (Element) document.createElement("principal");
276: // principal.appendChild(document.createTextNode(getPrincipal()));
277: // activelock.appendChild(principal);
278: // }
279:
280: // if (getExpiration() != null) {
281: // Element expiration = (Element) document.createElement("expiration");
282: // expiration.appendChild(document.createTextNode(getExpiration().toString()));
283: // activelock.appendChild(expiration);
284: // }
285:
286: return activelock;
287: }
288:
289: /**
290: * Get the depth of the lock.
291: * <ul>
292: * <li>shallow: only this resource is locked or will be locked</li>
293: * <li>deep: this resource and recursively, all its internal members are
294: * locked</li>
295: * </ul>
296: *
297: * @return shallow or deep
298: */
299: public String getDepth() {
300: return depth;
301: }
302:
303: /**
304: * Get the date and time when the lock will timeout. Null means it will
305: * never timeout. This is an IBM EXTENSION.
306: *
307: * @return the expiration date for the lock
308: */
309: public Date getExpiration() {
310: return expiration;
311: }
312:
313: /**
314: * Get the lock token. A lock token represents the lock, and is used to
315: * unlock the resource or for any access that might change the resource
316: * state. There may be many (shared) locks on a resource, each with its own
317: * lock token. Each lock will have its own ActiveLock instance describing
318: * the lock and providing access to the lock token. See the lockdiscovery
319: * DAV property.
320: *
321: * @return the lock token identifying a lock on this resource.
322: */
323: public String getLockToken() {
324: return lockToken;
325: }
326:
327: /**
328: * Get the type of the lock.
329: *
330: * @return write (other lock types may be supported in the future)
331: */
332: public String getLockType() {
333: return lockType;
334: }
335:
336: /**
337: * Get the owner of the lock. The method provides information about the
338: * principal taking out the lock, but not necessarily the principal's
339: * authorization ID.
340: *
341: * @return any information that might identify the principal taking out the
342: * lock.
343: */
344: public Element getOwner() {
345: return owner;
346: }
347:
348: /**
349: * Get the user authorization id of the owner of the lock. This is an IBM
350: * EXTENSION to the WebDAV activelock.
351: *
352: * @return the principal owning this lock as given in the Authorization
353: * context on lock
354: */
355: public String getPrincipal() {
356: return principal;
357: }
358:
359: /**
360: * Get the scope of the lock.
361: *
362: * @return exclusive or shared
363: */
364: public String getScope() {
365: return scope;
366: }
367:
368: /**
369: * Get the lock timeout.
370: *
371: * @return the lock timeout as either Second-n or "Infinite" for no timeout.
372: */
373: public String getTimeout() {
374: return timeout;
375: }
376:
377: /**
378: * Get the time remaining before the lock times out
379: *
380: * @return the number of seconds that must elapse before the lock times out.
381: * 0 means the lock has timed out.
382: */
383: public long getTimeRemaining() {
384: long now = new Date().getTime();
385: long t = expiration.getTime() - now;
386: if (t < 0) {
387: t = 0;
388: }
389: return t;
390: }
391:
392: /**
393: * Set the depth of the lock.
394: * <ul>
395: * <li>shallow: only this resource is locked or will be locked</li>
396: * <li>deep: this resource and recursively, all its internal members are
397: * locked</li>
398: * </ul>
399: *
400: * @param depth
401: * shallow or deep
402: * @exception com.ibm.webdav.ClientException
403: * thrown if the depth is incorrect
404: */
405: public void setDepth(String depth) throws ClientException {
406: if (!(depth.equals(Collection.shallow) || depth
407: .equals(Collection.deep))) {
408: throw new ClientException(400, "invalid lock depth");
409: }
410: this .depth = depth;
411: }
412:
413: /**
414: * Set the date and time when the lock will timeout. Null means it will
415: * never timeout. This is an IBM EXTENSION.
416: */
417: public void setExpiration(Date value) {
418: expiration = value;
419: }
420:
421: /**
422: * Set the lock token.
423: *
424: * @param lockToken
425: * the lock token corresponding to a lock on a resource.
426: */
427: public void setLockToken(String lockToken) {
428: this .lockToken = lockToken;
429: }
430:
431: /**
432: * Set the type of the lock.
433: *
434: * @param lockType
435: * write (other lock types may be supported in the future)
436: * @exception com.ibm.webdav.ClientException
437: * thrown if the lockType is incorrect. Currently, only write
438: * locks are supported.
439: */
440: public void setLockType(String lockType) throws ClientException {
441: if (!(lockType.equals(writeLock))) {
442: throw new ClientException(400, "invalid lock type: "
443: + lockType);
444: }
445: this .lockType = lockType;
446: }
447:
448: /**
449: * Set the owner of the lock. The method sets the information about the
450: * principal taking out the lock. This is not necessarily the authorization
451: * id of the principal owning the lock, and therefore cannot be relied upon
452: * for authentication.
453: *
454: * @param owner
455: * any information that might identify the principal taking out
456: * the lock.
457: */
458: public void setOwner(Element owner) {
459: this .owner = owner;
460: }
461:
462: public void setOwner(String sOwner) {
463: this .sOwner = sOwner;
464: }
465:
466: /**
467: * Set the user authorization id of the owner of the lock. This is and IBM
468: * EXTENSION.
469: */
470: public void setPrincipal(String value) {
471: principal = value;
472: }
473:
474: /**
475: * Set the scope of the lock.
476: *
477: * @param scope
478: * exclusive or shared
479: * @exception com.ibm.webdav.ClientException
480: * thrown if the scope is invalid
481: */
482: public void setScope(String scope) throws ClientException {
483: if (!(scope.equals(exclusive) || scope.equals(shared))) {
484: throw new ClientException(400, "invalid lock scope: "
485: + scope);
486: }
487: this .scope = scope;
488: }
489:
490: /**
491: * Set the lock timeout.
492: *
493: * @param timeout
494: * the lock timeout in seconds. -1 means infinite timeout.
495: */
496: public void setTimeout(int timeout) {
497: if (timeout < 0) {
498: setTimeout("Infinite");
499: } else {
500: setTimeout("Second-" + new Integer(timeout).toString());
501: }
502: }
503:
504: /**
505: * Set the lock timeout.
506: *
507: * @param timeout
508: * the lock timeout as either Second-n or "Infinite" for no
509: * timeout. Any other syntax is ignored.
510: */
511: public void setTimeout(String timeout) {
512: this .timeout = timeout;
513: if (timeout.equals("Infinite")) {
514: expiration = null;
515: } else {
516: if (timeout.startsWith("Second-")) {
517: long t = new Long(timeout.substring(7)).longValue();
518: expiration = new Date(new Date().getTime() + t * 1000);
519: }
520: }
521: }
522:
523: /**
524: * Convert this ActiveLock to a String representation (an activelock XML
525: * element).
526: *
527: * @return a String representation of the ActiveLock as an activelock
528: * element
529: *
530: */
531: public String toString() {
532: /*
533: * ByteArrayOutputStream os = new ByteArrayOutputStream(); PrintWriter
534: * pout = new PrintWriter(os); Element activelock = (Element) asXML();
535: * try { activelock.print(pout); } catch (Exception exc) { }
536: * pout.close(); return os.toString();
537: */
538: return XMLUtility.printNode(asXML());
539: }
540: }
|