Source Code Cross Referenced for WebdavServlet.java in  » Sevlet-Container » tomcat-catalina » 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 » tomcat catalina » org.apache.catalina.servlets 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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