Source Code Cross Referenced for WebdavServlet.java in  » Sevlet-Container » apache-tomcat-6.0.14 » org » apache » catalina » servlets » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Sevlet Container » apache tomcat 6.0.14 » org.apache.catalina.servlets 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one or more
0003:         * contributor license agreements.  See the NOTICE file distributed with
0004:         * this work for additional information regarding copyright ownership.
0005:         * The ASF licenses this file to You under the Apache License, Version 2.0
0006:         * (the "License"); you may not use this file except in compliance with
0007:         * the License.  You may obtain a copy of the License at
0008:         *
0009:         *      http://www.apache.org/licenses/LICENSE-2.0
0010:         *
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         */
0017:
0018:        package org.apache.catalina.servlets;
0019:
0020:        import java.io.IOException;
0021:        import java.io.StringWriter;
0022:        import java.io.Writer;
0023:        import java.security.MessageDigest;
0024:        import java.security.NoSuchAlgorithmException;
0025:        import java.text.SimpleDateFormat;
0026:        import java.util.Date;
0027:        import java.util.Enumeration;
0028:        import java.util.Hashtable;
0029:        import java.util.Stack;
0030:        import java.util.TimeZone;
0031:        import java.util.Vector;
0032:
0033:        import javax.naming.NameClassPair;
0034:        import javax.naming.NamingEnumeration;
0035:        import javax.naming.NamingException;
0036:        import javax.naming.directory.DirContext;
0037:        import javax.servlet.ServletException;
0038:        import javax.servlet.UnavailableException;
0039:        import javax.servlet.http.HttpServletRequest;
0040:        import javax.servlet.http.HttpServletResponse;
0041:        import javax.xml.parsers.DocumentBuilder;
0042:        import javax.xml.parsers.DocumentBuilderFactory;
0043:        import javax.xml.parsers.ParserConfigurationException;
0044:
0045:        import org.apache.catalina.util.DOMWriter;
0046:        import org.apache.catalina.util.MD5Encoder;
0047:        import org.apache.catalina.util.RequestUtil;
0048:        import org.apache.catalina.util.XMLWriter;
0049:        import org.apache.naming.resources.CacheEntry;
0050:        import org.apache.naming.resources.Resource;
0051:        import org.apache.naming.resources.ResourceAttributes;
0052:        import org.apache.tomcat.util.http.FastHttpDateFormat;
0053:        import org.w3c.dom.Document;
0054:        import org.w3c.dom.Element;
0055:        import org.w3c.dom.Node;
0056:        import org.w3c.dom.NodeList;
0057:        import org.xml.sax.InputSource;
0058:        import org.xml.sax.SAXException;
0059:
0060:        /**
0061:         * Servlet which adds support for WebDAV level 2. All the basic HTTP requests
0062:         * are handled by the DefaultServlet.
0063:         *
0064:         * @author Remy Maucherat
0065:         * @version $Revision: 543681 $ $Date: 2007-06-02 02:42:59 +0200 (sam., 02 juin 2007) $
0066:         */
0067:
0068:        public class WebdavServlet extends DefaultServlet {
0069:
0070:            // -------------------------------------------------------------- Constants
0071:
0072:            private static final String METHOD_HEAD = "HEAD";
0073:            private static final String METHOD_PROPFIND = "PROPFIND";
0074:            private static final String METHOD_PROPPATCH = "PROPPATCH";
0075:            private static final String METHOD_MKCOL = "MKCOL";
0076:            private static final String METHOD_COPY = "COPY";
0077:            private static final String METHOD_MOVE = "MOVE";
0078:            private static final String METHOD_LOCK = "LOCK";
0079:            private static final String METHOD_UNLOCK = "UNLOCK";
0080:
0081:            /**
0082:             * Default depth is infite.
0083:             */
0084:            private static final int INFINITY = 3; // To limit tree browsing a bit
0085:
0086:            /**
0087:             * PROPFIND - Specify a property mask.
0088:             */
0089:            private static final int FIND_BY_PROPERTY = 0;
0090:
0091:            /**
0092:             * PROPFIND - Display all properties.
0093:             */
0094:            private static final int FIND_ALL_PROP = 1;
0095:
0096:            /**
0097:             * PROPFIND - Return property names.
0098:             */
0099:            private static final int FIND_PROPERTY_NAMES = 2;
0100:
0101:            /**
0102:             * Create a new lock.
0103:             */
0104:            private static final int LOCK_CREATION = 0;
0105:
0106:            /**
0107:             * Refresh lock.
0108:             */
0109:            private static final int LOCK_REFRESH = 1;
0110:
0111:            /**
0112:             * Default lock timeout value.
0113:             */
0114:            private static final int DEFAULT_TIMEOUT = 3600;
0115:
0116:            /**
0117:             * Maximum lock timeout.
0118:             */
0119:            private static final int MAX_TIMEOUT = 604800;
0120:
0121:            /**
0122:             * Default namespace.
0123:             */
0124:            protected static final String DEFAULT_NAMESPACE = "DAV:";
0125:
0126:            /**
0127:             * Simple date format for the creation date ISO representation (partial).
0128:             */
0129:            protected static final SimpleDateFormat creationDateFormat = new SimpleDateFormat(
0130:                    "yyyy-MM-dd'T'HH:mm:ss'Z'");
0131:
0132:            /**
0133:             * MD5 message digest provider.
0134:             */
0135:            protected static MessageDigest md5Helper;
0136:
0137:            /**
0138:             * The MD5 helper object for this class.
0139:             */
0140:            protected static final MD5Encoder md5Encoder = new MD5Encoder();
0141:
0142:            static {
0143:                creationDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
0144:            }
0145:
0146:            // ----------------------------------------------------- Instance Variables
0147:
0148:            /**
0149:             * Repository of the locks put on single resources.
0150:             * <p>
0151:             * Key : path <br>
0152:             * Value : LockInfo
0153:             */
0154:            private Hashtable<String, LockInfo> resourceLocks = new Hashtable<String, LockInfo>();
0155:
0156:            /**
0157:             * Repository of the lock-null resources.
0158:             * <p>
0159:             * Key : path of the collection containing the lock-null resource<br>
0160:             * Value : Vector of lock-null resource which are members of the
0161:             * collection. Each element of the Vector is the path associated with
0162:             * the lock-null resource.
0163:             */
0164:            private Hashtable<String, Vector<String>> lockNullResources = new Hashtable<String, Vector<String>>();
0165:
0166:            /**
0167:             * Vector of the heritable locks.
0168:             * <p>
0169:             * Key : path <br>
0170:             * Value : LockInfo
0171:             */
0172:            private Vector<LockInfo> collectionLocks = new Vector<LockInfo>();
0173:
0174:            /**
0175:             * Secret information used to generate reasonably secure lock ids.
0176:             */
0177:            private String secret = "catalina";
0178:
0179:            // --------------------------------------------------------- Public Methods
0180:
0181:            /**
0182:             * Initialize this servlet.
0183:             */
0184:            public void init() throws ServletException {
0185:
0186:                super .init();
0187:
0188:                if (getServletConfig().getInitParameter("secret") != null)
0189:                    secret = getServletConfig().getInitParameter("secret");
0190:
0191:                // Load the MD5 helper used to calculate signatures.
0192:                try {
0193:                    md5Helper = MessageDigest.getInstance("MD5");
0194:                } catch (NoSuchAlgorithmException e) {
0195:                    throw new UnavailableException("No MD5");
0196:                }
0197:
0198:            }
0199:
0200:            // ------------------------------------------------------ Protected Methods
0201:
0202:            /**
0203:             * Return JAXP document builder instance.
0204:             */
0205:            protected DocumentBuilder getDocumentBuilder()
0206:                    throws ServletException {
0207:                DocumentBuilder documentBuilder = null;
0208:                DocumentBuilderFactory documentBuilderFactory = null;
0209:                try {
0210:                    documentBuilderFactory = DocumentBuilderFactory
0211:                            .newInstance();
0212:                    documentBuilderFactory.setNamespaceAware(true);
0213:                    documentBuilder = documentBuilderFactory
0214:                            .newDocumentBuilder();
0215:                } catch (ParserConfigurationException e) {
0216:                    throw new ServletException(sm
0217:                            .getString("webdavservlet.jaxpfailed"));
0218:                }
0219:                return documentBuilder;
0220:            }
0221:
0222:            /**
0223:             * Handles the special WebDAV methods.
0224:             */
0225:            protected void service(HttpServletRequest req,
0226:                    HttpServletResponse resp) throws ServletException,
0227:                    IOException {
0228:
0229:                String method = req.getMethod();
0230:
0231:                if (debug > 0) {
0232:                    String path = getRelativePath(req);
0233:                    log("[" + method + "] " + path);
0234:                }
0235:
0236:                if (method.equals(METHOD_PROPFIND)) {
0237:                    doPropfind(req, resp);
0238:                } else if (method.equals(METHOD_PROPPATCH)) {
0239:                    doProppatch(req, resp);
0240:                } else if (method.equals(METHOD_MKCOL)) {
0241:                    doMkcol(req, resp);
0242:                } else if (method.equals(METHOD_COPY)) {
0243:                    doCopy(req, resp);
0244:                } else if (method.equals(METHOD_MOVE)) {
0245:                    doMove(req, resp);
0246:                } else if (method.equals(METHOD_LOCK)) {
0247:                    doLock(req, resp);
0248:                } else if (method.equals(METHOD_UNLOCK)) {
0249:                    doUnlock(req, resp);
0250:                } else {
0251:                    // DefaultServlet processing
0252:                    super .service(req, resp);
0253:                }
0254:
0255:            }
0256:
0257:            /**
0258:             * Check if the conditions specified in the optional If headers are
0259:             * satisfied.
0260:             *
0261:             * @param request The servlet request we are processing
0262:             * @param response The servlet response we are creating
0263:             * @param resourceAttributes The resource information
0264:             * @return boolean true if the resource meets all the specified conditions,
0265:             * and false if any of the conditions is not satisfied, in which case
0266:             * request processing is stopped
0267:             */
0268:            protected boolean checkIfHeaders(HttpServletRequest request,
0269:                    HttpServletResponse response,
0270:                    ResourceAttributes resourceAttributes) throws IOException {
0271:
0272:                if (!super 
0273:                        .checkIfHeaders(request, response, resourceAttributes))
0274:                    return false;
0275:
0276:                // TODO : Checking the WebDAV If header
0277:                return true;
0278:
0279:            }
0280:
0281:            /**
0282:             * OPTIONS Method.
0283:             *
0284:             * @param req The request
0285:             * @param resp The response
0286:             * @throws ServletException If an error occurs
0287:             * @throws IOException If an IO error occurs
0288:             */
0289:            protected void doOptions(HttpServletRequest req,
0290:                    HttpServletResponse resp) throws ServletException,
0291:                    IOException {
0292:
0293:                resp.addHeader("DAV", "1,2");
0294:
0295:                StringBuffer methodsAllowed = determineMethodsAllowed(
0296:                        resources, req);
0297:
0298:                resp.addHeader("Allow", methodsAllowed.toString());
0299:                resp.addHeader("MS-Author-Via", "DAV");
0300:
0301:            }
0302:
0303:            /**
0304:             * PROPFIND Method.
0305:             */
0306:            protected void doPropfind(HttpServletRequest req,
0307:                    HttpServletResponse resp) throws ServletException,
0308:                    IOException {
0309:
0310:                if (!listings) {
0311:                    // Get allowed methods
0312:                    StringBuffer methodsAllowed = determineMethodsAllowed(
0313:                            resources, req);
0314:
0315:                    resp.addHeader("Allow", methodsAllowed.toString());
0316:                    resp.sendError(WebdavStatus.SC_METHOD_NOT_ALLOWED);
0317:                    return;
0318:                }
0319:
0320:                String path = getRelativePath(req);
0321:                if (path.endsWith("/"))
0322:                    path = path.substring(0, path.length() - 1);
0323:
0324:                if ((path.toUpperCase().startsWith("/WEB-INF"))
0325:                        || (path.toUpperCase().startsWith("/META-INF"))) {
0326:                    resp.sendError(WebdavStatus.SC_FORBIDDEN);
0327:                    return;
0328:                }
0329:
0330:                // Properties which are to be displayed.
0331:                Vector<String> properties = null;
0332:                // Propfind depth
0333:                int depth = INFINITY;
0334:                // Propfind type
0335:                int type = FIND_ALL_PROP;
0336:
0337:                String depthStr = req.getHeader("Depth");
0338:
0339:                if (depthStr == null) {
0340:                    depth = INFINITY;
0341:                } else {
0342:                    if (depthStr.equals("0")) {
0343:                        depth = 0;
0344:                    } else if (depthStr.equals("1")) {
0345:                        depth = 1;
0346:                    } else if (depthStr.equals("infinity")) {
0347:                        depth = INFINITY;
0348:                    }
0349:                }
0350:
0351:                Node propNode = null;
0352:
0353:                DocumentBuilder documentBuilder = getDocumentBuilder();
0354:
0355:                try {
0356:                    Document document = documentBuilder.parse(new InputSource(
0357:                            req.getInputStream()));
0358:
0359:                    // Get the root element of the document
0360:                    Element rootElement = document.getDocumentElement();
0361:                    NodeList childList = rootElement.getChildNodes();
0362:
0363:                    for (int i = 0; i < childList.getLength(); i++) {
0364:                        Node currentNode = childList.item(i);
0365:                        switch (currentNode.getNodeType()) {
0366:                        case Node.TEXT_NODE:
0367:                            break;
0368:                        case Node.ELEMENT_NODE:
0369:                            if (currentNode.getNodeName().endsWith("prop")) {
0370:                                type = FIND_BY_PROPERTY;
0371:                                propNode = currentNode;
0372:                            }
0373:                            if (currentNode.getNodeName().endsWith("propname")) {
0374:                                type = FIND_PROPERTY_NAMES;
0375:                            }
0376:                            if (currentNode.getNodeName().endsWith("allprop")) {
0377:                                type = FIND_ALL_PROP;
0378:                            }
0379:                            break;
0380:                        }
0381:                    }
0382:                } catch (SAXException e) {
0383:                    // Most likely there was no content : we use the defaults.
0384:                } catch (IOException e) {
0385:                    // Most likely there was no content : we use the defaults.
0386:                }
0387:
0388:                if (type == FIND_BY_PROPERTY) {
0389:                    properties = new Vector<String>();
0390:                    NodeList childList = propNode.getChildNodes();
0391:
0392:                    for (int i = 0; i < childList.getLength(); i++) {
0393:                        Node currentNode = childList.item(i);
0394:                        switch (currentNode.getNodeType()) {
0395:                        case Node.TEXT_NODE:
0396:                            break;
0397:                        case Node.ELEMENT_NODE:
0398:                            String nodeName = currentNode.getNodeName();
0399:                            String propertyName = null;
0400:                            if (nodeName.indexOf(':') != -1) {
0401:                                propertyName = nodeName.substring(nodeName
0402:                                        .indexOf(':') + 1);
0403:                            } else {
0404:                                propertyName = nodeName;
0405:                            }
0406:                            // href is a live property which is handled differently
0407:                            properties.addElement(propertyName);
0408:                            break;
0409:                        }
0410:                    }
0411:
0412:                }
0413:
0414:                boolean exists = true;
0415:                Object object = null;
0416:                try {
0417:                    object = resources.lookup(path);
0418:                } catch (NamingException e) {
0419:                    exists = false;
0420:                    int slash = path.lastIndexOf('/');
0421:                    if (slash != -1) {
0422:                        String parentPath = path.substring(0, slash);
0423:                        Vector currentLockNullResources = (Vector) lockNullResources
0424:                                .get(parentPath);
0425:                        if (currentLockNullResources != null) {
0426:                            Enumeration lockNullResourcesList = currentLockNullResources
0427:                                    .elements();
0428:                            while (lockNullResourcesList.hasMoreElements()) {
0429:                                String lockNullPath = (String) lockNullResourcesList
0430:                                        .nextElement();
0431:                                if (lockNullPath.equals(path)) {
0432:                                    resp
0433:                                            .setStatus(WebdavStatus.SC_MULTI_STATUS);
0434:                                    resp
0435:                                            .setContentType("text/xml; charset=UTF-8");
0436:                                    // Create multistatus object
0437:                                    XMLWriter generatedXML = new XMLWriter(resp
0438:                                            .getWriter());
0439:                                    generatedXML.writeXMLHeader();
0440:                                    generatedXML
0441:                                            .writeElement(
0442:                                                    null,
0443:                                                    "multistatus"
0444:                                                            + generateNamespaceDeclarations(),
0445:                                                    XMLWriter.OPENING);
0446:                                    parseLockNullProperties(req, generatedXML,
0447:                                            lockNullPath, type, properties);
0448:                                    generatedXML.writeElement(null,
0449:                                            "multistatus", XMLWriter.CLOSING);
0450:                                    generatedXML.sendData();
0451:                                    return;
0452:                                }
0453:                            }
0454:                        }
0455:                    }
0456:                }
0457:
0458:                if (!exists) {
0459:                    resp.sendError(HttpServletResponse.SC_NOT_FOUND, path);
0460:                    return;
0461:                }
0462:
0463:                resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
0464:
0465:                resp.setContentType("text/xml; charset=UTF-8");
0466:
0467:                // Create multistatus object
0468:                XMLWriter generatedXML = new XMLWriter(resp.getWriter());
0469:                generatedXML.writeXMLHeader();
0470:
0471:                generatedXML.writeElement(null, "multistatus"
0472:                        + generateNamespaceDeclarations(), XMLWriter.OPENING);
0473:
0474:                if (depth == 0) {
0475:                    parseProperties(req, generatedXML, path, type, properties);
0476:                } else {
0477:                    // The stack always contains the object of the current level
0478:                    Stack<String> stack = new Stack<String>();
0479:                    stack.push(path);
0480:
0481:                    // Stack of the objects one level below
0482:                    Stack<String> stackBelow = new Stack<String>();
0483:
0484:                    while ((!stack.isEmpty()) && (depth >= 0)) {
0485:
0486:                        String currentPath = (String) stack.pop();
0487:                        parseProperties(req, generatedXML, currentPath, type,
0488:                                properties);
0489:
0490:                        try {
0491:                            object = resources.lookup(currentPath);
0492:                        } catch (NamingException e) {
0493:                            continue;
0494:                        }
0495:
0496:                        if ((object instanceof  DirContext) && (depth > 0)) {
0497:
0498:                            try {
0499:                                NamingEnumeration enumeration = resources
0500:                                        .list(currentPath);
0501:                                while (enumeration.hasMoreElements()) {
0502:                                    NameClassPair ncPair = (NameClassPair) enumeration
0503:                                            .nextElement();
0504:                                    String newPath = currentPath;
0505:                                    if (!(newPath.endsWith("/")))
0506:                                        newPath += "/";
0507:                                    newPath += ncPair.getName();
0508:                                    stackBelow.push(newPath);
0509:                                }
0510:                            } catch (NamingException e) {
0511:                                resp
0512:                                        .sendError(
0513:                                                HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
0514:                                                path);
0515:                                return;
0516:                            }
0517:
0518:                            // Displaying the lock-null resources present in that
0519:                            // collection
0520:                            String lockPath = currentPath;
0521:                            if (lockPath.endsWith("/"))
0522:                                lockPath = lockPath.substring(0, lockPath
0523:                                        .length() - 1);
0524:                            Vector currentLockNullResources = (Vector) lockNullResources
0525:                                    .get(lockPath);
0526:                            if (currentLockNullResources != null) {
0527:                                Enumeration lockNullResourcesList = currentLockNullResources
0528:                                        .elements();
0529:                                while (lockNullResourcesList.hasMoreElements()) {
0530:                                    String lockNullPath = (String) lockNullResourcesList
0531:                                            .nextElement();
0532:                                    parseLockNullProperties(req, generatedXML,
0533:                                            lockNullPath, type, properties);
0534:                                }
0535:                            }
0536:
0537:                        }
0538:
0539:                        if (stack.isEmpty()) {
0540:                            depth--;
0541:                            stack = stackBelow;
0542:                            stackBelow = new Stack<String>();
0543:                        }
0544:
0545:                        generatedXML.sendData();
0546:
0547:                    }
0548:                }
0549:
0550:                generatedXML.writeElement(null, "multistatus",
0551:                        XMLWriter.CLOSING);
0552:
0553:                generatedXML.sendData();
0554:
0555:            }
0556:
0557:            /**
0558:             * PROPPATCH Method.
0559:             */
0560:            protected void doProppatch(HttpServletRequest req,
0561:                    HttpServletResponse resp) throws ServletException,
0562:                    IOException {
0563:
0564:                if (readOnly) {
0565:                    resp.sendError(WebdavStatus.SC_FORBIDDEN);
0566:                    return;
0567:                }
0568:
0569:                if (isLocked(req)) {
0570:                    resp.sendError(WebdavStatus.SC_LOCKED);
0571:                    return;
0572:                }
0573:
0574:                resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED);
0575:
0576:            }
0577:
0578:            /**
0579:             * MKCOL Method.
0580:             */
0581:            protected void doMkcol(HttpServletRequest req,
0582:                    HttpServletResponse resp) throws ServletException,
0583:                    IOException {
0584:
0585:                if (readOnly) {
0586:                    resp.sendError(WebdavStatus.SC_FORBIDDEN);
0587:                    return;
0588:                }
0589:
0590:                if (isLocked(req)) {
0591:                    resp.sendError(WebdavStatus.SC_LOCKED);
0592:                    return;
0593:                }
0594:
0595:                String path = getRelativePath(req);
0596:
0597:                if ((path.toUpperCase().startsWith("/WEB-INF"))
0598:                        || (path.toUpperCase().startsWith("/META-INF"))) {
0599:                    resp.sendError(WebdavStatus.SC_FORBIDDEN);
0600:                    return;
0601:                }
0602:
0603:                boolean exists = true;
0604:                Object object = null;
0605:                try {
0606:                    object = resources.lookup(path);
0607:                } catch (NamingException e) {
0608:                    exists = false;
0609:                }
0610:
0611:                // Can't create a collection if a resource already exists at the given
0612:                // path
0613:                if (exists) {
0614:                    // Get allowed methods
0615:                    StringBuffer methodsAllowed = determineMethodsAllowed(
0616:                            resources, req);
0617:
0618:                    resp.addHeader("Allow", methodsAllowed.toString());
0619:
0620:                    resp.sendError(WebdavStatus.SC_METHOD_NOT_ALLOWED);
0621:                    return;
0622:                }
0623:
0624:                if (req.getInputStream().available() > 0) {
0625:                    DocumentBuilder documentBuilder = getDocumentBuilder();
0626:                    try {
0627:                        Document document = documentBuilder
0628:                                .parse(new InputSource(req.getInputStream()));
0629:                        // TODO : Process this request body
0630:                        resp.sendError(WebdavStatus.SC_NOT_IMPLEMENTED);
0631:                        return;
0632:
0633:                    } catch (SAXException saxe) {
0634:                        // Parse error - assume invalid content
0635:                        resp.sendError(WebdavStatus.SC_BAD_REQUEST);
0636:                        return;
0637:                    }
0638:                }
0639:
0640:                boolean result = true;
0641:                try {
0642:                    resources.createSubcontext(path);
0643:                } catch (NamingException e) {
0644:                    result = false;
0645:                }
0646:
0647:                if (!result) {
0648:                    resp.sendError(WebdavStatus.SC_CONFLICT, WebdavStatus
0649:                            .getStatusText(WebdavStatus.SC_CONFLICT));
0650:                } else {
0651:                    resp.setStatus(WebdavStatus.SC_CREATED);
0652:                    // Removing any lock-null resource which would be present
0653:                    lockNullResources.remove(path);
0654:                }
0655:
0656:            }
0657:
0658:            /**
0659:             * DELETE Method.
0660:             */
0661:            protected void doDelete(HttpServletRequest req,
0662:                    HttpServletResponse resp) throws ServletException,
0663:                    IOException {
0664:
0665:                if (readOnly) {
0666:                    resp.sendError(WebdavStatus.SC_FORBIDDEN);
0667:                    return;
0668:                }
0669:
0670:                if (isLocked(req)) {
0671:                    resp.sendError(WebdavStatus.SC_LOCKED);
0672:                    return;
0673:                }
0674:
0675:                deleteResource(req, resp);
0676:
0677:            }
0678:
0679:            /**
0680:             * Process a POST request for the specified resource.
0681:             *
0682:             * @param req The servlet request we are processing
0683:             * @param resp The servlet response we are creating
0684:             *
0685:             * @exception IOException if an input/output error occurs
0686:             * @exception ServletException if a servlet-specified error occurs
0687:             */
0688:            protected void doPut(HttpServletRequest req,
0689:                    HttpServletResponse resp) throws ServletException,
0690:                    IOException {
0691:
0692:                if (isLocked(req)) {
0693:                    resp.sendError(WebdavStatus.SC_LOCKED);
0694:                    return;
0695:                }
0696:
0697:                super .doPut(req, resp);
0698:
0699:                String path = getRelativePath(req);
0700:
0701:                // Removing any lock-null resource which would be present
0702:                lockNullResources.remove(path);
0703:
0704:            }
0705:
0706:            /**
0707:             * COPY Method.
0708:             */
0709:            protected void doCopy(HttpServletRequest req,
0710:                    HttpServletResponse resp) throws ServletException,
0711:                    IOException {
0712:
0713:                if (readOnly) {
0714:                    resp.sendError(WebdavStatus.SC_FORBIDDEN);
0715:                    return;
0716:                }
0717:
0718:                copyResource(req, resp);
0719:
0720:            }
0721:
0722:            /**
0723:             * MOVE Method.
0724:             */
0725:            protected void doMove(HttpServletRequest req,
0726:                    HttpServletResponse resp) throws ServletException,
0727:                    IOException {
0728:
0729:                if (readOnly) {
0730:                    resp.sendError(WebdavStatus.SC_FORBIDDEN);
0731:                    return;
0732:                }
0733:
0734:                if (isLocked(req)) {
0735:                    resp.sendError(WebdavStatus.SC_LOCKED);
0736:                    return;
0737:                }
0738:
0739:                String path = getRelativePath(req);
0740:
0741:                if (copyResource(req, resp)) {
0742:                    deleteResource(path, req, resp, false);
0743:                }
0744:
0745:            }
0746:
0747:            /**
0748:             * LOCK Method.
0749:             */
0750:            protected void doLock(HttpServletRequest req,
0751:                    HttpServletResponse resp) throws ServletException,
0752:                    IOException {
0753:
0754:                if (readOnly) {
0755:                    resp.sendError(WebdavStatus.SC_FORBIDDEN);
0756:                    return;
0757:                }
0758:
0759:                if (isLocked(req)) {
0760:                    resp.sendError(WebdavStatus.SC_LOCKED);
0761:                    return;
0762:                }
0763:
0764:                LockInfo lock = new LockInfo();
0765:
0766:                // Parsing lock request
0767:
0768:                // Parsing depth header
0769:
0770:                String depthStr = req.getHeader("Depth");
0771:
0772:                if (depthStr == null) {
0773:                    lock.depth = INFINITY;
0774:                } else {
0775:                    if (depthStr.equals("0")) {
0776:                        lock.depth = 0;
0777:                    } else {
0778:                        lock.depth = INFINITY;
0779:                    }
0780:                }
0781:
0782:                // Parsing timeout header
0783:
0784:                int lockDuration = DEFAULT_TIMEOUT;
0785:                String lockDurationStr = req.getHeader("Timeout");
0786:                if (lockDurationStr == null) {
0787:                    lockDuration = DEFAULT_TIMEOUT;
0788:                } else {
0789:                    int commaPos = lockDurationStr.indexOf(",");
0790:                    // If multiple timeouts, just use the first
0791:                    if (commaPos != -1) {
0792:                        lockDurationStr = lockDurationStr
0793:                                .substring(0, commaPos);
0794:                    }
0795:                    if (lockDurationStr.startsWith("Second-")) {
0796:                        lockDuration = (new Integer(lockDurationStr
0797:                                .substring(7))).intValue();
0798:                    } else {
0799:                        if (lockDurationStr.equalsIgnoreCase("infinity")) {
0800:                            lockDuration = MAX_TIMEOUT;
0801:                        } else {
0802:                            try {
0803:                                lockDuration = (new Integer(lockDurationStr))
0804:                                        .intValue();
0805:                            } catch (NumberFormatException e) {
0806:                                lockDuration = MAX_TIMEOUT;
0807:                            }
0808:                        }
0809:                    }
0810:                    if (lockDuration == 0) {
0811:                        lockDuration = DEFAULT_TIMEOUT;
0812:                    }
0813:                    if (lockDuration > MAX_TIMEOUT) {
0814:                        lockDuration = MAX_TIMEOUT;
0815:                    }
0816:                }
0817:                lock.expiresAt = System.currentTimeMillis()
0818:                        + (lockDuration * 1000);
0819:
0820:                int lockRequestType = LOCK_CREATION;
0821:
0822:                Node lockInfoNode = null;
0823:
0824:                DocumentBuilder documentBuilder = getDocumentBuilder();
0825:
0826:                try {
0827:                    Document document = documentBuilder.parse(new InputSource(
0828:                            req.getInputStream()));
0829:
0830:                    // Get the root element of the document
0831:                    Element rootElement = document.getDocumentElement();
0832:                    lockInfoNode = rootElement;
0833:                } catch (IOException e) {
0834:                    lockRequestType = LOCK_REFRESH;
0835:                } catch (SAXException e) {
0836:                    lockRequestType = LOCK_REFRESH;
0837:                }
0838:
0839:                if (lockInfoNode != null) {
0840:
0841:                    // Reading lock information
0842:
0843:                    NodeList childList = lockInfoNode.getChildNodes();
0844:                    StringWriter strWriter = null;
0845:                    DOMWriter domWriter = null;
0846:
0847:                    Node lockScopeNode = null;
0848:                    Node lockTypeNode = null;
0849:                    Node lockOwnerNode = null;
0850:
0851:                    for (int i = 0; i < childList.getLength(); i++) {
0852:                        Node currentNode = childList.item(i);
0853:                        switch (currentNode.getNodeType()) {
0854:                        case Node.TEXT_NODE:
0855:                            break;
0856:                        case Node.ELEMENT_NODE:
0857:                            String nodeName = currentNode.getNodeName();
0858:                            if (nodeName.endsWith("lockscope")) {
0859:                                lockScopeNode = currentNode;
0860:                            }
0861:                            if (nodeName.endsWith("locktype")) {
0862:                                lockTypeNode = currentNode;
0863:                            }
0864:                            if (nodeName.endsWith("owner")) {
0865:                                lockOwnerNode = currentNode;
0866:                            }
0867:                            break;
0868:                        }
0869:                    }
0870:
0871:                    if (lockScopeNode != null) {
0872:
0873:                        childList = lockScopeNode.getChildNodes();
0874:                        for (int i = 0; i < childList.getLength(); i++) {
0875:                            Node currentNode = childList.item(i);
0876:                            switch (currentNode.getNodeType()) {
0877:                            case Node.TEXT_NODE:
0878:                                break;
0879:                            case Node.ELEMENT_NODE:
0880:                                String tempScope = currentNode.getNodeName();
0881:                                if (tempScope.indexOf(':') != -1) {
0882:                                    lock.scope = tempScope.substring(tempScope
0883:                                            .indexOf(':') + 1);
0884:                                } else {
0885:                                    lock.scope = tempScope;
0886:                                }
0887:                                break;
0888:                            }
0889:                        }
0890:
0891:                        if (lock.scope == null) {
0892:                            // Bad request
0893:                            resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
0894:                        }
0895:
0896:                    } else {
0897:                        // Bad request
0898:                        resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
0899:                    }
0900:
0901:                    if (lockTypeNode != null) {
0902:
0903:                        childList = lockTypeNode.getChildNodes();
0904:                        for (int i = 0; i < childList.getLength(); i++) {
0905:                            Node currentNode = childList.item(i);
0906:                            switch (currentNode.getNodeType()) {
0907:                            case Node.TEXT_NODE:
0908:                                break;
0909:                            case Node.ELEMENT_NODE:
0910:                                String tempType = currentNode.getNodeName();
0911:                                if (tempType.indexOf(':') != -1) {
0912:                                    lock.type = tempType.substring(tempType
0913:                                            .indexOf(':') + 1);
0914:                                } else {
0915:                                    lock.type = tempType;
0916:                                }
0917:                                break;
0918:                            }
0919:                        }
0920:
0921:                        if (lock.type == null) {
0922:                            // Bad request
0923:                            resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
0924:                        }
0925:
0926:                    } else {
0927:                        // Bad request
0928:                        resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
0929:                    }
0930:
0931:                    if (lockOwnerNode != null) {
0932:
0933:                        childList = lockOwnerNode.getChildNodes();
0934:                        for (int i = 0; i < childList.getLength(); i++) {
0935:                            Node currentNode = childList.item(i);
0936:                            switch (currentNode.getNodeType()) {
0937:                            case Node.TEXT_NODE:
0938:                                lock.owner += currentNode.getNodeValue();
0939:                                break;
0940:                            case Node.ELEMENT_NODE:
0941:                                strWriter = new StringWriter();
0942:                                domWriter = new DOMWriter(strWriter, true);
0943:                                domWriter.setQualifiedNames(false);
0944:                                domWriter.print(currentNode);
0945:                                lock.owner += strWriter.toString();
0946:                                break;
0947:                            }
0948:                        }
0949:
0950:                        if (lock.owner == null) {
0951:                            // Bad request
0952:                            resp.setStatus(WebdavStatus.SC_BAD_REQUEST);
0953:                        }
0954:
0955:                    } else {
0956:                        lock.owner = new String();
0957:                    }
0958:
0959:                }
0960:
0961:                String path = getRelativePath(req);
0962:
0963:                lock.path = path;
0964:
0965:                boolean exists = true;
0966:                Object object = null;
0967:                try {
0968:                    object = resources.lookup(path);
0969:                } catch (NamingException e) {
0970:                    exists = false;
0971:                }
0972:
0973:                Enumeration locksList = null;
0974:
0975:                if (lockRequestType == LOCK_CREATION) {
0976:
0977:                    // Generating lock id
0978:                    String lockTokenStr = req.getServletPath() + "-"
0979:                            + lock.type + "-" + lock.scope + "-"
0980:                            + req.getUserPrincipal() + "-" + lock.depth + "-"
0981:                            + lock.owner + "-" + lock.tokens + "-"
0982:                            + lock.expiresAt + "-" + System.currentTimeMillis()
0983:                            + "-" + secret;
0984:                    String lockToken = md5Encoder.encode(md5Helper
0985:                            .digest(lockTokenStr.getBytes()));
0986:
0987:                    if ((exists) && (object instanceof  DirContext)
0988:                            && (lock.depth == INFINITY)) {
0989:
0990:                        // Locking a collection (and all its member resources)
0991:
0992:                        // Checking if a child resource of this collection is
0993:                        // already locked
0994:                        Vector<String> lockPaths = new Vector<String>();
0995:                        locksList = collectionLocks.elements();
0996:                        while (locksList.hasMoreElements()) {
0997:                            LockInfo currentLock = (LockInfo) locksList
0998:                                    .nextElement();
0999:                            if (currentLock.hasExpired()) {
1000:                                resourceLocks.remove(currentLock.path);
1001:                                continue;
1002:                            }
1003:                            if ((currentLock.path.startsWith(lock.path))
1004:                                    && ((currentLock.isExclusive()) || (lock
1005:                                            .isExclusive()))) {
1006:                                // A child collection of this collection is locked
1007:                                lockPaths.addElement(currentLock.path);
1008:                            }
1009:                        }
1010:                        locksList = resourceLocks.elements();
1011:                        while (locksList.hasMoreElements()) {
1012:                            LockInfo currentLock = (LockInfo) locksList
1013:                                    .nextElement();
1014:                            if (currentLock.hasExpired()) {
1015:                                resourceLocks.remove(currentLock.path);
1016:                                continue;
1017:                            }
1018:                            if ((currentLock.path.startsWith(lock.path))
1019:                                    && ((currentLock.isExclusive()) || (lock
1020:                                            .isExclusive()))) {
1021:                                // A child resource of this collection is locked
1022:                                lockPaths.addElement(currentLock.path);
1023:                            }
1024:                        }
1025:
1026:                        if (!lockPaths.isEmpty()) {
1027:
1028:                            // One of the child paths was locked
1029:                            // We generate a multistatus error report
1030:
1031:                            Enumeration lockPathsList = lockPaths.elements();
1032:
1033:                            resp.setStatus(WebdavStatus.SC_CONFLICT);
1034:
1035:                            XMLWriter generatedXML = new XMLWriter();
1036:                            generatedXML.writeXMLHeader();
1037:
1038:                            generatedXML.writeElement(null, "multistatus"
1039:                                    + generateNamespaceDeclarations(),
1040:                                    XMLWriter.OPENING);
1041:
1042:                            while (lockPathsList.hasMoreElements()) {
1043:                                generatedXML.writeElement(null, "response",
1044:                                        XMLWriter.OPENING);
1045:                                generatedXML.writeElement(null, "href",
1046:                                        XMLWriter.OPENING);
1047:                                generatedXML.writeText((String) lockPathsList
1048:                                        .nextElement());
1049:                                generatedXML.writeElement(null, "href",
1050:                                        XMLWriter.CLOSING);
1051:                                generatedXML.writeElement(null, "status",
1052:                                        XMLWriter.OPENING);
1053:                                generatedXML
1054:                                        .writeText("HTTP/1.1 "
1055:                                                + WebdavStatus.SC_LOCKED
1056:                                                + " "
1057:                                                + WebdavStatus
1058:                                                        .getStatusText(WebdavStatus.SC_LOCKED));
1059:                                generatedXML.writeElement(null, "status",
1060:                                        XMLWriter.CLOSING);
1061:
1062:                                generatedXML.writeElement(null, "response",
1063:                                        XMLWriter.CLOSING);
1064:                            }
1065:
1066:                            generatedXML.writeElement(null, "multistatus",
1067:                                    XMLWriter.CLOSING);
1068:
1069:                            Writer writer = resp.getWriter();
1070:                            writer.write(generatedXML.toString());
1071:                            writer.close();
1072:
1073:                            return;
1074:
1075:                        }
1076:
1077:                        boolean addLock = true;
1078:
1079:                        // Checking if there is already a shared lock on this path
1080:                        locksList = collectionLocks.elements();
1081:                        while (locksList.hasMoreElements()) {
1082:
1083:                            LockInfo currentLock = (LockInfo) locksList
1084:                                    .nextElement();
1085:                            if (currentLock.path.equals(lock.path)) {
1086:
1087:                                if (currentLock.isExclusive()) {
1088:                                    resp.sendError(WebdavStatus.SC_LOCKED);
1089:                                    return;
1090:                                } else {
1091:                                    if (lock.isExclusive()) {
1092:                                        resp.sendError(WebdavStatus.SC_LOCKED);
1093:                                        return;
1094:                                    }
1095:                                }
1096:
1097:                                currentLock.tokens.addElement(lockToken);
1098:                                lock = currentLock;
1099:                                addLock = false;
1100:
1101:                            }
1102:
1103:                        }
1104:
1105:                        if (addLock) {
1106:                            lock.tokens.addElement(lockToken);
1107:                            collectionLocks.addElement(lock);
1108:                        }
1109:
1110:                    } else {
1111:
1112:                        // Locking a single resource
1113:
1114:                        // Retrieving an already existing lock on that resource
1115:                        LockInfo presentLock = (LockInfo) resourceLocks
1116:                                .get(lock.path);
1117:                        if (presentLock != null) {
1118:
1119:                            if ((presentLock.isExclusive())
1120:                                    || (lock.isExclusive())) {
1121:                                // If either lock is exclusive, the lock can't be
1122:                                // granted
1123:                                resp
1124:                                        .sendError(WebdavStatus.SC_PRECONDITION_FAILED);
1125:                                return;
1126:                            } else {
1127:                                presentLock.tokens.addElement(lockToken);
1128:                                lock = presentLock;
1129:                            }
1130:
1131:                        } else {
1132:
1133:                            lock.tokens.addElement(lockToken);
1134:                            resourceLocks.put(lock.path, lock);
1135:
1136:                            // Checking if a resource exists at this path
1137:                            exists = true;
1138:                            try {
1139:                                object = resources.lookup(path);
1140:                            } catch (NamingException e) {
1141:                                exists = false;
1142:                            }
1143:                            if (!exists) {
1144:
1145:                                // "Creating" a lock-null resource
1146:                                int slash = lock.path.lastIndexOf('/');
1147:                                String parentPath = lock.path.substring(0,
1148:                                        slash);
1149:
1150:                                Vector<String> lockNulls = lockNullResources
1151:                                        .get(parentPath);
1152:                                if (lockNulls == null) {
1153:                                    lockNulls = new Vector<String>();
1154:                                    lockNullResources
1155:                                            .put(parentPath, lockNulls);
1156:                                }
1157:
1158:                                lockNulls.addElement(lock.path);
1159:
1160:                            }
1161:                            // Add the Lock-Token header as by RFC 2518 8.10.1
1162:                            // - only do this for newly created locks
1163:                            resp.addHeader("Lock-Token", "<opaquelocktoken:"
1164:                                    + lockToken + ">");
1165:                        }
1166:
1167:                    }
1168:
1169:                }
1170:
1171:                if (lockRequestType == LOCK_REFRESH) {
1172:
1173:                    String ifHeader = req.getHeader("If");
1174:                    if (ifHeader == null)
1175:                        ifHeader = "";
1176:
1177:                    // Checking resource locks
1178:
1179:                    LockInfo toRenew = (LockInfo) resourceLocks.get(path);
1180:                    Enumeration tokenList = null;
1181:                    if (lock != null) {
1182:
1183:                        // At least one of the tokens of the locks must have been given
1184:
1185:                        tokenList = toRenew.tokens.elements();
1186:                        while (tokenList.hasMoreElements()) {
1187:                            String token = (String) tokenList.nextElement();
1188:                            if (ifHeader.indexOf(token) != -1) {
1189:                                toRenew.expiresAt = lock.expiresAt;
1190:                                lock = toRenew;
1191:                            }
1192:                        }
1193:
1194:                    }
1195:
1196:                    // Checking inheritable collection locks
1197:
1198:                    Enumeration collectionLocksList = collectionLocks
1199:                            .elements();
1200:                    while (collectionLocksList.hasMoreElements()) {
1201:                        toRenew = (LockInfo) collectionLocksList.nextElement();
1202:                        if (path.equals(toRenew.path)) {
1203:
1204:                            tokenList = toRenew.tokens.elements();
1205:                            while (tokenList.hasMoreElements()) {
1206:                                String token = (String) tokenList.nextElement();
1207:                                if (ifHeader.indexOf(token) != -1) {
1208:                                    toRenew.expiresAt = lock.expiresAt;
1209:                                    lock = toRenew;
1210:                                }
1211:                            }
1212:
1213:                        }
1214:                    }
1215:
1216:                }
1217:
1218:                // Set the status, then generate the XML response containing
1219:                // the lock information
1220:                XMLWriter generatedXML = new XMLWriter();
1221:                generatedXML.writeXMLHeader();
1222:                generatedXML.writeElement(null, "prop"
1223:                        + generateNamespaceDeclarations(), XMLWriter.OPENING);
1224:
1225:                generatedXML.writeElement(null, "lockdiscovery",
1226:                        XMLWriter.OPENING);
1227:
1228:                lock.toXML(generatedXML);
1229:
1230:                generatedXML.writeElement(null, "lockdiscovery",
1231:                        XMLWriter.CLOSING);
1232:
1233:                generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
1234:
1235:                resp.setStatus(WebdavStatus.SC_OK);
1236:                resp.setContentType("text/xml; charset=UTF-8");
1237:                Writer writer = resp.getWriter();
1238:                writer.write(generatedXML.toString());
1239:                writer.close();
1240:
1241:            }
1242:
1243:            /**
1244:             * UNLOCK Method.
1245:             */
1246:            protected void doUnlock(HttpServletRequest req,
1247:                    HttpServletResponse resp) throws ServletException,
1248:                    IOException {
1249:
1250:                if (readOnly) {
1251:                    resp.sendError(WebdavStatus.SC_FORBIDDEN);
1252:                    return;
1253:                }
1254:
1255:                if (isLocked(req)) {
1256:                    resp.sendError(WebdavStatus.SC_LOCKED);
1257:                    return;
1258:                }
1259:
1260:                String path = getRelativePath(req);
1261:
1262:                String lockTokenHeader = req.getHeader("Lock-Token");
1263:                if (lockTokenHeader == null)
1264:                    lockTokenHeader = "";
1265:
1266:                // Checking resource locks
1267:
1268:                LockInfo lock = (LockInfo) resourceLocks.get(path);
1269:                Enumeration tokenList = null;
1270:                if (lock != null) {
1271:
1272:                    // At least one of the tokens of the locks must have been given
1273:
1274:                    tokenList = lock.tokens.elements();
1275:                    while (tokenList.hasMoreElements()) {
1276:                        String token = (String) tokenList.nextElement();
1277:                        if (lockTokenHeader.indexOf(token) != -1) {
1278:                            lock.tokens.removeElement(token);
1279:                        }
1280:                    }
1281:
1282:                    if (lock.tokens.isEmpty()) {
1283:                        resourceLocks.remove(path);
1284:                        // Removing any lock-null resource which would be present
1285:                        lockNullResources.remove(path);
1286:                    }
1287:
1288:                }
1289:
1290:                // Checking inheritable collection locks
1291:
1292:                Enumeration collectionLocksList = collectionLocks.elements();
1293:                while (collectionLocksList.hasMoreElements()) {
1294:                    lock = (LockInfo) collectionLocksList.nextElement();
1295:                    if (path.equals(lock.path)) {
1296:
1297:                        tokenList = lock.tokens.elements();
1298:                        while (tokenList.hasMoreElements()) {
1299:                            String token = (String) tokenList.nextElement();
1300:                            if (lockTokenHeader.indexOf(token) != -1) {
1301:                                lock.tokens.removeElement(token);
1302:                                break;
1303:                            }
1304:                        }
1305:
1306:                        if (lock.tokens.isEmpty()) {
1307:                            collectionLocks.removeElement(lock);
1308:                            // Removing any lock-null resource which would be present
1309:                            lockNullResources.remove(path);
1310:                        }
1311:
1312:                    }
1313:                }
1314:
1315:                resp.setStatus(WebdavStatus.SC_NO_CONTENT);
1316:
1317:            }
1318:
1319:            /**
1320:             * Return a context-relative path, beginning with a "/", that represents
1321:             * the canonical version of the specified path after ".." and "." elements
1322:             * are resolved out.  If the specified path attempts to go outside the
1323:             * boundaries of the current context (i.e. too many ".." path elements
1324:             * are present), return <code>null</code> instead.
1325:             *
1326:             * @param path Path to be normalized
1327:             */
1328:            protected String normalize(String path) {
1329:
1330:                if (path == null)
1331:                    return null;
1332:
1333:                // Create a place for the normalized path
1334:                String normalized = path;
1335:
1336:                if (normalized == null)
1337:                    return (null);
1338:
1339:                if (normalized.equals("/."))
1340:                    return "/";
1341:
1342:                // Normalize the slashes and add leading slash if necessary
1343:                if (normalized.indexOf('\\') >= 0)
1344:                    normalized = normalized.replace('\\', '/');
1345:                if (!normalized.startsWith("/"))
1346:                    normalized = "/" + normalized;
1347:
1348:                // Resolve occurrences of "//" in the normalized path
1349:                while (true) {
1350:                    int index = normalized.indexOf("//");
1351:                    if (index < 0)
1352:                        break;
1353:                    normalized = normalized.substring(0, index)
1354:                            + normalized.substring(index + 1);
1355:                }
1356:
1357:                // Resolve occurrences of "/./" in the normalized path
1358:                while (true) {
1359:                    int index = normalized.indexOf("/./");
1360:                    if (index < 0)
1361:                        break;
1362:                    normalized = normalized.substring(0, index)
1363:                            + normalized.substring(index + 2);
1364:                }
1365:
1366:                // Resolve occurrences of "/../" in the normalized path
1367:                while (true) {
1368:                    int index = normalized.indexOf("/../");
1369:                    if (index < 0)
1370:                        break;
1371:                    if (index == 0)
1372:                        return (null); // Trying to go outside our context
1373:                    int index2 = normalized.lastIndexOf('/', index - 1);
1374:                    normalized = normalized.substring(0, index2)
1375:                            + normalized.substring(index + 3);
1376:                }
1377:
1378:                // Return the normalized path that we have completed
1379:                return (normalized);
1380:
1381:            }
1382:
1383:            // -------------------------------------------------------- Private Methods
1384:
1385:            /**
1386:             * Generate the namespace declarations.
1387:             */
1388:            private String generateNamespaceDeclarations() {
1389:                return " xmlns=\"" + DEFAULT_NAMESPACE + "\"";
1390:            }
1391:
1392:            /**
1393:             * Check to see if a resource is currently write locked. The method
1394:             * will look at the "If" header to make sure the client
1395:             * has give the appropriate lock tokens.
1396:             *
1397:             * @param req Servlet request
1398:             * @return boolean true if the resource is locked (and no appropriate
1399:             * lock token has been found for at least one of the non-shared locks which
1400:             * are present on the resource).
1401:             */
1402:            private boolean isLocked(HttpServletRequest req) {
1403:
1404:                String path = getRelativePath(req);
1405:
1406:                String ifHeader = req.getHeader("If");
1407:                if (ifHeader == null)
1408:                    ifHeader = "";
1409:
1410:                String lockTokenHeader = req.getHeader("Lock-Token");
1411:                if (lockTokenHeader == null)
1412:                    lockTokenHeader = "";
1413:
1414:                return isLocked(path, ifHeader + lockTokenHeader);
1415:
1416:            }
1417:
1418:            /**
1419:             * Check to see if a resource is currently write locked.
1420:             *
1421:             * @param path Path of the resource
1422:             * @param ifHeader "If" HTTP header which was included in the request
1423:             * @return boolean true if the resource is locked (and no appropriate
1424:             * lock token has been found for at least one of the non-shared locks which
1425:             * are present on the resource).
1426:             */
1427:            private boolean isLocked(String path, String ifHeader) {
1428:
1429:                // Checking resource locks
1430:
1431:                LockInfo lock = (LockInfo) resourceLocks.get(path);
1432:                Enumeration tokenList = null;
1433:                if ((lock != null) && (lock.hasExpired())) {
1434:                    resourceLocks.remove(path);
1435:                } else if (lock != null) {
1436:
1437:                    // At least one of the tokens of the locks must have been given
1438:
1439:                    tokenList = lock.tokens.elements();
1440:                    boolean tokenMatch = false;
1441:                    while (tokenList.hasMoreElements()) {
1442:                        String token = (String) tokenList.nextElement();
1443:                        if (ifHeader.indexOf(token) != -1)
1444:                            tokenMatch = true;
1445:                    }
1446:                    if (!tokenMatch)
1447:                        return true;
1448:
1449:                }
1450:
1451:                // Checking inheritable collection locks
1452:
1453:                Enumeration collectionLocksList = collectionLocks.elements();
1454:                while (collectionLocksList.hasMoreElements()) {
1455:                    lock = (LockInfo) collectionLocksList.nextElement();
1456:                    if (lock.hasExpired()) {
1457:                        collectionLocks.removeElement(lock);
1458:                    } else if (path.startsWith(lock.path)) {
1459:
1460:                        tokenList = lock.tokens.elements();
1461:                        boolean tokenMatch = false;
1462:                        while (tokenList.hasMoreElements()) {
1463:                            String token = (String) tokenList.nextElement();
1464:                            if (ifHeader.indexOf(token) != -1)
1465:                                tokenMatch = true;
1466:                        }
1467:                        if (!tokenMatch)
1468:                            return true;
1469:
1470:                    }
1471:                }
1472:
1473:                return false;
1474:
1475:            }
1476:
1477:            /**
1478:             * Copy a resource.
1479:             *
1480:             * @param req Servlet request
1481:             * @param resp Servlet response
1482:             * @return boolean true if the copy is successful
1483:             */
1484:            private boolean copyResource(HttpServletRequest req,
1485:                    HttpServletResponse resp) throws ServletException,
1486:                    IOException {
1487:
1488:                // Parsing destination header
1489:
1490:                String destinationPath = req.getHeader("Destination");
1491:
1492:                if (destinationPath == null) {
1493:                    resp.sendError(WebdavStatus.SC_BAD_REQUEST);
1494:                    return false;
1495:                }
1496:
1497:                // Remove url encoding from destination
1498:                destinationPath = RequestUtil
1499:                        .URLDecode(destinationPath, "UTF8");
1500:
1501:                int protocolIndex = destinationPath.indexOf("://");
1502:                if (protocolIndex >= 0) {
1503:                    // if the Destination URL contains the protocol, we can safely
1504:                    // trim everything upto the first "/" character after "://"
1505:                    int firstSeparator = destinationPath.indexOf("/",
1506:                            protocolIndex + 4);
1507:                    if (firstSeparator < 0) {
1508:                        destinationPath = "/";
1509:                    } else {
1510:                        destinationPath = destinationPath
1511:                                .substring(firstSeparator);
1512:                    }
1513:                } else {
1514:                    String hostName = req.getServerName();
1515:                    if ((hostName != null)
1516:                            && (destinationPath.startsWith(hostName))) {
1517:                        destinationPath = destinationPath.substring(hostName
1518:                                .length());
1519:                    }
1520:
1521:                    int portIndex = destinationPath.indexOf(":");
1522:                    if (portIndex >= 0) {
1523:                        destinationPath = destinationPath.substring(portIndex);
1524:                    }
1525:
1526:                    if (destinationPath.startsWith(":")) {
1527:                        int firstSeparator = destinationPath.indexOf("/");
1528:                        if (firstSeparator < 0) {
1529:                            destinationPath = "/";
1530:                        } else {
1531:                            destinationPath = destinationPath
1532:                                    .substring(firstSeparator);
1533:                        }
1534:                    }
1535:                }
1536:
1537:                // Normalise destination path (remove '.' and '..')
1538:                destinationPath = normalize(destinationPath);
1539:
1540:                String contextPath = req.getContextPath();
1541:                if ((contextPath != null)
1542:                        && (destinationPath.startsWith(contextPath))) {
1543:                    destinationPath = destinationPath.substring(contextPath
1544:                            .length());
1545:                }
1546:
1547:                String pathInfo = req.getPathInfo();
1548:                if (pathInfo != null) {
1549:                    String servletPath = req.getServletPath();
1550:                    if ((servletPath != null)
1551:                            && (destinationPath.startsWith(servletPath))) {
1552:                        destinationPath = destinationPath.substring(servletPath
1553:                                .length());
1554:                    }
1555:                }
1556:
1557:                if (debug > 0)
1558:                    log("Dest path :" + destinationPath);
1559:
1560:                if ((destinationPath.toUpperCase().startsWith("/WEB-INF"))
1561:                        || (destinationPath.toUpperCase()
1562:                                .startsWith("/META-INF"))) {
1563:                    resp.sendError(WebdavStatus.SC_FORBIDDEN);
1564:                    return false;
1565:                }
1566:
1567:                String path = getRelativePath(req);
1568:
1569:                if ((path.toUpperCase().startsWith("/WEB-INF"))
1570:                        || (path.toUpperCase().startsWith("/META-INF"))) {
1571:                    resp.sendError(WebdavStatus.SC_FORBIDDEN);
1572:                    return false;
1573:                }
1574:
1575:                if (destinationPath.equals(path)) {
1576:                    resp.sendError(WebdavStatus.SC_FORBIDDEN);
1577:                    return false;
1578:                }
1579:
1580:                // Parsing overwrite header
1581:
1582:                boolean overwrite = true;
1583:                String overwriteHeader = req.getHeader("Overwrite");
1584:
1585:                if (overwriteHeader != null) {
1586:                    if (overwriteHeader.equalsIgnoreCase("T")) {
1587:                        overwrite = true;
1588:                    } else {
1589:                        overwrite = false;
1590:                    }
1591:                }
1592:
1593:                // Overwriting the destination
1594:
1595:                boolean exists = true;
1596:                try {
1597:                    resources.lookup(destinationPath);
1598:                } catch (NamingException e) {
1599:                    exists = false;
1600:                }
1601:
1602:                if (overwrite) {
1603:
1604:                    // Delete destination resource, if it exists
1605:                    if (exists) {
1606:                        if (!deleteResource(destinationPath, req, resp, true)) {
1607:                            return false;
1608:                        }
1609:                    } else {
1610:                        resp.setStatus(WebdavStatus.SC_CREATED);
1611:                    }
1612:
1613:                } else {
1614:
1615:                    // If the destination exists, then it's a conflict
1616:                    if (exists) {
1617:                        resp.sendError(WebdavStatus.SC_PRECONDITION_FAILED);
1618:                        return false;
1619:                    }
1620:
1621:                }
1622:
1623:                // Copying source to destination
1624:
1625:                Hashtable<String, Integer> errorList = new Hashtable<String, Integer>();
1626:
1627:                boolean result = copyResource(resources, errorList, path,
1628:                        destinationPath);
1629:
1630:                if ((!result) || (!errorList.isEmpty())) {
1631:
1632:                    sendReport(req, resp, errorList);
1633:                    return false;
1634:
1635:                }
1636:
1637:                // Removing any lock-null resource which would be present at
1638:                // the destination path
1639:                lockNullResources.remove(destinationPath);
1640:
1641:                return true;
1642:
1643:            }
1644:
1645:            /**
1646:             * Copy a collection.
1647:             *
1648:             * @param resources Resources implementation to be used
1649:             * @param errorList Hashtable containing the list of errors which occurred
1650:             * during the copy operation
1651:             * @param source Path of the resource to be copied
1652:             * @param dest Destination path
1653:             */
1654:            private boolean copyResource(DirContext resources,
1655:                    Hashtable<String, Integer> errorList, String source,
1656:                    String dest) {
1657:
1658:                if (debug > 1)
1659:                    log("Copy: " + source + " To: " + dest);
1660:
1661:                Object object = null;
1662:                try {
1663:                    object = resources.lookup(source);
1664:                } catch (NamingException e) {
1665:                }
1666:
1667:                if (object instanceof  DirContext) {
1668:
1669:                    try {
1670:                        resources.createSubcontext(dest);
1671:                    } catch (NamingException e) {
1672:                        errorList.put(dest, new Integer(
1673:                                WebdavStatus.SC_CONFLICT));
1674:                        return false;
1675:                    }
1676:
1677:                    try {
1678:                        NamingEnumeration enumeration = resources.list(source);
1679:                        while (enumeration.hasMoreElements()) {
1680:                            NameClassPair ncPair = (NameClassPair) enumeration
1681:                                    .nextElement();
1682:                            String childDest = dest;
1683:                            if (!childDest.equals("/"))
1684:                                childDest += "/";
1685:                            childDest += ncPair.getName();
1686:                            String childSrc = source;
1687:                            if (!childSrc.equals("/"))
1688:                                childSrc += "/";
1689:                            childSrc += ncPair.getName();
1690:                            copyResource(resources, errorList, childSrc,
1691:                                    childDest);
1692:                        }
1693:                    } catch (NamingException e) {
1694:                        errorList.put(dest, new Integer(
1695:                                WebdavStatus.SC_INTERNAL_SERVER_ERROR));
1696:                        return false;
1697:                    }
1698:
1699:                } else {
1700:
1701:                    if (object instanceof  Resource) {
1702:                        try {
1703:                            resources.bind(dest, object);
1704:                        } catch (NamingException e) {
1705:                            errorList.put(source, new Integer(
1706:                                    WebdavStatus.SC_INTERNAL_SERVER_ERROR));
1707:                            return false;
1708:                        }
1709:                    } else {
1710:                        errorList.put(source, new Integer(
1711:                                WebdavStatus.SC_INTERNAL_SERVER_ERROR));
1712:                        return false;
1713:                    }
1714:
1715:                }
1716:
1717:                return true;
1718:
1719:            }
1720:
1721:            /**
1722:             * Delete a resource.
1723:             *
1724:             * @param req Servlet request
1725:             * @param resp Servlet response
1726:             * @return boolean true if the copy is successful
1727:             */
1728:            private boolean deleteResource(HttpServletRequest req,
1729:                    HttpServletResponse resp) throws ServletException,
1730:                    IOException {
1731:
1732:                String path = getRelativePath(req);
1733:
1734:                return deleteResource(path, req, resp, true);
1735:
1736:            }
1737:
1738:            /**
1739:             * Delete a resource.
1740:             *
1741:             * @param path Path of the resource which is to be deleted
1742:             * @param req Servlet request
1743:             * @param resp Servlet response
1744:             * @param setStatus Should the response status be set on successful
1745:             *                  completion
1746:             */
1747:            private boolean deleteResource(String path, HttpServletRequest req,
1748:                    HttpServletResponse resp, boolean setStatus)
1749:                    throws ServletException, IOException {
1750:
1751:                if ((path.toUpperCase().startsWith("/WEB-INF"))
1752:                        || (path.toUpperCase().startsWith("/META-INF"))) {
1753:                    resp.sendError(WebdavStatus.SC_FORBIDDEN);
1754:                    return false;
1755:                }
1756:
1757:                String ifHeader = req.getHeader("If");
1758:                if (ifHeader == null)
1759:                    ifHeader = "";
1760:
1761:                String lockTokenHeader = req.getHeader("Lock-Token");
1762:                if (lockTokenHeader == null)
1763:                    lockTokenHeader = "";
1764:
1765:                if (isLocked(path, ifHeader + lockTokenHeader)) {
1766:                    resp.sendError(WebdavStatus.SC_LOCKED);
1767:                    return false;
1768:                }
1769:
1770:                boolean exists = true;
1771:                Object object = null;
1772:                try {
1773:                    object = resources.lookup(path);
1774:                } catch (NamingException e) {
1775:                    exists = false;
1776:                }
1777:
1778:                if (!exists) {
1779:                    resp.sendError(WebdavStatus.SC_NOT_FOUND);
1780:                    return false;
1781:                }
1782:
1783:                boolean collection = (object instanceof  DirContext);
1784:
1785:                if (!collection) {
1786:                    try {
1787:                        resources.unbind(path);
1788:                    } catch (NamingException e) {
1789:                        resp.sendError(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
1790:                        return false;
1791:                    }
1792:                } else {
1793:
1794:                    Hashtable<String, Integer> errorList = new Hashtable<String, Integer>();
1795:
1796:                    deleteCollection(req, resources, path, errorList);
1797:                    try {
1798:                        resources.unbind(path);
1799:                    } catch (NamingException e) {
1800:                        errorList.put(path, new Integer(
1801:                                WebdavStatus.SC_INTERNAL_SERVER_ERROR));
1802:                    }
1803:
1804:                    if (!errorList.isEmpty()) {
1805:
1806:                        sendReport(req, resp, errorList);
1807:                        return false;
1808:
1809:                    }
1810:
1811:                }
1812:                if (setStatus) {
1813:                    resp.setStatus(WebdavStatus.SC_NO_CONTENT);
1814:                }
1815:                return true;
1816:
1817:            }
1818:
1819:            /**
1820:             * Deletes a collection.
1821:             *
1822:             * @param resources Resources implementation associated with the context
1823:             * @param path Path to the collection to be deleted
1824:             * @param errorList Contains the list of the errors which occurred
1825:             */
1826:            private void deleteCollection(HttpServletRequest req,
1827:                    DirContext resources, String path,
1828:                    Hashtable<String, Integer> errorList) {
1829:
1830:                if (debug > 1)
1831:                    log("Delete:" + path);
1832:
1833:                if ((path.toUpperCase().startsWith("/WEB-INF"))
1834:                        || (path.toUpperCase().startsWith("/META-INF"))) {
1835:                    errorList.put(path, new Integer(WebdavStatus.SC_FORBIDDEN));
1836:                    return;
1837:                }
1838:
1839:                String ifHeader = req.getHeader("If");
1840:                if (ifHeader == null)
1841:                    ifHeader = "";
1842:
1843:                String lockTokenHeader = req.getHeader("Lock-Token");
1844:                if (lockTokenHeader == null)
1845:                    lockTokenHeader = "";
1846:
1847:                Enumeration enumeration = null;
1848:                try {
1849:                    enumeration = resources.list(path);
1850:                } catch (NamingException e) {
1851:                    errorList.put(path, new Integer(
1852:                            WebdavStatus.SC_INTERNAL_SERVER_ERROR));
1853:                    return;
1854:                }
1855:
1856:                while (enumeration.hasMoreElements()) {
1857:                    NameClassPair ncPair = (NameClassPair) enumeration
1858:                            .nextElement();
1859:                    String childName = path;
1860:                    if (!childName.equals("/"))
1861:                        childName += "/";
1862:                    childName += ncPair.getName();
1863:
1864:                    if (isLocked(childName, ifHeader + lockTokenHeader)) {
1865:
1866:                        errorList.put(childName, new Integer(
1867:                                WebdavStatus.SC_LOCKED));
1868:
1869:                    } else {
1870:
1871:                        try {
1872:                            Object object = resources.lookup(childName);
1873:                            if (object instanceof  DirContext) {
1874:                                deleteCollection(req, resources, childName,
1875:                                        errorList);
1876:                            }
1877:
1878:                            try {
1879:                                resources.unbind(childName);
1880:                            } catch (NamingException e) {
1881:                                if (!(object instanceof  DirContext)) {
1882:                                    // If it's not a collection, then it's an unknown
1883:                                    // error
1884:                                    errorList
1885:                                            .put(
1886:                                                    childName,
1887:                                                    new Integer(
1888:                                                            WebdavStatus.SC_INTERNAL_SERVER_ERROR));
1889:                                }
1890:                            }
1891:                        } catch (NamingException e) {
1892:                            errorList.put(childName, new Integer(
1893:                                    WebdavStatus.SC_INTERNAL_SERVER_ERROR));
1894:                        }
1895:                    }
1896:
1897:                }
1898:
1899:            }
1900:
1901:            /**
1902:             * Send a multistatus element containing a complete error report to the
1903:             * client.
1904:             *
1905:             * @param req Servlet request
1906:             * @param resp Servlet response
1907:             * @param errorList List of error to be displayed
1908:             */
1909:            private void sendReport(HttpServletRequest req,
1910:                    HttpServletResponse resp, Hashtable errorList)
1911:                    throws ServletException, IOException {
1912:
1913:                resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
1914:
1915:                String absoluteUri = req.getRequestURI();
1916:                String relativePath = getRelativePath(req);
1917:
1918:                XMLWriter generatedXML = new XMLWriter();
1919:                generatedXML.writeXMLHeader();
1920:
1921:                generatedXML.writeElement(null, "multistatus"
1922:                        + generateNamespaceDeclarations(), XMLWriter.OPENING);
1923:
1924:                Enumeration pathList = errorList.keys();
1925:                while (pathList.hasMoreElements()) {
1926:
1927:                    String errorPath = (String) pathList.nextElement();
1928:                    int errorCode = ((Integer) errorList.get(errorPath))
1929:                            .intValue();
1930:
1931:                    generatedXML.writeElement(null, "response",
1932:                            XMLWriter.OPENING);
1933:
1934:                    generatedXML.writeElement(null, "href", XMLWriter.OPENING);
1935:                    String toAppend = errorPath
1936:                            .substring(relativePath.length());
1937:                    if (!toAppend.startsWith("/"))
1938:                        toAppend = "/" + toAppend;
1939:                    generatedXML.writeText(absoluteUri + toAppend);
1940:                    generatedXML.writeElement(null, "href", XMLWriter.CLOSING);
1941:                    generatedXML
1942:                            .writeElement(null, "status", XMLWriter.OPENING);
1943:                    generatedXML.writeText("HTTP/1.1 " + errorCode + " "
1944:                            + WebdavStatus.getStatusText(errorCode));
1945:                    generatedXML
1946:                            .writeElement(null, "status", XMLWriter.CLOSING);
1947:
1948:                    generatedXML.writeElement(null, "response",
1949:                            XMLWriter.CLOSING);
1950:
1951:                }
1952:
1953:                generatedXML.writeElement(null, "multistatus",
1954:                        XMLWriter.CLOSING);
1955:
1956:                Writer writer = resp.getWriter();
1957:                writer.write(generatedXML.toString());
1958:                writer.close();
1959:
1960:            }
1961:
1962:            /**
1963:             * Propfind helper method.
1964:             *
1965:             * @param req The servlet request
1966:             * @param resources Resources object associated with this context
1967:             * @param generatedXML XML response to the Propfind request
1968:             * @param path Path of the current resource
1969:             * @param type Propfind type
1970:             * @param propertiesVector If the propfind type is find properties by
1971:             * name, then this Vector contains those properties
1972:             */
1973:            private void parseProperties(HttpServletRequest req,
1974:                    XMLWriter generatedXML, String path, int type,
1975:                    Vector<String> propertiesVector) {
1976:
1977:                // Exclude any resource in the /WEB-INF and /META-INF subdirectories
1978:                // (the "toUpperCase()" avoids problems on Windows systems)
1979:                if (path.toUpperCase().startsWith("/WEB-INF")
1980:                        || path.toUpperCase().startsWith("/META-INF"))
1981:                    return;
1982:
1983:                CacheEntry cacheEntry = resources.lookupCache(path);
1984:
1985:                generatedXML.writeElement(null, "response", XMLWriter.OPENING);
1986:                String status = new String("HTTP/1.1 " + WebdavStatus.SC_OK
1987:                        + " " + WebdavStatus.getStatusText(WebdavStatus.SC_OK));
1988:
1989:                // Generating href element
1990:                generatedXML.writeElement(null, "href", XMLWriter.OPENING);
1991:
1992:                String href = req.getContextPath() + req.getServletPath();
1993:                if ((href.endsWith("/")) && (path.startsWith("/")))
1994:                    href += path.substring(1);
1995:                else
1996:                    href += path;
1997:                if ((cacheEntry.context != null) && (!href.endsWith("/")))
1998:                    href += "/";
1999:
2000:                generatedXML.writeText(rewriteUrl(href));
2001:
2002:                generatedXML.writeElement(null, "href", XMLWriter.CLOSING);
2003:
2004:                String resourceName = path;
2005:                int lastSlash = path.lastIndexOf('/');
2006:                if (lastSlash != -1)
2007:                    resourceName = resourceName.substring(lastSlash + 1);
2008:
2009:                switch (type) {
2010:
2011:                case FIND_ALL_PROP:
2012:
2013:                    generatedXML.writeElement(null, "propstat",
2014:                            XMLWriter.OPENING);
2015:                    generatedXML.writeElement(null, "prop", XMLWriter.OPENING);
2016:
2017:                    generatedXML.writeProperty(null, "creationdate",
2018:                            getISOCreationDate(cacheEntry.attributes
2019:                                    .getCreation()));
2020:                    generatedXML.writeElement(null, "displayname",
2021:                            XMLWriter.OPENING);
2022:                    generatedXML.writeData(resourceName);
2023:                    generatedXML.writeElement(null, "displayname",
2024:                            XMLWriter.CLOSING);
2025:                    if (cacheEntry.resource != null) {
2026:                        generatedXML.writeProperty(null, "getlastmodified",
2027:                                FastHttpDateFormat
2028:                                        .formatDate(cacheEntry.attributes
2029:                                                .getLastModified(), null));
2030:                        generatedXML.writeProperty(null, "getcontentlength",
2031:                                String.valueOf(cacheEntry.attributes
2032:                                        .getContentLength()));
2033:                        String contentType = getServletContext().getMimeType(
2034:                                cacheEntry.name);
2035:                        if (contentType != null) {
2036:                            generatedXML.writeProperty(null, "getcontenttype",
2037:                                    contentType);
2038:                        }
2039:                        generatedXML.writeProperty(null, "getetag",
2040:                                getETag(cacheEntry.attributes));
2041:                        generatedXML.writeElement(null, "resourcetype",
2042:                                XMLWriter.NO_CONTENT);
2043:                    } else {
2044:                        generatedXML.writeElement(null, "resourcetype",
2045:                                XMLWriter.OPENING);
2046:                        generatedXML.writeElement(null, "collection",
2047:                                XMLWriter.NO_CONTENT);
2048:                        generatedXML.writeElement(null, "resourcetype",
2049:                                XMLWriter.CLOSING);
2050:                    }
2051:
2052:                    generatedXML.writeProperty(null, "source", "");
2053:
2054:                    String supportedLocks = "<lockentry>"
2055:                            + "<lockscope><exclusive/></lockscope>"
2056:                            + "<locktype><write/></locktype>" + "</lockentry>"
2057:                            + "<lockentry>"
2058:                            + "<lockscope><shared/></lockscope>"
2059:                            + "<locktype><write/></locktype>" + "</lockentry>";
2060:                    generatedXML.writeElement(null, "supportedlock",
2061:                            XMLWriter.OPENING);
2062:                    generatedXML.writeText(supportedLocks);
2063:                    generatedXML.writeElement(null, "supportedlock",
2064:                            XMLWriter.CLOSING);
2065:
2066:                    generateLockDiscovery(path, generatedXML);
2067:
2068:                    generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
2069:                    generatedXML
2070:                            .writeElement(null, "status", XMLWriter.OPENING);
2071:                    generatedXML.writeText(status);
2072:                    generatedXML
2073:                            .writeElement(null, "status", XMLWriter.CLOSING);
2074:                    generatedXML.writeElement(null, "propstat",
2075:                            XMLWriter.CLOSING);
2076:
2077:                    break;
2078:
2079:                case FIND_PROPERTY_NAMES:
2080:
2081:                    generatedXML.writeElement(null, "propstat",
2082:                            XMLWriter.OPENING);
2083:                    generatedXML.writeElement(null, "prop", XMLWriter.OPENING);
2084:
2085:                    generatedXML.writeElement(null, "creationdate",
2086:                            XMLWriter.NO_CONTENT);
2087:                    generatedXML.writeElement(null, "displayname",
2088:                            XMLWriter.NO_CONTENT);
2089:                    if (cacheEntry.resource != null) {
2090:                        generatedXML.writeElement(null, "getcontentlanguage",
2091:                                XMLWriter.NO_CONTENT);
2092:                        generatedXML.writeElement(null, "getcontentlength",
2093:                                XMLWriter.NO_CONTENT);
2094:                        generatedXML.writeElement(null, "getcontenttype",
2095:                                XMLWriter.NO_CONTENT);
2096:                        generatedXML.writeElement(null, "getetag",
2097:                                XMLWriter.NO_CONTENT);
2098:                        generatedXML.writeElement(null, "getlastmodified",
2099:                                XMLWriter.NO_CONTENT);
2100:                    }
2101:                    generatedXML.writeElement(null, "resourcetype",
2102:                            XMLWriter.NO_CONTENT);
2103:                    generatedXML.writeElement(null, "source",
2104:                            XMLWriter.NO_CONTENT);
2105:                    generatedXML.writeElement(null, "lockdiscovery",
2106:                            XMLWriter.NO_CONTENT);
2107:
2108:                    generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
2109:                    generatedXML
2110:                            .writeElement(null, "status", XMLWriter.OPENING);
2111:                    generatedXML.writeText(status);
2112:                    generatedXML
2113:                            .writeElement(null, "status", XMLWriter.CLOSING);
2114:                    generatedXML.writeElement(null, "propstat",
2115:                            XMLWriter.CLOSING);
2116:
2117:                    break;
2118:
2119:                case FIND_BY_PROPERTY:
2120:
2121:                    Vector<String> propertiesNotFound = new Vector<String>();
2122:
2123:                    // Parse the list of properties
2124:
2125:                    generatedXML.writeElement(null, "propstat",
2126:                            XMLWriter.OPENING);
2127:                    generatedXML.writeElement(null, "prop", XMLWriter.OPENING);
2128:
2129:                    Enumeration<String> properties = propertiesVector
2130:                            .elements();
2131:
2132:                    while (properties.hasMoreElements()) {
2133:
2134:                        String property = (String) properties.nextElement();
2135:
2136:                        if (property.equals("creationdate")) {
2137:                            generatedXML.writeProperty(null, "creationdate",
2138:                                    getISOCreationDate(cacheEntry.attributes
2139:                                            .getCreation()));
2140:                        } else if (property.equals("displayname")) {
2141:                            generatedXML.writeElement(null, "displayname",
2142:                                    XMLWriter.OPENING);
2143:                            generatedXML.writeData(resourceName);
2144:                            generatedXML.writeElement(null, "displayname",
2145:                                    XMLWriter.CLOSING);
2146:                        } else if (property.equals("getcontentlanguage")) {
2147:                            if (cacheEntry.context != null) {
2148:                                propertiesNotFound.addElement(property);
2149:                            } else {
2150:                                generatedXML.writeElement(null,
2151:                                        "getcontentlanguage",
2152:                                        XMLWriter.NO_CONTENT);
2153:                            }
2154:                        } else if (property.equals("getcontentlength")) {
2155:                            if (cacheEntry.context != null) {
2156:                                propertiesNotFound.addElement(property);
2157:                            } else {
2158:                                generatedXML.writeProperty(null,
2159:                                        "getcontentlength", (String
2160:                                                .valueOf(cacheEntry.attributes
2161:                                                        .getContentLength())));
2162:                            }
2163:                        } else if (property.equals("getcontenttype")) {
2164:                            if (cacheEntry.context != null) {
2165:                                propertiesNotFound.addElement(property);
2166:                            } else {
2167:                                generatedXML.writeProperty(null,
2168:                                        "getcontenttype", getServletContext()
2169:                                                .getMimeType(cacheEntry.name));
2170:                            }
2171:                        } else if (property.equals("getetag")) {
2172:                            if (cacheEntry.context != null) {
2173:                                propertiesNotFound.addElement(property);
2174:                            } else {
2175:                                generatedXML.writeProperty(null, "getetag",
2176:                                        getETag(cacheEntry.attributes));
2177:                            }
2178:                        } else if (property.equals("getlastmodified")) {
2179:                            if (cacheEntry.context != null) {
2180:                                propertiesNotFound.addElement(property);
2181:                            } else {
2182:                                generatedXML.writeProperty(null,
2183:                                        "getlastmodified",
2184:                                        FastHttpDateFormat.formatDate(
2185:                                                cacheEntry.attributes
2186:                                                        .getLastModified(),
2187:                                                null));
2188:                            }
2189:                        } else if (property.equals("resourcetype")) {
2190:                            if (cacheEntry.context != null) {
2191:                                generatedXML.writeElement(null, "resourcetype",
2192:                                        XMLWriter.OPENING);
2193:                                generatedXML.writeElement(null, "collection",
2194:                                        XMLWriter.NO_CONTENT);
2195:                                generatedXML.writeElement(null, "resourcetype",
2196:                                        XMLWriter.CLOSING);
2197:                            } else {
2198:                                generatedXML.writeElement(null, "resourcetype",
2199:                                        XMLWriter.NO_CONTENT);
2200:                            }
2201:                        } else if (property.equals("source")) {
2202:                            generatedXML.writeProperty(null, "source", "");
2203:                        } else if (property.equals("supportedlock")) {
2204:                            supportedLocks = "<lockentry>"
2205:                                    + "<lockscope><exclusive/></lockscope>"
2206:                                    + "<locktype><write/></locktype>"
2207:                                    + "</lockentry>" + "<lockentry>"
2208:                                    + "<lockscope><shared/></lockscope>"
2209:                                    + "<locktype><write/></locktype>"
2210:                                    + "</lockentry>";
2211:                            generatedXML.writeElement(null, "supportedlock",
2212:                                    XMLWriter.OPENING);
2213:                            generatedXML.writeText(supportedLocks);
2214:                            generatedXML.writeElement(null, "supportedlock",
2215:                                    XMLWriter.CLOSING);
2216:                        } else if (property.equals("lockdiscovery")) {
2217:                            if (!generateLockDiscovery(path, generatedXML))
2218:                                propertiesNotFound.addElement(property);
2219:                        } else {
2220:                            propertiesNotFound.addElement(property);
2221:                        }
2222:
2223:                    }
2224:
2225:                    generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
2226:                    generatedXML
2227:                            .writeElement(null, "status", XMLWriter.OPENING);
2228:                    generatedXML.writeText(status);
2229:                    generatedXML
2230:                            .writeElement(null, "status", XMLWriter.CLOSING);
2231:                    generatedXML.writeElement(null, "propstat",
2232:                            XMLWriter.CLOSING);
2233:
2234:                    Enumeration propertiesNotFoundList = propertiesNotFound
2235:                            .elements();
2236:
2237:                    if (propertiesNotFoundList.hasMoreElements()) {
2238:
2239:                        status = new String(
2240:                                "HTTP/1.1 "
2241:                                        + WebdavStatus.SC_NOT_FOUND
2242:                                        + " "
2243:                                        + WebdavStatus
2244:                                                .getStatusText(WebdavStatus.SC_NOT_FOUND));
2245:
2246:                        generatedXML.writeElement(null, "propstat",
2247:                                XMLWriter.OPENING);
2248:                        generatedXML.writeElement(null, "prop",
2249:                                XMLWriter.OPENING);
2250:
2251:                        while (propertiesNotFoundList.hasMoreElements()) {
2252:                            generatedXML.writeElement(null,
2253:                                    (String) propertiesNotFoundList
2254:                                            .nextElement(),
2255:                                    XMLWriter.NO_CONTENT);
2256:                        }
2257:
2258:                        generatedXML.writeElement(null, "prop",
2259:                                XMLWriter.CLOSING);
2260:                        generatedXML.writeElement(null, "status",
2261:                                XMLWriter.OPENING);
2262:                        generatedXML.writeText(status);
2263:                        generatedXML.writeElement(null, "status",
2264:                                XMLWriter.CLOSING);
2265:                        generatedXML.writeElement(null, "propstat",
2266:                                XMLWriter.CLOSING);
2267:
2268:                    }
2269:
2270:                    break;
2271:
2272:                }
2273:
2274:                generatedXML.writeElement(null, "response", XMLWriter.CLOSING);
2275:
2276:            }
2277:
2278:            /**
2279:             * Propfind helper method. Dispays the properties of a lock-null resource.
2280:             *
2281:             * @param resources Resources object associated with this context
2282:             * @param generatedXML XML response to the Propfind request
2283:             * @param path Path of the current resource
2284:             * @param type Propfind type
2285:             * @param propertiesVector If the propfind type is find properties by
2286:             * name, then this Vector contains those properties
2287:             */
2288:            private void parseLockNullProperties(HttpServletRequest req,
2289:                    XMLWriter generatedXML, String path, int type,
2290:                    Vector propertiesVector) {
2291:
2292:                // Exclude any resource in the /WEB-INF and /META-INF subdirectories
2293:                // (the "toUpperCase()" avoids problems on Windows systems)
2294:                if (path.toUpperCase().startsWith("/WEB-INF")
2295:                        || path.toUpperCase().startsWith("/META-INF"))
2296:                    return;
2297:
2298:                // Retrieving the lock associated with the lock-null resource
2299:                LockInfo lock = (LockInfo) resourceLocks.get(path);
2300:
2301:                if (lock == null)
2302:                    return;
2303:
2304:                generatedXML.writeElement(null, "response", XMLWriter.OPENING);
2305:                String status = new String("HTTP/1.1 " + WebdavStatus.SC_OK
2306:                        + " " + WebdavStatus.getStatusText(WebdavStatus.SC_OK));
2307:
2308:                // Generating href element
2309:                generatedXML.writeElement(null, "href", XMLWriter.OPENING);
2310:
2311:                String absoluteUri = req.getRequestURI();
2312:                String relativePath = getRelativePath(req);
2313:                String toAppend = path.substring(relativePath.length());
2314:                if (!toAppend.startsWith("/"))
2315:                    toAppend = "/" + toAppend;
2316:
2317:                generatedXML.writeText(rewriteUrl(normalize(absoluteUri
2318:                        + toAppend)));
2319:
2320:                generatedXML.writeElement(null, "href", XMLWriter.CLOSING);
2321:
2322:                String resourceName = path;
2323:                int lastSlash = path.lastIndexOf('/');
2324:                if (lastSlash != -1)
2325:                    resourceName = resourceName.substring(lastSlash + 1);
2326:
2327:                switch (type) {
2328:
2329:                case FIND_ALL_PROP:
2330:
2331:                    generatedXML.writeElement(null, "propstat",
2332:                            XMLWriter.OPENING);
2333:                    generatedXML.writeElement(null, "prop", XMLWriter.OPENING);
2334:
2335:                    generatedXML.writeProperty(null, "creationdate",
2336:                            getISOCreationDate(lock.creationDate.getTime()));
2337:                    generatedXML.writeElement(null, "displayname",
2338:                            XMLWriter.OPENING);
2339:                    generatedXML.writeData(resourceName);
2340:                    generatedXML.writeElement(null, "displayname",
2341:                            XMLWriter.CLOSING);
2342:                    generatedXML.writeProperty(null, "getlastmodified",
2343:                            FastHttpDateFormat.formatDate(lock.creationDate
2344:                                    .getTime(), null));
2345:                    generatedXML.writeProperty(null, "getcontentlength", String
2346:                            .valueOf(0));
2347:                    generatedXML.writeProperty(null, "getcontenttype", "");
2348:                    generatedXML.writeProperty(null, "getetag", "");
2349:                    generatedXML.writeElement(null, "resourcetype",
2350:                            XMLWriter.OPENING);
2351:                    generatedXML.writeElement(null, "lock-null",
2352:                            XMLWriter.NO_CONTENT);
2353:                    generatedXML.writeElement(null, "resourcetype",
2354:                            XMLWriter.CLOSING);
2355:
2356:                    generatedXML.writeProperty(null, "source", "");
2357:
2358:                    String supportedLocks = "<lockentry>"
2359:                            + "<lockscope><exclusive/></lockscope>"
2360:                            + "<locktype><write/></locktype>" + "</lockentry>"
2361:                            + "<lockentry>"
2362:                            + "<lockscope><shared/></lockscope>"
2363:                            + "<locktype><write/></locktype>" + "</lockentry>";
2364:                    generatedXML.writeElement(null, "supportedlock",
2365:                            XMLWriter.OPENING);
2366:                    generatedXML.writeText(supportedLocks);
2367:                    generatedXML.writeElement(null, "supportedlock",
2368:                            XMLWriter.CLOSING);
2369:
2370:                    generateLockDiscovery(path, generatedXML);
2371:
2372:                    generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
2373:                    generatedXML
2374:                            .writeElement(null, "status", XMLWriter.OPENING);
2375:                    generatedXML.writeText(status);
2376:                    generatedXML
2377:                            .writeElement(null, "status", XMLWriter.CLOSING);
2378:                    generatedXML.writeElement(null, "propstat",
2379:                            XMLWriter.CLOSING);
2380:
2381:                    break;
2382:
2383:                case FIND_PROPERTY_NAMES:
2384:
2385:                    generatedXML.writeElement(null, "propstat",
2386:                            XMLWriter.OPENING);
2387:                    generatedXML.writeElement(null, "prop", XMLWriter.OPENING);
2388:
2389:                    generatedXML.writeElement(null, "creationdate",
2390:                            XMLWriter.NO_CONTENT);
2391:                    generatedXML.writeElement(null, "displayname",
2392:                            XMLWriter.NO_CONTENT);
2393:                    generatedXML.writeElement(null, "getcontentlanguage",
2394:                            XMLWriter.NO_CONTENT);
2395:                    generatedXML.writeElement(null, "getcontentlength",
2396:                            XMLWriter.NO_CONTENT);
2397:                    generatedXML.writeElement(null, "getcontenttype",
2398:                            XMLWriter.NO_CONTENT);
2399:                    generatedXML.writeElement(null, "getetag",
2400:                            XMLWriter.NO_CONTENT);
2401:                    generatedXML.writeElement(null, "getlastmodified",
2402:                            XMLWriter.NO_CONTENT);
2403:                    generatedXML.writeElement(null, "resourcetype",
2404:                            XMLWriter.NO_CONTENT);
2405:                    generatedXML.writeElement(null, "source",
2406:                            XMLWriter.NO_CONTENT);
2407:                    generatedXML.writeElement(null, "lockdiscovery",
2408:                            XMLWriter.NO_CONTENT);
2409:
2410:                    generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
2411:                    generatedXML
2412:                            .writeElement(null, "status", XMLWriter.OPENING);
2413:                    generatedXML.writeText(status);
2414:                    generatedXML
2415:                            .writeElement(null, "status", XMLWriter.CLOSING);
2416:                    generatedXML.writeElement(null, "propstat",
2417:                            XMLWriter.CLOSING);
2418:
2419:                    break;
2420:
2421:                case FIND_BY_PROPERTY:
2422:
2423:                    Vector<String> propertiesNotFound = new Vector<String>();
2424:
2425:                    // Parse the list of properties
2426:
2427:                    generatedXML.writeElement(null, "propstat",
2428:                            XMLWriter.OPENING);
2429:                    generatedXML.writeElement(null, "prop", XMLWriter.OPENING);
2430:
2431:                    Enumeration properties = propertiesVector.elements();
2432:
2433:                    while (properties.hasMoreElements()) {
2434:
2435:                        String property = (String) properties.nextElement();
2436:
2437:                        if (property.equals("creationdate")) {
2438:                            generatedXML.writeProperty(null, "creationdate",
2439:                                    getISOCreationDate(lock.creationDate
2440:                                            .getTime()));
2441:                        } else if (property.equals("displayname")) {
2442:                            generatedXML.writeElement(null, "displayname",
2443:                                    XMLWriter.OPENING);
2444:                            generatedXML.writeData(resourceName);
2445:                            generatedXML.writeElement(null, "displayname",
2446:                                    XMLWriter.CLOSING);
2447:                        } else if (property.equals("getcontentlanguage")) {
2448:                            generatedXML.writeElement(null,
2449:                                    "getcontentlanguage", XMLWriter.NO_CONTENT);
2450:                        } else if (property.equals("getcontentlength")) {
2451:                            generatedXML.writeProperty(null,
2452:                                    "getcontentlength", (String.valueOf(0)));
2453:                        } else if (property.equals("getcontenttype")) {
2454:                            generatedXML.writeProperty(null, "getcontenttype",
2455:                                    "");
2456:                        } else if (property.equals("getetag")) {
2457:                            generatedXML.writeProperty(null, "getetag", "");
2458:                        } else if (property.equals("getlastmodified")) {
2459:                            generatedXML.writeProperty(null, "getlastmodified",
2460:                                    FastHttpDateFormat.formatDate(
2461:                                            lock.creationDate.getTime(), null));
2462:                        } else if (property.equals("resourcetype")) {
2463:                            generatedXML.writeElement(null, "resourcetype",
2464:                                    XMLWriter.OPENING);
2465:                            generatedXML.writeElement(null, "lock-null",
2466:                                    XMLWriter.NO_CONTENT);
2467:                            generatedXML.writeElement(null, "resourcetype",
2468:                                    XMLWriter.CLOSING);
2469:                        } else if (property.equals("source")) {
2470:                            generatedXML.writeProperty(null, "source", "");
2471:                        } else if (property.equals("supportedlock")) {
2472:                            supportedLocks = "<lockentry>"
2473:                                    + "<lockscope><exclusive/></lockscope>"
2474:                                    + "<locktype><write/></locktype>"
2475:                                    + "</lockentry>" + "<lockentry>"
2476:                                    + "<lockscope><shared/></lockscope>"
2477:                                    + "<locktype><write/></locktype>"
2478:                                    + "</lockentry>";
2479:                            generatedXML.writeElement(null, "supportedlock",
2480:                                    XMLWriter.OPENING);
2481:                            generatedXML.writeText(supportedLocks);
2482:                            generatedXML.writeElement(null, "supportedlock",
2483:                                    XMLWriter.CLOSING);
2484:                        } else if (property.equals("lockdiscovery")) {
2485:                            if (!generateLockDiscovery(path, generatedXML))
2486:                                propertiesNotFound.addElement(property);
2487:                        } else {
2488:                            propertiesNotFound.addElement(property);
2489:                        }
2490:
2491:                    }
2492:
2493:                    generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
2494:                    generatedXML
2495:                            .writeElement(null, "status", XMLWriter.OPENING);
2496:                    generatedXML.writeText(status);
2497:                    generatedXML
2498:                            .writeElement(null, "status", XMLWriter.CLOSING);
2499:                    generatedXML.writeElement(null, "propstat",
2500:                            XMLWriter.CLOSING);
2501:
2502:                    Enumeration propertiesNotFoundList = propertiesNotFound
2503:                            .elements();
2504:
2505:                    if (propertiesNotFoundList.hasMoreElements()) {
2506:
2507:                        status = new String(
2508:                                "HTTP/1.1 "
2509:                                        + WebdavStatus.SC_NOT_FOUND
2510:                                        + " "
2511:                                        + WebdavStatus
2512:                                                .getStatusText(WebdavStatus.SC_NOT_FOUND));
2513:
2514:                        generatedXML.writeElement(null, "propstat",
2515:                                XMLWriter.OPENING);
2516:                        generatedXML.writeElement(null, "prop",
2517:                                XMLWriter.OPENING);
2518:
2519:                        while (propertiesNotFoundList.hasMoreElements()) {
2520:                            generatedXML.writeElement(null,
2521:                                    (String) propertiesNotFoundList
2522:                                            .nextElement(),
2523:                                    XMLWriter.NO_CONTENT);
2524:                        }
2525:
2526:                        generatedXML.writeElement(null, "prop",
2527:                                XMLWriter.CLOSING);
2528:                        generatedXML.writeElement(null, "status",
2529:                                XMLWriter.OPENING);
2530:                        generatedXML.writeText(status);
2531:                        generatedXML.writeElement(null, "status",
2532:                                XMLWriter.CLOSING);
2533:                        generatedXML.writeElement(null, "propstat",
2534:                                XMLWriter.CLOSING);
2535:
2536:                    }
2537:
2538:                    break;
2539:
2540:                }
2541:
2542:                generatedXML.writeElement(null, "response", XMLWriter.CLOSING);
2543:
2544:            }
2545:
2546:            /**
2547:             * Print the lock discovery information associated with a path.
2548:             *
2549:             * @param path Path
2550:             * @param generatedXML XML data to which the locks info will be appended
2551:             * @return true if at least one lock was displayed
2552:             */
2553:            private boolean generateLockDiscovery(String path,
2554:                    XMLWriter generatedXML) {
2555:
2556:                LockInfo resourceLock = (LockInfo) resourceLocks.get(path);
2557:                Enumeration collectionLocksList = collectionLocks.elements();
2558:
2559:                boolean wroteStart = false;
2560:
2561:                if (resourceLock != null) {
2562:                    wroteStart = true;
2563:                    generatedXML.writeElement(null, "lockdiscovery",
2564:                            XMLWriter.OPENING);
2565:                    resourceLock.toXML(generatedXML);
2566:                }
2567:
2568:                while (collectionLocksList.hasMoreElements()) {
2569:                    LockInfo currentLock = (LockInfo) collectionLocksList
2570:                            .nextElement();
2571:                    if (path.startsWith(currentLock.path)) {
2572:                        if (!wroteStart) {
2573:                            wroteStart = true;
2574:                            generatedXML.writeElement(null, "lockdiscovery",
2575:                                    XMLWriter.OPENING);
2576:                        }
2577:                        currentLock.toXML(generatedXML);
2578:                    }
2579:                }
2580:
2581:                if (wroteStart) {
2582:                    generatedXML.writeElement(null, "lockdiscovery",
2583:                            XMLWriter.CLOSING);
2584:                } else {
2585:                    return false;
2586:                }
2587:
2588:                return true;
2589:
2590:            }
2591:
2592:            /**
2593:             * Get creation date in ISO format.
2594:             */
2595:            private String getISOCreationDate(long creationDate) {
2596:                StringBuffer creationDateValue = new StringBuffer(
2597:                        creationDateFormat.format(new Date(creationDate)));
2598:                /*
2599:                int offset = Calendar.getInstance().getTimeZone().getRawOffset()
2600:                    / 3600000; // FIXME ?
2601:                if (offset < 0) {
2602:                    creationDateValue.append("-");
2603:                    offset = -offset;
2604:                } else if (offset > 0) {
2605:                    creationDateValue.append("+");
2606:                }
2607:                if (offset != 0) {
2608:                    if (offset < 10)
2609:                        creationDateValue.append("0");
2610:                    creationDateValue.append(offset + ":00");
2611:                } else {
2612:                    creationDateValue.append("Z");
2613:                }
2614:                 */
2615:                return creationDateValue.toString();
2616:            }
2617:
2618:            /**
2619:             * Determines the methods normally allowed for the resource.
2620:             *
2621:             */
2622:            private StringBuffer determineMethodsAllowed(DirContext resources,
2623:                    HttpServletRequest req) {
2624:
2625:                StringBuffer methodsAllowed = new StringBuffer();
2626:                boolean exists = true;
2627:                Object object = null;
2628:                try {
2629:                    String path = getRelativePath(req);
2630:
2631:                    object = resources.lookup(path);
2632:                } catch (NamingException e) {
2633:                    exists = false;
2634:                }
2635:
2636:                if (!exists) {
2637:                    methodsAllowed.append("OPTIONS, MKCOL, PUT, LOCK");
2638:                    return methodsAllowed;
2639:                }
2640:
2641:                methodsAllowed
2642:                        .append("OPTIONS, GET, HEAD, POST, DELETE, TRACE");
2643:                methodsAllowed.append(", PROPPATCH, COPY, MOVE, LOCK, UNLOCK");
2644:
2645:                if (listings) {
2646:                    methodsAllowed.append(", PROPFIND");
2647:                }
2648:
2649:                if (!(object instanceof  DirContext)) {
2650:                    methodsAllowed.append(", PUT");
2651:                }
2652:
2653:                return methodsAllowed;
2654:            }
2655:
2656:            // --------------------------------------------------  LockInfo Inner Class
2657:
2658:            /**
2659:             * Holds a lock information.
2660:             */
2661:            private class LockInfo {
2662:
2663:                // -------------------------------------------------------- Constructor
2664:
2665:                /**
2666:                 * Constructor.
2667:                 */
2668:                public LockInfo() {
2669:
2670:                }
2671:
2672:                // ------------------------------------------------- Instance Variables
2673:
2674:                String path = "/";
2675:                String type = "write";
2676:                String scope = "exclusive";
2677:                int depth = 0;
2678:                String owner = "";
2679:                Vector<String> tokens = new Vector<String>();
2680:                long expiresAt = 0;
2681:                Date creationDate = new Date();
2682:
2683:                // ----------------------------------------------------- Public Methods
2684:
2685:                /**
2686:                 * Get a String representation of this lock token.
2687:                 */
2688:                public String toString() {
2689:
2690:                    String result = "Type:" + type + "\n";
2691:                    result += "Scope:" + scope + "\n";
2692:                    result += "Depth:" + depth + "\n";
2693:                    result += "Owner:" + owner + "\n";
2694:                    result += "Expiration:"
2695:                            + FastHttpDateFormat.formatDate(expiresAt, null)
2696:                            + "\n";
2697:                    Enumeration tokensList = tokens.elements();
2698:                    while (tokensList.hasMoreElements()) {
2699:                        result += "Token:" + tokensList.nextElement() + "\n";
2700:                    }
2701:                    return result;
2702:
2703:                }
2704:
2705:                /**
2706:                 * Return true if the lock has expired.
2707:                 */
2708:                public boolean hasExpired() {
2709:                    return (System.currentTimeMillis() > expiresAt);
2710:                }
2711:
2712:                /**
2713:                 * Return true if the lock is exclusive.
2714:                 */
2715:                public boolean isExclusive() {
2716:
2717:                    return (scope.equals("exclusive"));
2718:
2719:                }
2720:
2721:                /**
2722:                 * Get an XML representation of this lock token. This method will
2723:                 * append an XML fragment to the given XML writer.
2724:                 */
2725:                public void toXML(XMLWriter generatedXML) {
2726:
2727:                    generatedXML.writeElement(null, "activelock",
2728:                            XMLWriter.OPENING);
2729:
2730:                    generatedXML.writeElement(null, "locktype",
2731:                            XMLWriter.OPENING);
2732:                    generatedXML.writeElement(null, type, XMLWriter.NO_CONTENT);
2733:                    generatedXML.writeElement(null, "locktype",
2734:                            XMLWriter.CLOSING);
2735:
2736:                    generatedXML.writeElement(null, "lockscope",
2737:                            XMLWriter.OPENING);
2738:                    generatedXML
2739:                            .writeElement(null, scope, XMLWriter.NO_CONTENT);
2740:                    generatedXML.writeElement(null, "lockscope",
2741:                            XMLWriter.CLOSING);
2742:
2743:                    generatedXML.writeElement(null, "depth", XMLWriter.OPENING);
2744:                    if (depth == INFINITY) {
2745:                        generatedXML.writeText("Infinity");
2746:                    } else {
2747:                        generatedXML.writeText("0");
2748:                    }
2749:                    generatedXML.writeElement(null, "depth", XMLWriter.CLOSING);
2750:
2751:                    generatedXML.writeElement(null, "owner", XMLWriter.OPENING);
2752:                    generatedXML.writeText(owner);
2753:                    generatedXML.writeElement(null, "owner", XMLWriter.CLOSING);
2754:
2755:                    generatedXML.writeElement(null, "timeout",
2756:                            XMLWriter.OPENING);
2757:                    long timeout = (expiresAt - System.currentTimeMillis()) / 1000;
2758:                    generatedXML.writeText("Second-" + timeout);
2759:                    generatedXML.writeElement(null, "timeout",
2760:                            XMLWriter.CLOSING);
2761:
2762:                    generatedXML.writeElement(null, "locktoken",
2763:                            XMLWriter.OPENING);
2764:                    Enumeration tokensList = tokens.elements();
2765:                    while (tokensList.hasMoreElements()) {
2766:                        generatedXML.writeElement(null, "href",
2767:                                XMLWriter.OPENING);
2768:                        generatedXML.writeText("opaquelocktoken:"
2769:                                + tokensList.nextElement());
2770:                        generatedXML.writeElement(null, "href",
2771:                                XMLWriter.CLOSING);
2772:                    }
2773:                    generatedXML.writeElement(null, "locktoken",
2774:                            XMLWriter.CLOSING);
2775:
2776:                    generatedXML.writeElement(null, "activelock",
2777:                            XMLWriter.CLOSING);
2778:
2779:                }
2780:
2781:            }
2782:
2783:        };
2784:
2785:        // --------------------------------------------------------  WebdavStatus Class
2786:
2787:        /**
2788:         * Wraps the HttpServletResponse class to abstract the
2789:         * specific protocol used.  To support other protocols
2790:         * we would only need to modify this class and the
2791:         * WebDavRetCode classes.
2792:         *
2793:         * @author              Marc Eaddy
2794:         * @version             1.0, 16 Nov 1997
2795:         */
2796:        class WebdavStatus {
2797:
2798:            // ----------------------------------------------------- Instance Variables
2799:
2800:            /**
2801:             * This Hashtable contains the mapping of HTTP and WebDAV
2802:             * status codes to descriptive text.  This is a static
2803:             * variable.
2804:             */
2805:            private static Hashtable<Integer, String> mapStatusCodes = new Hashtable<Integer, String>();
2806:
2807:            // ------------------------------------------------------ HTTP Status Codes
2808:
2809:            /**
2810:             * Status code (200) indicating the request succeeded normally.
2811:             */
2812:            public static final int SC_OK = HttpServletResponse.SC_OK;
2813:
2814:            /**
2815:             * Status code (201) indicating the request succeeded and created
2816:             * a new resource on the server.
2817:             */
2818:            public static final int SC_CREATED = HttpServletResponse.SC_CREATED;
2819:
2820:            /**
2821:             * Status code (202) indicating that a request was accepted for
2822:             * processing, but was not completed.
2823:             */
2824:            public static final int SC_ACCEPTED = HttpServletResponse.SC_ACCEPTED;
2825:
2826:            /**
2827:             * Status code (204) indicating that the request succeeded but that
2828:             * there was no new information to return.
2829:             */
2830:            public static final int SC_NO_CONTENT = HttpServletResponse.SC_NO_CONTENT;
2831:
2832:            /**
2833:             * Status code (301) indicating that the resource has permanently
2834:             * moved to a new location, and that future references should use a
2835:             * new URI with their requests.
2836:             */
2837:            public static final int SC_MOVED_PERMANENTLY = HttpServletResponse.SC_MOVED_PERMANENTLY;
2838:
2839:            /**
2840:             * Status code (302) indicating that the resource has temporarily
2841:             * moved to another location, but that future references should
2842:             * still use the original URI to access the resource.
2843:             */
2844:            public static final int SC_MOVED_TEMPORARILY = HttpServletResponse.SC_MOVED_TEMPORARILY;
2845:
2846:            /**
2847:             * Status code (304) indicating that a conditional GET operation
2848:             * found that the resource was available and not modified.
2849:             */
2850:            public static final int SC_NOT_MODIFIED = HttpServletResponse.SC_NOT_MODIFIED;
2851:
2852:            /**
2853:             * Status code (400) indicating the request sent by the client was
2854:             * syntactically incorrect.
2855:             */
2856:            public static final int SC_BAD_REQUEST = HttpServletResponse.SC_BAD_REQUEST;
2857:
2858:            /**
2859:             * Status code (401) indicating that the request requires HTTP
2860:             * authentication.
2861:             */
2862:            public static final int SC_UNAUTHORIZED = HttpServletResponse.SC_UNAUTHORIZED;
2863:
2864:            /**
2865:             * Status code (403) indicating the server understood the request
2866:             * but refused to fulfill it.
2867:             */
2868:            public static final int SC_FORBIDDEN = HttpServletResponse.SC_FORBIDDEN;
2869:
2870:            /**
2871:             * Status code (404) indicating that the requested resource is not
2872:             * available.
2873:             */
2874:            public static final int SC_NOT_FOUND = HttpServletResponse.SC_NOT_FOUND;
2875:
2876:            /**
2877:             * Status code (500) indicating an error inside the HTTP service
2878:             * which prevented it from fulfilling the request.
2879:             */
2880:            public static final int SC_INTERNAL_SERVER_ERROR = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
2881:
2882:            /**
2883:             * Status code (501) indicating the HTTP service does not support
2884:             * the functionality needed to fulfill the request.
2885:             */
2886:            public static final int SC_NOT_IMPLEMENTED = HttpServletResponse.SC_NOT_IMPLEMENTED;
2887:
2888:            /**
2889:             * Status code (502) indicating that the HTTP server received an
2890:             * invalid response from a server it consulted when acting as a
2891:             * proxy or gateway.
2892:             */
2893:            public static final int SC_BAD_GATEWAY = HttpServletResponse.SC_BAD_GATEWAY;
2894:
2895:            /**
2896:             * Status code (503) indicating that the HTTP service is
2897:             * temporarily overloaded, and unable to handle the request.
2898:             */
2899:            public static final int SC_SERVICE_UNAVAILABLE = HttpServletResponse.SC_SERVICE_UNAVAILABLE;
2900:
2901:            /**
2902:             * Status code (100) indicating the client may continue with
2903:             * its request.  This interim response is used to inform the
2904:             * client that the initial part of the request has been
2905:             * received and has not yet been rejected by the server.
2906:             */
2907:            public static final int SC_CONTINUE = 100;
2908:
2909:            /**
2910:             * Status code (405) indicating the method specified is not
2911:             * allowed for the resource.
2912:             */
2913:            public static final int SC_METHOD_NOT_ALLOWED = 405;
2914:
2915:            /**
2916:             * Status code (409) indicating that the request could not be
2917:             * completed due to a conflict with the current state of the
2918:             * resource.
2919:             */
2920:            public static final int SC_CONFLICT = 409;
2921:
2922:            /**
2923:             * Status code (412) indicating the precondition given in one
2924:             * or more of the request-header fields evaluated to false
2925:             * when it was tested on the server.
2926:             */
2927:            public static final int SC_PRECONDITION_FAILED = 412;
2928:
2929:            /**
2930:             * Status code (413) indicating the server is refusing to
2931:             * process a request because the request entity is larger
2932:             * than the server is willing or able to process.
2933:             */
2934:            public static final int SC_REQUEST_TOO_LONG = 413;
2935:
2936:            /**
2937:             * Status code (415) indicating the server is refusing to service
2938:             * the request because the entity of the request is in a format
2939:             * not supported by the requested resource for the requested
2940:             * method.
2941:             */
2942:            public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415;
2943:
2944:            // -------------------------------------------- Extended WebDav status code
2945:
2946:            /**
2947:             * Status code (207) indicating that the response requires
2948:             * providing status for multiple independent operations.
2949:             */
2950:            public static final int SC_MULTI_STATUS = 207;
2951:            // This one colides with HTTP 1.1
2952:            // "207 Parital Update OK"
2953:
2954:            /**
2955:             * Status code (418) indicating the entity body submitted with
2956:             * the PATCH method was not understood by the resource.
2957:             */
2958:            public static final int SC_UNPROCESSABLE_ENTITY = 418;
2959:            // This one colides with HTTP 1.1
2960:            // "418 Reauthentication Required"
2961:
2962:            /**
2963:             * Status code (419) indicating that the resource does not have
2964:             * sufficient space to record the state of the resource after the
2965:             * execution of this method.
2966:             */
2967:            public static final int SC_INSUFFICIENT_SPACE_ON_RESOURCE = 419;
2968:            // This one colides with HTTP 1.1
2969:            // "419 Proxy Reauthentication Required"
2970:
2971:            /**
2972:             * Status code (420) indicating the method was not executed on
2973:             * a particular resource within its scope because some part of
2974:             * the method's execution failed causing the entire method to be
2975:             * aborted.
2976:             */
2977:            public static final int SC_METHOD_FAILURE = 420;
2978:
2979:            /**
2980:             * Status code (423) indicating the destination resource of a
2981:             * method is locked, and either the request did not contain a
2982:             * valid Lock-Info header, or the Lock-Info header identifies
2983:             * a lock held by another principal.
2984:             */
2985:            public static final int SC_LOCKED = 423;
2986:
2987:            // ------------------------------------------------------------ Initializer
2988:
2989:            static {
2990:                // HTTP 1.0 tatus Code
2991:                addStatusCodeMap(SC_OK, "OK");
2992:                addStatusCodeMap(SC_CREATED, "Created");
2993:                addStatusCodeMap(SC_ACCEPTED, "Accepted");
2994:                addStatusCodeMap(SC_NO_CONTENT, "No Content");
2995:                addStatusCodeMap(SC_MOVED_PERMANENTLY, "Moved Permanently");
2996:                addStatusCodeMap(SC_MOVED_TEMPORARILY, "Moved Temporarily");
2997:                addStatusCodeMap(SC_NOT_MODIFIED, "Not Modified");
2998:                addStatusCodeMap(SC_BAD_REQUEST, "Bad Request");
2999:                addStatusCodeMap(SC_UNAUTHORIZED, "Unauthorized");
3000:                addStatusCodeMap(SC_FORBIDDEN, "Forbidden");
3001:                addStatusCodeMap(SC_NOT_FOUND, "Not Found");
3002:                addStatusCodeMap(SC_INTERNAL_SERVER_ERROR,
3003:                        "Internal Server Error");
3004:                addStatusCodeMap(SC_NOT_IMPLEMENTED, "Not Implemented");
3005:                addStatusCodeMap(SC_BAD_GATEWAY, "Bad Gateway");
3006:                addStatusCodeMap(SC_SERVICE_UNAVAILABLE, "Service Unavailable");
3007:                addStatusCodeMap(SC_CONTINUE, "Continue");
3008:                addStatusCodeMap(SC_METHOD_NOT_ALLOWED, "Method Not Allowed");
3009:                addStatusCodeMap(SC_CONFLICT, "Conflict");
3010:                addStatusCodeMap(SC_PRECONDITION_FAILED, "Precondition Failed");
3011:                addStatusCodeMap(SC_REQUEST_TOO_LONG, "Request Too Long");
3012:                addStatusCodeMap(SC_UNSUPPORTED_MEDIA_TYPE,
3013:                        "Unsupported Media Type");
3014:                // WebDav Status Codes
3015:                addStatusCodeMap(SC_MULTI_STATUS, "Multi-Status");
3016:                addStatusCodeMap(SC_UNPROCESSABLE_ENTITY,
3017:                        "Unprocessable Entity");
3018:                addStatusCodeMap(SC_INSUFFICIENT_SPACE_ON_RESOURCE,
3019:                        "Insufficient Space On Resource");
3020:                addStatusCodeMap(SC_METHOD_FAILURE, "Method Failure");
3021:                addStatusCodeMap(SC_LOCKED, "Locked");
3022:            }
3023:
3024:            // --------------------------------------------------------- Public Methods
3025:
3026:            /**
3027:             * Returns the HTTP status text for the HTTP or WebDav status code
3028:             * specified by looking it up in the static mapping.  This is a
3029:             * static function.
3030:             *
3031:             * @param   nHttpStatusCode [IN] HTTP or WebDAV status code
3032:             * @return  A string with a short descriptive phrase for the
3033:             *                  HTTP status code (e.g., "OK").
3034:             */
3035:            public static String getStatusText(int nHttpStatusCode) {
3036:                Integer intKey = new Integer(nHttpStatusCode);
3037:
3038:                if (!mapStatusCodes.containsKey(intKey)) {
3039:                    return "";
3040:                } else {
3041:                    return (String) mapStatusCodes.get(intKey);
3042:                }
3043:            }
3044:
3045:            // -------------------------------------------------------- Private Methods
3046:
3047:            /**
3048:             * Adds a new status code -> status text mapping.  This is a static
3049:             * method because the mapping is a static variable.
3050:             *
3051:             * @param   nKey    [IN] HTTP or WebDAV status code
3052:             * @param   strVal  [IN] HTTP status text
3053:             */
3054:            private static void addStatusCodeMap(int nKey, String strVal) {
3055:                mapStatusCodes.put(new Integer(nKey), strVal);
3056:            }
3057:
3058:        };
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.