001: /*
002: * Copyright (c) 2000, Jacob Smullyan.
003: *
004: * This is part of SkunkDAV, a WebDAV client. See http://skunkdav.sourceforge.net/
005: * for the latest version.
006: *
007: * SkunkDAV is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License as published
009: * by the Free Software Foundation; either version 2, or (at your option)
010: * any later version.
011: *
012: * SkunkDAV 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: * General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with SkunkDAV; see the file COPYING. If not, write to the Free
019: * Software Foundation, 59 Temple Place - Suite 330, Boston, MA
020: * 02111-1307, USA.
021: */
022:
023: package org.skunk.dav.client;
024:
025: import java.util.ArrayList;
026: import java.util.HashMap;
027: import java.util.Iterator;
028: import java.util.Map;
029: import java.util.TreeSet;
030: import org.skunk.trace.Debug;
031:
032: /**
033: * a wrapper around the results returned by a DAV propfind or other DAV method.
034: * It resembles a beanified ResultSet more than a File object; two DAVFile objects
035: * with the same host, port, and path may have quite different contents, depending
036: * on the sorts of queries that were used to generate it.
037: *
038: * @author Jacob Smullyan
039: */
040: public class DAVFile implements Comparable {
041: private ArrayList supportedLocks = null;
042: private HashMap customProperties = null;
043: private ArrayList availableProperties = null;
044: private String name;
045: private String etag;
046: private String creationDate;
047: private String lastModified;
048: private String href;
049: private String resourceType;
050: private String contentType;
051: private Long contentLength;
052: private String contentLanguage;
053: private ArrayList locks = null;
054: private TreeSet children = null;
055: private Integer status;
056: private String displayName;
057: private ArrayList links = null;
058: private String responseDescription;
059: private String host;
060: private int port;
061: private String protocol = DAVConstants.HTTP;
062:
063: public DAVFile(String path) {
064: this .name = path;
065: }
066:
067: public DAVFile(String host, int port, String filename) {
068: this .host = host;
069: this .port = port;
070: this .name = filename;
071: }
072:
073: public DAVFile(String protocol, String host, int port, String path) {
074: this .protocol = protocol;
075: this .host = host;
076: this .port = port;
077: this .name = path;
078: }
079:
080: public String getName() {
081: return name;
082: }
083:
084: public String getFullName() {
085: StringBuffer sb = new StringBuffer(host);
086: sb.append(":");
087: sb.append(port);
088: sb.append(name);
089: return sb.toString();
090: }
091:
092: public String getFullNameWithProtocol() {
093: return new StringBuffer(getProtocol()).append("://").append(
094: getFullName()).toString();
095: }
096:
097: public String getProtocol() {
098: return this .protocol;
099: }
100:
101: public void setProtocol(String protocol) {
102: this .protocol = protocol;
103: }
104:
105: public String getFileName() {
106: String shornName = (name.charAt(name.length() - 1) == '/') ? name
107: .substring(0, name.length() - 1)
108: : name;
109: return shornName.substring(shornName.lastIndexOf("/") + 1);
110: }
111:
112: public String getHost() {
113: return host;
114: }
115:
116: public void setHost(String host) {
117: this .host = host;
118: }
119:
120: public int getPort() {
121: return port;
122: }
123:
124: public void setPort(int port) {
125: this .port = port;
126: }
127:
128: public DAVConnection getDAVConnection() {
129: return DAVConnectionPool.getDAVConnection(host, port);
130: }
131:
132: public boolean isCollection() {
133: return (resourceType != null && resourceType
134: .equals(DAVConstants.COLLECTION_ELEM));
135: }
136:
137: public void addChild(DAVFile child) {
138: if (children == null)
139: children = new TreeSet();
140: children.add(child);
141: }
142:
143: public Iterator children() {
144: if (children == null)
145: children = new TreeSet();
146: return children.iterator();
147: }
148:
149: public int getChildCount() {
150: return (children == null) ? 0 : children.size();
151: }
152:
153: public int getChildCollectionCount() {
154: if (children == null)
155: return 0;
156: Iterator kids = children.iterator();
157: int cnt = 0;
158: while (kids.hasNext()) {
159: DAVFile kid = (DAVFile) kids.next();
160: if (kid.isCollection())
161: cnt++;
162: }
163: return cnt;
164: }
165:
166: public DAVFile getChildAt(int index) {
167: if (children == null)
168: return null;
169: Iterator kids = children();
170: for (int i = 0; kids.hasNext(); i++) {
171: Object o = kids.next();
172: if (i == index)
173: return (DAVFile) o;
174: }
175: return null;
176: }
177:
178: public DAVFile getChildNamed(String path) {
179: if (path == null || children == null)
180: return null;
181: for (Iterator kids = children(); kids.hasNext();) {
182: DAVFile kidFile = (DAVFile) kids.next();
183: if (path.equals(kidFile.getName()))
184: return kidFile;
185: }
186: return null;
187: }
188:
189: public String getResourceType() {
190: return resourceType;
191: }
192:
193: public void setResourceType(String resourceType) {
194: this .resourceType = resourceType;
195: //adjust name to reflect whether or not it is a collection
196: if (isCollection() && !getName().endsWith("/"))
197: name += "/";
198: }
199:
200: public boolean isLocked() {
201: return (locks != null && (!locks.isEmpty()));
202: }
203:
204: public boolean isExclusiveLocked() {
205: // I enforce that if a lock is exclusive, there can be only one of
206: // them.
207: return (isLocked() && locks.size() == 1);
208: }
209:
210: public String getExclusiveLockToken() {
211: if (isExclusiveLocked())
212: return getExclusiveLock().getLockToken();
213: return null;
214: }
215:
216: public Lock[] getLocks() {
217: return getLockArray(locks);
218: }
219:
220: public Lock getExclusiveLock() {
221: if (isLocked() && locks.size() == 1) {
222: Lock soleLock = (Lock) locks.get(0);
223: if (soleLock.getLockScope().equals(LockScope.EXCLUSIVE))
224: return soleLock;
225: }
226: return null;
227: }
228:
229: public Lock getLock(String owner) {
230: if (owner == null || !isLocked())
231: return null;
232: if (isExclusiveLocked())
233: return getExclusiveLock();
234: //must be a shared lock
235:
236: // N.B. there is a bug here; for some reason,
237: // the code below FAILS for shared locks, while
238: // the loop below works. Seem impossible to you?
239: // Does to me, too.
240: // for (Iterator it=locks.iterator();it.hasNext();)
241: // {
242: // Lock nextLock=(Lock)it.next();
243: // if (owner.equals(nextLock.getOwner()))
244: // return nextLock;
245: // }
246:
247: int numLocks = locks.size();
248: for (int i = 0; i < numLocks; i++) {
249: Lock lk = (Lock) locks.get(i);
250: if (owner.equals(lk.getOwner()))
251: return lk;
252: }
253:
254: return null;
255: }
256:
257: public void setExclusiveLock(Lock lock) {
258: //verify that the lock argument is exclusive
259: if (lock == null
260: || (!lock.getLockScope().equals(LockScope.EXCLUSIVE)))
261: throw new IllegalArgumentException(
262: "lock argument to setExclusiveLock() must be an exclusive lock");
263: addLock(lock);
264: }
265:
266: public void addLock(Lock lock) {
267: if (locks == null)
268: locks = new ArrayList();
269: if (lock == null) {
270: Debug.trace(this , Debug.DP2,
271: " ** ignoring null argument to addLock()");
272: return;
273: }
274: if (lock.getLockScope().equals(LockScope.EXCLUSIVE)
275: && locks.size() > 0) {
276: Debug
277: .trace(
278: this ,
279: Debug.DP3,
280: "in setExclusiveLock() -- other locks {0} on resource exist, are being destroyed!!",
281: locks);
282: locks.clear();
283: }
284: locks.add(lock);
285: }
286:
287: public void removeLock(Lock lock) {
288: if (locks != null && locks.contains(lock))
289: locks.remove(locks.indexOf(lock));
290: }
291:
292: public String getLastModified() {
293: return lastModified;
294: }
295:
296: public void setLastModified(String lastModified) {
297: this .lastModified = lastModified;
298: }
299:
300: public String getCreationDate() {
301: return creationDate;
302: }
303:
304: public void setCreationDate(String creationDate) {
305: this .creationDate = creationDate;
306: }
307:
308: public String getExclusiveLockOwner() {
309: return (isExclusiveLocked()) ? getExclusiveLock().getOwner()
310: : null;
311: }
312:
313: public String getEtag() {
314: return etag;
315: }
316:
317: public void setEtag(String etag) {
318: this .etag = etag;
319: }
320:
321: public Long getContentLength() {
322: return contentLength;
323: }
324:
325: public void setContentLength(Long contentLength) {
326: this .contentLength = contentLength;
327: }
328:
329: public String getCustomProperty(DAVProperty property) {
330: Debug.trace(this , Debug.DP3,
331: "getting custom property {0} from map {1}",
332: new Object[] { property, customProperties });
333: if (customProperties == null)
334: return null;
335: Object o = customProperties.get(property);
336: return (o == null) ? null : o.toString();
337: }
338:
339: public void setCustomProperty(DAVProperty property,
340: String propertyValue) {
341: if (customProperties == null)
342: customProperties = new HashMap();
343: customProperties.put(property, propertyValue);
344: }
345:
346: public Map getCustomProperties() {
347: return customProperties;
348: }
349:
350: private Lock[] getLockArray(ArrayList lockList) {
351: if (lockList == null)
352: return null;
353: Lock[] lockArray = new Lock[lockList.size()];
354: for (int i = 0; i < lockArray.length; i++) {
355: lockArray[i] = (Lock) lockList.get(i);
356: }
357: return lockArray;
358: }
359:
360: public Lock[] getSupportedLocks() {
361: return getLockArray(supportedLocks);
362: }
363:
364: public void addSupportedLock(Lock shlock) {
365: if (supportedLocks == null)
366: supportedLocks = new ArrayList();
367: supportedLocks.add(shlock);
368: }
369:
370: /**
371: * N.B. this only has meaning after a propname query. An allprop or prop
372: * will not populate this structure and this method will then return null
373: */
374: public DAVProperty[] getAvailableProperties() {
375: if (availableProperties == null)
376: return null;
377: //I'm not synchronizing this, because I assume that once the available properties are
378: //set, the results won't be touched.
379: DAVProperty[] props = new DAVProperty[availableProperties
380: .size()];
381: for (int i = 0; i < props.length; i++) {
382: props[i] = (DAVProperty) availableProperties.get(i);
383: }
384: return props;
385: }
386:
387: public void addAvailableProperty(DAVProperty property) {
388: if (availableProperties == null)
389: availableProperties = new ArrayList();
390: availableProperties.add(property);
391: }
392:
393: public Integer getStatus() {
394: return status;
395: }
396:
397: public void setStatus(Integer status) {
398: this .status = status;
399: }
400:
401: public String getDisplayName() {
402: return displayName;
403: }
404:
405: public void setDisplayName(String displayName) {
406: this .displayName = displayName;
407: }
408:
409: public String getContentLanguage() {
410: return contentLanguage;
411: }
412:
413: public void setContentLanguage(String contentLanguage) {
414: this .contentLanguage = contentLanguage;
415: }
416:
417: public String getContentType() {
418: return contentType;
419: }
420:
421: public void setContentType(String contentType) {
422: this .contentType = contentType;
423: }
424:
425: public Link[] getLinks() {
426: if (links != null)
427: return (Link[]) links.toArray();
428: else
429: return null;
430: }
431:
432: public void addLink(Link l) {
433: if (links == null)
434: links = new ArrayList();
435: links.add(l);
436: }
437:
438: public String getResponseDescription() {
439: return this .responseDescription;
440: }
441:
442: public void setResponseDescription(String responseDescription) {
443: this .responseDescription = responseDescription;
444: }
445:
446: private static String flush(String s, int len) {
447: StringBuffer sb = new StringBuffer(len);
448: sb.append(s);
449: for (int i = 0; i < len - s.length(); i++)
450: sb.append(' ');
451: return sb.toString();
452: }
453:
454: private static StringBuffer flush(String s, int len, StringBuffer sb) {
455: int slen = s.length();
456: for (int i = 0; i < len - slen; i++)
457: sb.append(' ');
458: return sb;
459: }
460:
461: private static void display(String prompt, Object value,
462: StringBuffer buffer) {
463: if (value != null) {
464: buffer.append(prompt);
465: flush(":", 25 - prompt.length(), buffer).append(
466: value.toString()).append("\n");
467: }
468: }
469:
470: public String toVerboseString() {
471: StringBuffer sb = new StringBuffer();
472: display("host", getHost(), sb);
473: display("port", new Integer(getPort()), sb);
474: display("resource name", getName(), sb);
475: display("creation date", creationDate, sb);
476: display("last modified", lastModified, sb);
477: display("content type", contentType, sb);
478: display("content length", contentLength, sb);
479: display("content language", contentLanguage, sb);
480: display("display name", displayName, sb);
481: display("status", getStatus(), sb);
482: display("resource type", resourceType, sb);
483: display("etag", etag, sb);
484: display("supported locks", supportedLocks, sb);
485: display("children", children, sb);
486: display("active locks", locks, sb);
487: display("links", links, sb);
488: display("custom properties", customProperties, sb);
489: display("available properties", availableProperties, sb);
490: display("response description", responseDescription, sb);
491: return sb.toString();
492: }
493:
494: public String toString() {
495: StringBuffer sb = new StringBuffer("DAVFile [");
496: sb.append(getName());
497: sb.append(']');
498: return sb.toString();
499: }
500:
501: public int compareToDAVFile(DAVFile otherFile) {
502: //first host, then port, then isCollection, then name
503: String otherHost = otherFile.getHost();
504: String this Host = getHost();
505: if (otherHost == null)
506: otherHost = "";
507: if (this Host == null)
508: this Host = "";
509: if (!otherHost.equals(this Host)) {
510: return this Host.compareTo(otherHost);
511: }
512: int otherPort = otherFile.getPort();
513: int this Port = getPort();
514: if (otherPort != this Port) {
515: return (new Integer(this Port)).compareTo(new Integer(
516: otherPort));
517: }
518: boolean coll1 = isCollection();
519: boolean coll2 = otherFile.isCollection();
520: if (coll1 && !coll2)
521: return -1;
522: if (coll2 && !coll1)
523: return 1;
524: return getName().compareTo(otherFile.getName());
525: }
526:
527: public int compareTo(Object otherObject) {
528: if (otherObject instanceof DAVFile)
529: return compareToDAVFile((DAVFile) otherObject);
530: return getName().compareTo(otherObject.toString());
531: }
532: }
533:
534: /* $Log: DAVFile.java,v $
535: /* Revision 1.17 2001/07/18 20:20:53 smulloni
536: /* added IfHeader to LockMethod; fixed peculiar DAVFile bug (in getLock());
537: /* various fixes, new cases to auto.py
538: /*
539: /* Revision 1.16 2001/01/05 08:01:12 smulloni
540: /* changes to the connection gui for the Explorer; added depth configurability to
541: /* propfind in the jpython test script; added an experimental "allprop" system
542: /* property which affects the propfind query type
543: /*
544: /* Revision 1.15 2001/01/03 20:11:31 smulloni
545: /* the DAVFileChooser now replaces JFileChooser for remote file access.
546: /* DAVMethod now has a protocol property.
547: /*
548: /* Revision 1.14 2000/12/19 22:06:15 smulloni
549: /* adding documentation.
550: /*
551: /* Revision 1.13 2000/12/03 23:53:25 smulloni
552: /* added license and copyright preamble to java files.
553: /*
554: /* Revision 1.12 2000/12/01 16:25:50 smullyan
555: /* improvements to look and feel; fixed NPE in DAVFile; new actions for text
556: /* editor
557: /*
558: /* Revision 1.11 2000/11/20 23:30:18 smullyan
559: /* more editor integration work.
560: /*
561: /* Revision 1.10 2000/11/09 23:34:50 smullyan
562: /* log added to every Java file, with the help of python. Lock stealing
563: /* implemented, and treatment of locks made more robust.
564: /* */
|