/** ========================================================================= *
* Copyright (C) 2012 IBM Corporation *
* based on work of *
* Copyright (C) 2006, 2007 TAO Consulting Pte <http://www.taoconsulting.sg/> *
* All rights reserved. *
* ========================================================================== *
* *
* Licensed under the Apache License, Version 2.0 (the "License"). You may *
* not use this file except in compliance with the License. You may obtain a *
* copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
* License for the specific language governing permissions and limitations *
* under the License. *
* *
* ========================================================================== **/
package com.ibm.xsp.webdav;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import biz.taoconsulting.dominodav.LockManager;
import com.ibm.xsp.webdav.repository.DAVRepositoryMETA;
/**
* The webDAV manager handles the webDAV configuration, the supported methods
* and the potential webDAV methods, refactored out of the original servlet
* Implemented as singleton
*
* @author Stephan H. Wissel
*
*/
public class WebDavManager {
/**
* Key to load the supported HTTP methods like get, post etc.
*/
private static final String SUPPORTEDMETHODSFILE = "methods.properties";
/**
* Properties of the Meta repository like the styles to use and where to
* find the repositories
*/
public static final String METAREPOPROPFILE = "metarepository.properties";
/**
* Key to load temp directory
*/
private static final String INIT_KEY_TEMPDIR = "temp-directory";
/**
* The instance of the class we return
*/
private static WebDavManager internalWebDavManager = null;
/**
* The logger object for event logging
*/
private static final Log LOGGER = LogFactory.getLog(WebDavManager.class);
private static final String DEFAULT_TMP_DIR = "/tmp";
/**
* Style for PROPFIND in XSLT
*/
private String propfindStyle;
/**
* Style for PROPFIND in XSLT for the list of repositories
*/
private String rootPropfindStyle;
/**
* tempDir the directory for temporary file operations
*/
private String tempDir;
/**
* Can the manager been reset, should be false for production The property
* doesn't prevent anything but the servlet is querying it
*/
private boolean allowReset = true;
/**
* The path of the servlet, needs to prefix repositories and files
*/
private String servletPath;
/**
* Mimetype registry
*/
private HashMap<String, String> knownMimeTypes;
/**
*
* @return the servlet Path
*/
public String getServletPath() {
return servletPath;
}
/**
*
* @param servletPath
* prefix for making repositories complete
*/
public void setServletPath(String servletPath) {
this.servletPath = servletPath;
}
/**
* Should the Manager be resettable
*
* @return
*/
public boolean isAllowReset() {
return allowReset;
}
/**
* Initialize the Manager and make sure we did load everything
*/
private synchronized static void initializeWebDavManager(String servletPath) {
if (internalWebDavManager == null) {
internalWebDavManager = new WebDavManager();
}
if (servletPath != null) {
internalWebDavManager.setServletPath(servletPath);
}
internalWebDavManager.getLockManager(); // Start the lock manager
internalWebDavManager.loadSupportedMethods(); // The maximum of methods
// we currently support
internalWebDavManager.loadMetaRepository(); // The repository of our
// repositories
internalWebDavManager.loadMimeTypes(); // All the mimetypes we know
}
private void loadMimeTypes() {
// TODO Find a better way than hardcoding them here!
this.knownMimeTypes = new HashMap<String, String>();
this.knownMimeTypes.put("abs", "audio/x-mpeg");
this.knownMimeTypes.put("ai", "application/postscript");
this.knownMimeTypes.put("aif", "audio/x-aiff");
this.knownMimeTypes.put("aifc", "audio/x-aiff");
this.knownMimeTypes.put("aiff", "audio/x-aiff");
this.knownMimeTypes.put("aim", "application/x-aim");
this.knownMimeTypes.put("art", "image/x-jg");
this.knownMimeTypes.put("asf", "video/x-ms-asf");
this.knownMimeTypes.put("asx", "video/x-ms-asf");
this.knownMimeTypes.put("au", "audio/basic");
this.knownMimeTypes.put("avi", "video/x-msvideo");
this.knownMimeTypes.put("avx", "video/x-rad-screenplay");
this.knownMimeTypes.put("bcpio", "application/x-bcpio");
this.knownMimeTypes.put("bin", "application/octet-stream");
this.knownMimeTypes.put("bmp", "image/bmp");
this.knownMimeTypes.put("body", "text/html");
this.knownMimeTypes.put("cdf", "application/x-cdf");
this.knownMimeTypes.put("cer", "application/x-x509-ca-cert");
this.knownMimeTypes.put("class", "application/java");
this.knownMimeTypes.put("cpio", "application/x-cpio");
this.knownMimeTypes.put("csh", "application/x-csh");
this.knownMimeTypes.put("css", "text/css");
this.knownMimeTypes.put("dib", "image/bmp");
this.knownMimeTypes.put("doc", "application/msword");
this.knownMimeTypes
.put("docx",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document");
this.knownMimeTypes.put("dtd", "application/xml-dtd");
this.knownMimeTypes.put("dv", "video/x-dv");
this.knownMimeTypes.put("dvi", "application/x-dvi");
this.knownMimeTypes.put("eps", "application/postscript");
this.knownMimeTypes.put("etx", "text/x-setext");
this.knownMimeTypes.put("exe", "application/octet-stream");
this.knownMimeTypes.put("gif", "image/gif");
this.knownMimeTypes.put("gtar", "application/x-gtar");
this.knownMimeTypes.put("gz", "application/x-gzip");
this.knownMimeTypes.put("hdf", "application/x-hdf");
this.knownMimeTypes.put("hqx", "application/mac-binhex40");
this.knownMimeTypes.put("htc", "text/x-component");
this.knownMimeTypes.put("htm", "text/html");
this.knownMimeTypes.put("html", "text/html");
this.knownMimeTypes.put("hqx", "application/mac-binhex40");
this.knownMimeTypes.put("ief", "image/ief");
this.knownMimeTypes.put("ini", "text/plain");
this.knownMimeTypes.put("jad", "text/vnd.sun.j2me.app-descriptor");
this.knownMimeTypes.put("jar", "application/java-archive");
this.knownMimeTypes.put("java", "text/plain");
this.knownMimeTypes.put("jnlp", "application/x-java-jnlp-file");
this.knownMimeTypes.put("jpe", "image/jpeg");
this.knownMimeTypes.put("jpeg", "image/jpeg");
this.knownMimeTypes.put("jpg", "image/jpeg");
this.knownMimeTypes.put("js", "text/javascript");
this.knownMimeTypes.put("jsf", "text/plain");
this.knownMimeTypes.put("jspf", "text/plain");
this.knownMimeTypes.put("kar", "audio/x-midi");
this.knownMimeTypes.put("latex", "application/x-latex");
this.knownMimeTypes.put("log", "text/plain");
this.knownMimeTypes.put("m3u", "audio/x-mpegurl");
this.knownMimeTypes.put("mac", "image/x-macpaint");
this.knownMimeTypes.put("man", "application/x-troff-man");
this.knownMimeTypes.put("mathml", "application/mathml+xml");
this.knownMimeTypes.put("me", "application/x-troff-me");
this.knownMimeTypes.put("mid", "audio/x-midi");
this.knownMimeTypes.put("midi", "audio/x-midi");
this.knownMimeTypes.put("mif", "application/x-mif");
this.knownMimeTypes.put("mov", "video/quicktime");
this.knownMimeTypes.put("movie", "video/x-sgi-movie");
this.knownMimeTypes.put("mp1", "audio/x-mpeg");
this.knownMimeTypes.put("mp2", "audio/x-mpeg");
this.knownMimeTypes.put("mp3", "audio/x-mpeg");
this.knownMimeTypes.put("mp4", "video/mp4");
this.knownMimeTypes.put("mpa", "audio/x-mpeg");
this.knownMimeTypes.put("mpe", "video/mpeg");
this.knownMimeTypes.put("mpeg", "video/mpeg");
this.knownMimeTypes.put("mpega", "audio/x-mpeg");
this.knownMimeTypes.put("mpg", "video/mpeg");
this.knownMimeTypes.put("mpv2", "video/mpeg2");
this.knownMimeTypes.put("ms", "application/x-wais-source");
this.knownMimeTypes.put("nc", "application/x-netcdf");
this.knownMimeTypes.put("ns2", "application/vnd.lotus-notes");
this.knownMimeTypes.put("ns3", "application/vnd.lotus-notes");
this.knownMimeTypes.put("ns4", "application/vnd.lotus-notes");
this.knownMimeTypes.put("ns5", "application/vnd.lotus-notes");
this.knownMimeTypes.put("ns6", "application/vnd.lotus-notes");
this.knownMimeTypes.put("ns7", "application/vnd.lotus-notes");
this.knownMimeTypes.put("ns8", "application/vnd.lotus-notes");
this.knownMimeTypes.put("ns9", "application/vnd.lotus-notes");
this.knownMimeTypes.put("nsf", "application/vnd.lotus-notes");
this.knownMimeTypes.put("ntf", "application/vnd.lotus-notes");
this.knownMimeTypes.put("oda", "application/oda");
this.knownMimeTypes.put("odb",
"application/vnd.oasis.opendocument.database");
this.knownMimeTypes.put("odc",
"application/vnd.oasis.opendocument.chart");
this.knownMimeTypes.put("odf",
"application/vnd.oasis.opendocument.formula");
this.knownMimeTypes.put("odg",
"application/vnd.oasis.opendocument.graphics");
this.knownMimeTypes.put("odi",
"application/vnd.oasis.opendocument.image");
this.knownMimeTypes.put("odm",
"application/vnd.oasis.opendocument.text-master");
this.knownMimeTypes.put("odp",
"application/vnd.oasis.opendocument.presentation");
this.knownMimeTypes.put("ods",
"application/vnd.oasis.opendocument.spreadsheet");
this.knownMimeTypes.put("odt",
"application/vnd.oasis.opendocument.text");
this.knownMimeTypes.put("ogg", "application/ogg");
this.knownMimeTypes.put("otg ",
"application/vnd.oasis.opendocument.graphics-template");
this.knownMimeTypes.put("oth",
"application/vnd.oasis.opendocument.text-web");
this.knownMimeTypes.put("otp",
"application/vnd.oasis.opendocument.presentation-template");
this.knownMimeTypes.put("ots",
"application/vnd.oasis.opendocument.spreadsheet-template ");
this.knownMimeTypes.put("ott",
"application/vnd.oasis.opendocument.text-template");
this.knownMimeTypes.put("pbm", "image/x-portable-bitmap");
this.knownMimeTypes.put("pct", "image/pict");
this.knownMimeTypes.put("pdf", "application/pdf");
this.knownMimeTypes.put("pgm", "image/x-portable-graymap");
this.knownMimeTypes.put("pic", "image/pict");
this.knownMimeTypes.put("pict", "image/pict");
this.knownMimeTypes.put("pls", "audio/x-scpls");
this.knownMimeTypes.put("png", "image/png");
this.knownMimeTypes.put("pnm", "image/x-portable-anymap");
this.knownMimeTypes.put("pnt", "image/x-macpaint");
this.knownMimeTypes.put("ppm", "image/x-portable-pixmap");
this.knownMimeTypes.put("pps", "application/vnd.ms-powerpoint");
this.knownMimeTypes.put("ppt", "application/vnd.ms-powerpoint");
this.knownMimeTypes
.put("pptx",
"application/vnd.openxmlformats-officedocument.presentationml.presentation");
this.knownMimeTypes.put("ps", "application/postscript");
this.knownMimeTypes.put("psd", "image/x-photoshop");
this.knownMimeTypes.put("qt", "video/quicktime");
this.knownMimeTypes.put("qti", "image/x-quicktime");
this.knownMimeTypes.put("qtif", "image/x-quicktime");
this.knownMimeTypes.put("ras", "image/x-cmu-raster");
this.knownMimeTypes.put("rdf", "application/rdf+xml");
this.knownMimeTypes.put("rgb", "image/x-rgb");
this.knownMimeTypes.put("rm", "application/vnd.rn-realmedia");
this.knownMimeTypes.put("roff", "application/x-troff");
this.knownMimeTypes.put("rtf", "application/rtf");
this.knownMimeTypes.put("rtx", "text/richtext");
this.knownMimeTypes.put("sh", "application/x-sh");
this.knownMimeTypes.put("shar", "application/x-shar");
this.knownMimeTypes.put("smf", "audio/x-midi");
this.knownMimeTypes.put("sit", "application/x-stuffit");
this.knownMimeTypes.put("snd", "audio/basic");
this.knownMimeTypes.put("src", "application/x-wais-source");
this.knownMimeTypes.put("sv4cpio", "application/x-sv4cpio");
this.knownMimeTypes.put("sv4crc", "application/x-sv4crc");
this.knownMimeTypes.put("svg", "image/svg+xml");
this.knownMimeTypes.put("svgz", "image/svg+xml");
this.knownMimeTypes.put("swf", "application/x-shockwave-flash");
this.knownMimeTypes.put("t", "application/x-troff");
this.knownMimeTypes.put("tar", "application/x-tar");
this.knownMimeTypes.put("tcl", "application/x-tcl");
this.knownMimeTypes.put("tex", "application/x-tex");
this.knownMimeTypes.put("texi", "application/x-texinfo");
this.knownMimeTypes.put("texinfo", "application/x-texinfo");
this.knownMimeTypes.put("tif", "image/tiff");
this.knownMimeTypes.put("tiff", "image/tiff");
this.knownMimeTypes.put("tr", "application/x-troff");
this.knownMimeTypes.put("tsv", "text/tab-separated-values");
this.knownMimeTypes.put("txt", "text/plain");
this.knownMimeTypes.put("ulw", "audio/basic");
this.knownMimeTypes.put("ustar", "application/x-ustar");
this.knownMimeTypes.put("vxml", "application/voicexml+xml");
this.knownMimeTypes.put("xbm", "image/x-xbitmap");
this.knownMimeTypes.put("xht", "application/xhtml+xml");
this.knownMimeTypes.put("xhtml", "application/xhtml+xml");
this.knownMimeTypes.put("xls", "application/vnd.ms-excel");
this.knownMimeTypes
.put("xlsx",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
this.knownMimeTypes.put("xml", "application/xml");
this.knownMimeTypes.put("xpm", "image/x-xpixmap");
this.knownMimeTypes.put("xsl", "application/xml");
this.knownMimeTypes.put("xslt", "application/xslt+xml");
this.knownMimeTypes.put("xul", "application/vnd.mozilla.xul+xml");
this.knownMimeTypes.put("xwd", "image/x-xwindowdump");
this.knownMimeTypes.put("vsd", "application/x-visio");
this.knownMimeTypes.put("wav", "audio/x-wav");
this.knownMimeTypes.put("wbmp", "image/vnd.wap.wbmp");
this.knownMimeTypes.put("webdav", "application/x-webdav");
this.knownMimeTypes.put("wml", "text/vnd.wap.wml");
this.knownMimeTypes.put("wmlc", "application/vnd.wap.wmlc");
this.knownMimeTypes.put("wmls", "text/vnd.wap.wmlscript");
this.knownMimeTypes.put("wmlscriptc", "application/vnd.wap.wmlscriptc");
this.knownMimeTypes.put("wmv", "video/x-ms-wmv");
this.knownMimeTypes.put("wrl", "x-world/x-vrml");
this.knownMimeTypes.put("wspolicy", "application/wspolicy+xml");
this.knownMimeTypes.put("Z", "application/x-compress");
this.knownMimeTypes.put("z", "application/x-compress");
this.knownMimeTypes.put("zip", "application/zip");
// LOGGER.info("Loaded "+String.valueOf(this.knownMimeTypes.size())+" mime types");
}
// The next 4 methods ensure that it is a singleton
/**
* @param reset
* boolean -- if true the webDav manager gets setup freshly
* @return the Singleton instance of the webDAV manager, should be loaded
* once only anyway
*/
public static synchronized WebDavManager getManager(String servletPath,
boolean reset) {
if (reset || internalWebDavManager == null) {
if (reset) {
LOGGER.error("WebDAVManager reset executed");
}
initializeWebDavManager(servletPath);
}
return internalWebDavManager;
}
/**
* @return the Singleton instance of the webDAV manager, should be loaded
* once only anyway
*/
public static synchronized WebDavManager getManager(String servletPath) {
return WebDavManager.getManager(servletPath, false);
}
/**
* (non-Javadoc)
*
* @see java.lang.Object#clone()
*/
@Override
protected Object clone() throws CloneNotSupportedException {
// Singletons must NOT be cloned
throw new CloneNotSupportedException();
}
/**
* We make the constructor private, so you can't get to it
*/
private WebDavManager() {
}
// Starting here are the class instance methods we actually use to return
// values
/**
* List of maximum supported HTTP Methods loaded from methods.properties
* This is the maxium of supported methods. Individual repositories might
* implement only a subset of them
*/
private Properties supportedMethods;
/**
* Lock Manager to allow locking of documents
*/
private LockManager lockManager;
/**
* Meta Repository to hold the list of top level repositories
*/
private DAVRepositoryMETA repositoryMeta;
/**
* @return Returns the lockManager.
*/
public LockManager getLockManager() {
if (this.lockManager != null) {
return this.lockManager;
}
this.lockManager = LockManager.getLockManager();
return this.lockManager;
}
/**
* Loads all the supported HTTP keywords
*/
private void loadSupportedMethods() {
this.supportedMethods = new Properties();
InputStream in = this.getClass().getResourceAsStream(
WebDavManager.SUPPORTEDMETHODSFILE);
try {
this.supportedMethods.load(in);
// FIXME - remove rawtimes
for (@SuppressWarnings("rawtypes")
Map.Entry curMethod : this.supportedMethods.entrySet()) {
LOGGER.debug("Method: " + curMethod.getKey().toString()
+ " with class " + curMethod.getValue().toString());
}
} catch (IOException e) {
LOGGER.error(e);
}
}
/**
* loads the meta repository that contains all the repositories we currently
* use as well as the global parameters now stored in the webDAVManager
*/
private void loadMetaRepository() {
// Load the Meta Repository -- and the style
Properties metaProp = new Properties(); // to be loaded from file
InputStream in = this.getClass().getResourceAsStream(
WebDavManager.METAREPOPROPFILE);
try {
metaProp.load(in);
} catch (IOException e) {
LOGGER.error(e);
}
// Now load the values with sensible defaults
String configLocation = metaProp.getProperty("repository-location",
DAVRepositoryMETA.DEFAULT_REPOSITORY_LOCATION);
String propfindStyle = metaProp.getProperty("style-name",
DAVRepositoryMETA.DEFAULT_PROPFIND_STYLE);
String rootStyle = metaProp.getProperty("root-style-name",
DAVRepositoryMETA.DEFAULT_ROOT_STYLE);
Boolean autoreload = new Boolean(metaProp.getProperty("auto-reload",
"true"));
Boolean canReset = new Boolean(metaProp.getProperty("allow-reset",
"false"));
String tempDir = metaProp
.getProperty(INIT_KEY_TEMPDIR, DEFAULT_TMP_DIR);
// Apply them to the repository and the manager
this.repositoryMeta = DAVRepositoryMETA.getRepository(configLocation);
this.repositoryMeta.setAutoReloadRepositoryList(autoreload
.booleanValue());
this.setRootPropfindStyle(rootStyle);
this.setPropfindStyle(propfindStyle);
this.setTempDir(tempDir);
this.allowReset = canReset.booleanValue();
// Write to the logger
LOGGER.debug("Root-Style name:" + this.getRootPropfindStyle());
LOGGER.debug("Repository-Style name:" + this.getPropfindStyle());
LOGGER.debug("Configuration location:" + configLocation);
LOGGER.debug("Can auto reload list:" + autoreload.toString());
LOGGER.debug("Can reset:" + canReset.toString());
LOGGER.debug("Temp Dir:" + tempDir);
}
/**
* @param methodName
* the HTTP method we need
* @return the classname for that method
*/
public String getClassForMethod(String methodName) {
if (this.supportedMethods == null) {
this.loadSupportedMethods();
}
return this.supportedMethods.getProperty(methodName.toUpperCase());
}
/**
* @return the repositoryMeta
*/
public DAVRepositoryMETA getRepositoryMeta() {
if (this.repositoryMeta == null) {
this.loadMetaRepository();
}
return this.repositoryMeta;
}
/**
* @param repositoryMeta
* the repositoryMeta to set
*/
public void setRepositoryMeta(DAVRepositoryMETA repositoryMeta) {
this.repositoryMeta = repositoryMeta;
}
/**
*
* @return String XSLT Style for Propfind to make it look pretty in the
* browser
*/
public String getPropfindStyle() {
return this.propfindStyle;
}
/**
*
* @param propfindStyle
* Style for Propfind
*/
public void setPropfindStyle(String propfindStyle) {
this.propfindStyle = propfindStyle;
}
/**
*
* @return String XSLT Style for Propfind to make it look pretty in the
* browser
*/
public String getRootPropfindStyle() {
return this.rootPropfindStyle;
}
/**
*
* @param propfindStyle
* Style for Propfind
*/
public void setRootPropfindStyle(String propfindStyle) {
this.rootPropfindStyle = propfindStyle;
}
/**
* @param tempDir
* the directory for temporary file operations
*/
public void setTempDir(String tempDir) {
this.tempDir = tempDir;
}
/**
* @return The current temporary directory
*/
public String getTempDir() {
if (this.tempDir == null) {
this.tempDir = DEFAULT_TMP_DIR;
}
return this.tempDir;
}
/**
* Retrieves mime types for known extensions
*
* @param fileName
* @return
*/
public String getMimeType(String fileName) {
String returnType = "application/octet-stream"; // Default value if
// things go wrong
int lastDot = fileName.lastIndexOf(".");
if (lastDot < 0) {
return returnType; // For files without extension we can't tell here
}
String extension = fileName.substring(lastDot + 1).toLowerCase();
if (this.knownMimeTypes.containsKey(extension)) {
returnType = this.knownMimeTypes.get(extension);
}
return returnType;
}
}