001: package com.ibm.webdav.fileSystem;
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: import java.io.*;
018: import java.net.*;
019: import java.util.*;
020:
021: import javax.xml.parsers.*;
022:
023: import org.w3c.dom.*;
024:
025: import com.ibm.webdav.*;
026: import com.ibm.webdav.impl.*;
027:
028: /** fileSystem.NamespaceManager implements all WebDAV namespace methods using
029: * the native file system as a repository manager. A resource collection
030: * corresponds to a directory while a resource corresponds to a file in a
031: * directory.
032: * @author Jim Amsden <jamsden@us.ibm.com>
033: */
034: public class NamespaceManager implements
035: com.ibm.webdav.impl.NamespaceManager {
036:
037: private ResourceImpl resource = null;
038: private OutputStream openedOutputStream = null;
039:
040: private static final int bufferSize = 8192;
041:
042: /** Create a NamespaceManager for creating resources. (This is necessary because
043: * createResource can't be static and declared in the NamespaceManager interface.)
044: */
045: public NamespaceManager() {
046: }
047:
048: /** Create a NamesapceManager for a given resource.
049: * @param resource the resource to manage
050: */
051: public NamespaceManager(ResourceImpl resource) {
052: initialize(resource);
053: }
054:
055: /** Close any opened OutputStream on the contents of the managed resource.
056: * In this case, just close any open file output stream.
057: * @exception com.ibm.webdav.WebDAVException
058: */
059: public void closeContentsOutputStream() throws WebDAVException {
060: // close any opened output stream
061: if (openedOutputStream == null) {
062: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
063: "No output stream is opened");
064: }
065: try {
066: openedOutputStream.close();
067: } catch (WebDAVException exc) {
068: throw exc;
069: } catch (java.io.IOException exc) {
070: throw new WebDAVException(
071: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO Error");
072: }
073: openedOutputStream = null;
074: }
075:
076: /** Create a collection with the given local name by creating a
077: * directory with the local name.
078: * @param localName the repository specific local name for the resource
079: * @exception com.ibm.webdav.WebDAVException
080: */
081: public void createCollection(String localName)
082: throws WebDAVException {
083: // be sure you can write to the parent directory
084: String parentName = getParentName();
085: File parent = new File(parentName);
086: if (!parent.canWrite()) {
087: throw new WebDAVException(WebDAVStatus.SC_FORBIDDEN,
088: "Insufficient permissions");
089: }
090: File dir = new File(localName);
091: if (!dir.mkdir()) {
092: throw new WebDAVException(
093: WebDAVStatus.SC_INSUFFICIENT_SPACE_ON_RESOURCE,
094: "Could not create collection");
095: }
096: }
097:
098: /** Create this resource as a lock-null resource, a resource created by locking one that
099: * did not previously exist. This implementation creates a properties file for the resource,
100: * but no resource file. That is, a lock-null resource is a resource with no contents file,
101: * but having a properties file.
102: * @exception com.ibm.webdav.WebDAVException
103: */
104: public void createLockNullResource() throws WebDAVException {
105: Document document = resource.loadProperties();
106: resource.saveProperties(document);
107: }
108:
109: /** create a binding
110: * @exception com.ibm.webdav.WebDAVException
111: */
112: public void createBinding(URL destURL) throws WebDAVException {
113: //@todo
114: }
115:
116: /** Move the managed resource.
117: * @exception com.ibm.webdav.WebDAVException
118: */
119: public void move(String path) throws WebDAVException {
120: //@todo
121: }
122:
123: /** Delete the managed resource from the repository. Just delete
124: * the file or directory after making sure the server has sufficient
125: * permission.
126: * @exception com.ibm.webdav.WebDAVException
127: */
128: public void delete() throws WebDAVException {
129: String fileName = ResourceFactory
130: .getRealPath(resource.getURL());
131: File file = new File(fileName);
132:
133: // see if the file is writeable
134: if (!file.canWrite()) {
135: throw new WebDAVException(WebDAVStatus.SC_FORBIDDEN,
136: "Insufficient permissions");
137: }
138:
139: // Attempt to delete this resource
140: if (!file.delete()) {
141: throw new WebDAVException(WebDAVStatus.SC_CONFLICT,
142: "Unable to delete resource, may be in use");
143: }
144: }
145:
146: /** Create an XML file containing the contents of a collection.
147: * @param file the directory to read
148: * @return an InputStream on the resulting XML file.
149: * @exception com.ibm.webdav.WebDAVException
150: */
151: private InputStream directoryToXMLStream(File file)
152: throws WebDAVException {
153: Document document = null;
154:
155: try {
156: document = DocumentBuilderFactory.newInstance()
157: .newDocumentBuilder().newDocument();
158: } catch (Exception e) {
159: throw new WebDAVException(
160: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, e
161: .getMessage());
162: }
163: //document.setVersion(Resource.XMLVersion);
164: //document.setEncoding(Resource.defaultXMLEncoding);
165:
166: Element collection = document.createElement("D:collection");
167: collection.setAttribute("xmlns:D", "DAV:");
168: document.appendChild(collection);
169: String[] fileNames = file.list();
170: for (int i = 0; i < fileNames.length; i++) {
171: String fileName = fileNames[i];
172: String propertiesFileName = null;
173: if (fileName.endsWith(PropertiesManager.propertiesSuffix)) {
174: propertiesFileName = fileName;
175: fileName = propertiesFileName.substring(0,
176: propertiesFileName.length()
177: - PropertiesManager.propertiesSuffix
178: .length());
179: }
180: // add resources and lock-null resources
181: if (propertiesFileName == null
182: || (propertiesFileName != null && !new File(
183: fileName).exists())) {
184: Element uri = document.createElement("D:member");
185: uri.appendChild(document.createTextNode(fileName));
186: collection.appendChild(uri);
187: }
188: }
189: ByteArrayOutputStream os = new ByteArrayOutputStream();
190: try {
191: PrintWriter pout = new PrintWriter(new OutputStreamWriter(
192: os, Resource.defaultCharEncoding), false);
193: pout.print(XMLUtility.printNode(document
194: .getDocumentElement()));
195: //document.print(pout);
196: } catch (Exception exc) {
197: }
198: // TODO: depends on charset encoding
199: //resource.getResponseContext().contentLength(os.toByteArray().length);
200: resource.getResponseContext().contentType("text/xml");
201: return new ByteArrayInputStream(os.toByteArray());
202: }
203:
204: /** See if this resource exists in the repository.
205: *
206: * @return true if the resource exists, false otherwise.
207: * @exception com.ibm.webdav.WebDAVException
208: */
209: public boolean exists() throws WebDAVException {
210: File file = new File(ResourceFactory.getRealPath(resource
211: .getURL()));
212: return file.exists();
213: }
214:
215: /** Open an InputStream on the contents of the managed resource. This implementation
216: * opens the resource file, or gets an input stream on the an XML document describing
217: * the contents of a directory.
218: *
219: * @return an InputStream on the contents of the managed resource.
220: * @exception com.ibm.webdav.WebDAVException
221: */
222: public InputStream getContentsInputStream() throws WebDAVException {
223: File file = new File(ResourceFactory.getRealPath(resource
224: .getURL()));
225: InputStream is = null;
226:
227: try {
228: // is the uri a collection (directory in this implementation)?
229: if (file.isDirectory()) {
230: resource.getResponseContext().contentType("text/xml");
231: is = directoryToXMLStream(file);
232: } else {
233: is = new BufferedInputStream(new FileInputStream(file),
234: bufferSize);
235: // get the content type. Default to text/plain
236: String contentType = guessAtContentTypeForName(file
237: .getName());
238: resource.getResponseContext().contentType(contentType);
239: // content type for text files must handle charset encodings
240: if (!contentType.startsWith("text/")) {
241: resource.getResponseContext().contentLength(
242: file.length());
243: }
244: String cdstring = new SimpleRFC1123DateFormat()
245: .format(new Date(file.lastModified()));
246: resource.getResponseContext().lastModified(cdstring);
247: }
248: } catch (FileNotFoundException exc) {
249: if (file.exists()) {
250: throw new WebDAVException(WebDAVStatus.SC_UNAUTHORIZED,
251: "Insufficient permissions");
252: } else {
253: throw new WebDAVException(WebDAVStatus.SC_NOT_FOUND,
254: "Resource not found");
255: }
256: } catch (SecurityException exc) {
257: throw new WebDAVException(WebDAVStatus.SC_UNAUTHORIZED,
258: "Insufficient permissions");
259: }
260: return is;
261: }
262:
263: /** Open an OutputStream in order to write the contents of the managed resource.
264: *
265: * @return an OutputStream on the contents of the managed resource.
266: * @exception com.ibm.webdav.WebDAVException
267: */
268: public OutputStream getContentsOutputStream()
269: throws WebDAVException {
270: String fileName = ResourceFactory
271: .getRealPath(resource.getURL());
272: File file = new File(fileName);
273:
274: // see if the file is writeable
275: if (file.exists() && !file.canWrite()) {
276: throw new WebDAVException(WebDAVStatus.SC_FORBIDDEN,
277: "Insufficient permissions");
278: }
279:
280: // don't allow writes to properties files
281: if (fileName.endsWith(PropertiesManager.propertiesSuffix)) {
282: throw new WebDAVException(WebDAVStatus.SC_FORBIDDEN,
283: "Can't write to WebDAV properties files");
284: }
285:
286: // Resources that already exist are overwritten
287: try {
288: openedOutputStream = new BufferedOutputStream(
289: new FileOutputStream(file), bufferSize);
290: } /*catch (WebDAVException exc) {
291: throw exc;
292: }*/catch (java.io.IOException exc) {
293: throw new WebDAVException(
294: WebDAVStatus.SC_INTERNAL_SERVER_ERROR, "IO Error");
295: }
296: return openedOutputStream;
297: }
298:
299: /** Get the members of a collection.
300: *
301: * @return a Vector of Resources (ResourceP or CollectionP)
302: * @exception com.ibm.webdav.WebDAVException
303: */
304: public Vector getMembers() throws WebDAVException {
305: Vector members = new Vector();
306: String parentName = ResourceFactory.getRealPath(resource
307: .getURL());
308: if (!parentName.endsWith(File.separator)) {
309: parentName = parentName + File.separator;
310: }
311:
312: File parent = new File(parentName);
313: if (!parent.isDirectory()) {
314: throw new WebDAVException(WebDAVStatus.SC_BAD_REQUEST,
315: "Resource is not a collection");
316: }
317:
318: String[] fileNames = parent.list();
319: if (fileNames == null) {
320: // this can happen if the directory was deleted, but there was an
321: // explorer open on it that hasn't been refreshed
322: return members;
323: }
324:
325: for (int i = 0; i < fileNames.length; i++) {
326: String fileName = fileNames[i];
327: String propertiesFileName = null;
328: if (fileName.endsWith(PropertiesManager.propertiesSuffix)) {
329: propertiesFileName = fileName;
330: fileName = propertiesFileName.substring(0,
331: propertiesFileName.length()
332: - PropertiesManager.propertiesSuffix
333: .length());
334: }
335: // add resources and lock-null resources
336: String childName = parentName + fileName;
337: File file = new File(childName);
338: if (propertiesFileName == null || !file.exists()) {
339: ResourceImpl member = null;
340: if (file.isDirectory()) {
341: member = new CollectionImpl(
342: ((CollectionImpl) resource)
343: .getChildURL(fileName), childName,
344: null);
345: } else {
346: member = new ResourceImpl(
347: ((CollectionImpl) resource)
348: .getChildURL(fileName), childName);
349: }
350: member.setRequestContext(resource.getContext());
351: members.addElement(member);
352: }
353: }
354: return members;
355: }
356:
357: /** Get the name of the collection (directory) containing this resource (file).
358: *
359: * @return the parent collection name, always ending in a separator
360: * @exception com.ibm.webdav.WebDAVException
361: */
362: public String getParentName() throws WebDAVException {
363: String fileName = ResourceFactory
364: .getRealPath(resource.getURL());
365: int delimiterPosition = 0;
366: if (fileName.endsWith(File.separator)) {
367: delimiterPosition = fileName.substring(0,
368: fileName.length() - 1).lastIndexOf(File.separator);
369: } else {
370: delimiterPosition = fileName.lastIndexOf(File.separator);
371: }
372: return fileName.substring(0, delimiterPosition + 1);
373: }
374:
375: /** Guess at the mimetype of a file based on it's filename extention.
376: *
377: * @param fn the filename
378: * @return the mimetype string
379: */
380: public static String guessAtContentTypeForName(String fn) {
381: int i = fn.lastIndexOf('.');
382: if (i == -1)
383: return "text/plain";
384: String ext = fn.substring(i + 1);
385: String mtype = ResourceFactory.properties.getProperty(ext,
386: "text/plain").trim();
387: // if (mtype == null) {
388: // mtype = URLConnection.guessContentTypeFromStream(is);
389: // }
390: if (mtype == null) {
391: mtype = "text/plain";
392: }
393: if (fn.endsWith(".xml")) {
394: mtype = "text/xml";
395: }
396: return mtype;
397: }
398:
399: /** Initialize this NamesapceManager on a given resource.
400: * @param resource the resource to manage
401: */
402: public void initialize(ResourceImpl resource) {
403: this .resource = resource;
404: }
405:
406: /** Is the managed resource a collection (i.e., is this file a directory)?
407: * @return true if this resource is a collection, false otherwise
408: * @exception com.ibm.webdav.WebDAVException
409: */
410: public boolean isCollection() throws WebDAVException {
411: File file = new File(ResourceFactory.getRealPath(resource
412: .getURL()));
413: if (!file.exists()) {
414: throw new ClientException(404, "File Not Found");
415: }
416: return file.isDirectory();
417: }
418:
419: /** Is this resource in the lock-null state? In this implementation, does
420: * this resource have a properties file, but no contents file.
421: * @return true if this resource is a lock-null resource, false otherwise
422: * @exception com.ibm.webdav.WebDAVException
423: */
424: public boolean isLockNull() throws WebDAVException {
425: File file = new File(ResourceFactory.getRealPath(resource
426: .getURL()));
427: String propertiesFileName = ResourceFactory
428: .getRealPath(resource.getURL());
429: if (propertiesFileName.endsWith(File.separator)) {
430: propertiesFileName = propertiesFileName.substring(0,
431: propertiesFileName.length() - 1);
432: }
433: propertiesFileName = propertiesFileName
434: + PropertiesManager.propertiesSuffix;
435: File propertiesFile = new File(propertiesFileName);
436: return !file.exists() && propertiesFile.exists();
437: }
438:
439: /** Treat the managed resource as a method and execute it with the given arguments.
440: * Ths should be done by the host Web server. Executes CGI scripts and Servlets. But
441: * the repository may have some additional capabilities of its own.
442: * @param args the URL query string (text following the ?)
443: * @return the contents of the result
444: * @exception com.ibm.webdav.WebDAVException
445: */
446: public byte[] performWith(String args) throws WebDAVException {
447: // todo: need to get the request entity body too
448: StringWriter buf = new StringWriter();
449:
450: try {
451: Runtime runtime = Runtime.getRuntime();
452: Process p = runtime.exec(ResourceFactory
453: .getRealPath(resource.getURL())
454: + " " + args);
455: BufferedReader inputStream = new BufferedReader(
456: new InputStreamReader(p.getInputStream()));
457: int ch = -1;
458: while ((ch = inputStream.read()) != -1) {
459: buf.write(ch);
460: }
461: } catch (Exception exc) {
462: System.err.println("MsxlxServlet exception: " + exc);
463: }
464:
465: return buf.toString().getBytes();
466: }
467:
468: /* (non-Javadoc)
469: * @see com.ibm.webdav.impl.NamespaceManager#isVersionable()
470: */
471: public boolean isVersionable() throws WebDAVException {
472: // TODO Auto-generated method stub
473: return false;
474: }
475:
476: /* (non-Javadoc)
477: * @see com.ibm.webdav.impl.NamespaceManager#getAllowedMethods()
478: */
479: public List getAllowedMethods() throws WebDAVException {
480: // TODO Auto-generated method stub
481: return null;
482: }
483:
484: /* (non-Javadoc)
485: * @see com.ibm.webdav.impl.NamespaceManager#setOrdering(org.w3c.dom.Document)
486: */
487: public void setOrdering(Document orderPatch) {
488: // TODO Auto-generated method stub
489:
490: }
491:
492: /* (non-Javadoc)
493: * @see com.ibm.webdav.impl.NamespaceManager#createBinding(java.lang.String, java.net.URL)
494: */
495: public void createBinding(String bindName, URL source)
496: throws WebDAVException {
497: // TODO Auto-generated method stub
498:
499: }
500:
501: /* (non-Javadoc)
502: * @see com.ibm.webdav.impl.NamespaceManager#getContentType()
503: */
504: public String getContentType() throws WebDAVException {
505: // TODO Auto-generated method stub
506: return null;
507: }
508:
509: /* (non-Javadoc)
510: * @see com.ibm.webdav.impl.NamespaceManager#closeContentsOutputStream(java.lang.String)
511: */
512: public void closeContentsOutputStream(String sContentType)
513: throws WebDAVException {
514: // TODO Auto-generated method stub
515:
516: }
517: }
|