KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > slide > webdav > JahiaWebdavServlet


1 /*
2  * $Header$
3  * $Revision: 11180 $
4  * $Date: 2005-10-14 16:04:28 +0200 (Fri, 14 Oct 2005) $
5  *
6  * ====================================================================
7  *
8  * Copyright 1999-2002 The Apache Software Foundation
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  */

23
24 package org.apache.slide.webdav;
25
26 import java.io.IOException JavaDoc;
27 import java.text.SimpleDateFormat JavaDoc;
28 import java.util.Date JavaDoc;
29
30 import javax.servlet.RequestDispatcher JavaDoc;
31 import javax.servlet.ServletConfig JavaDoc;
32 import javax.servlet.ServletException JavaDoc;
33 import javax.servlet.http.HttpServlet JavaDoc;
34 import javax.servlet.http.HttpServletRequest JavaDoc;
35 import javax.servlet.http.HttpServletResponse JavaDoc;
36 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
37 import javax.xml.parsers.ParserConfigurationException JavaDoc;
38 import javax.xml.parsers.FactoryConfigurationError JavaDoc;
39
40 import org.apache.slide.authenticate.SecurityToken;
41 import org.apache.slide.common.Domain;
42 import org.apache.slide.common.NamespaceAccessToken;
43 import org.apache.slide.common.SlideException;
44 import org.apache.slide.common.SlideToken;
45 import org.apache.slide.common.SlideTokenWrapper;
46 import org.apache.slide.security.AccessDeniedException;
47 import org.apache.slide.structure.LinkedObjectNotFoundException;
48 import org.apache.slide.structure.ObjectNotFoundException;
49 import org.apache.slide.util.logger.Logger;
50 import org.apache.slide.util.Configuration;
51 import org.apache.slide.webdav.util.DirectoryIndexGenerator;
52 import org.apache.slide.webdav.util.WebdavUtils;
53 import org.apache.slide.webdav.method.*;
54 import org.apache.webdav.lib.util.WebdavStatus;
55 import org.jahia.bin.Jahia;
56 import org.jahia.services.webdav.HttpRequestWrapper;
57 import org.jahia.services.database.ConnectionDispenser;
58 import org.jahia.services.cache.CacheFactory;
59 import org.jahia.exceptions.JahiaException;
60
61 /**
62  * The WebDAV servlet. It is responsible for dispatching incoming requests to
63  * implementations of the WebdavMethod interface.
64  *
65  * @author <a HREF="mailto:remm@apache.org">Remy Maucherat</a>
66  * @author Dirk Verbeeck
67  * @author <a HREF="mailto:cmlenz@apache.org">Christopher Lenz</a>
68  * @version $Revision: 11180 $
69  */

70 public class JahiaWebdavServlet
71     extends HttpServlet JavaDoc {
72
73
74     // -------------------------------------------------------------- Constants
75

76
77     /**
78      * Name of the log channel used by the WebDAV servlet.
79      */

80     private static final String JavaDoc LOG_CHANNEL = JahiaWebdavServlet.class.getName();
81
82
83     // ----------------------------------------------------- Instance Variables
84

85     public static final String JavaDoc ATTRIBUTE_NAME =
86         "org.apache.slide.NamespaceAccessToken";
87
88     /**
89      * Directory browsing enabled.
90      */

91     protected boolean directoryBrowsing = true;
92
93     /**
94      * Is authentication still needed for public files ?
95      */

96     private boolean authenticate;
97
98     /**
99      * RequestDispatcher to the directory browsing template, if specified.
100      */

101     protected RequestDispatcher JavaDoc directoryBrowsingTemplate;
102
103     // -------------------------------------------------------- Servlet Methods
104

105     protected void service (HttpServletRequest JavaDoc req, HttpServletResponse JavaDoc resp)
106         throws ServletException JavaDoc, IOException JavaDoc {
107
108         req.setAttribute("slide_uri", WebdavUtils.getRelativePath(req, (WebdavServletConfig) getServletConfig()));
109
110         try {
111             req = new HttpRequestWrapper(req);
112         } catch (JahiaException e) {
113             e.printStackTrace();
114             resp.sendError(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
115         }
116         NamespaceAccessToken token = (NamespaceAccessToken) req.getAttribute(HttpRequestWrapper.TOKEN_ATTRIBUTE);
117
118         if (token == null) {
119             resp.sendError(HttpServletResponse.SC_NOT_FOUND);
120             return;
121         }
122
123         SimpleDateFormat JavaDoc sdf = new SimpleDateFormat JavaDoc();
124         if( token.getLogger().isEnabled(LOG_CHANNEL, Logger.DEBUG) )
125             token.getLogger().log("==> "+req.getMethod()+" start: "+sdf.format(new Date JavaDoc(System.currentTimeMillis()))+" ["+Thread.currentThread().getName()+"]", LOG_CHANNEL, Logger.DEBUG);
126
127         if (authenticate &&
128             !req.getMethod().equals("GET") &&
129             !req.getMethod().equals("HEAD") &&
130             req.getUserPrincipal() == null) {
131             resp.addHeader("WWW-Authenticate", "BASIC realm=\"" + token.getName() + "\"");
132             resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
133         }
134
135         try {
136
137             if (token == null) {
138                 String JavaDoc namespaceName = req.getContextPath();
139                 if ((namespaceName == null) || (namespaceName.equals(""))) {
140                     namespaceName = Domain.getDefaultNamespace();
141                 }
142                 while (namespaceName.startsWith("/")) {
143                     namespaceName = namespaceName.substring(1);
144                 }
145                 token = Domain.accessNamespace(new SecurityToken(this), namespaceName);
146             }
147
148             req.setAttribute(ATTRIBUTE_NAME, token);
149
150             resp.setStatus(WebdavStatus.SC_OK);
151
152             String JavaDoc methodName = req.getMethod();
153             if ((methodName.equalsIgnoreCase("GET") ||
154                      methodName.equalsIgnoreCase("POST")) &&
155                 isCollection(token, req)) {
156                 // let the standard doGet() / doPost() methods handle
157
// GET/POST requests on collections (to display a directory
158
// index pag or something similar)
159
super.service(req, resp);
160             } else {
161                 WebdavMethod method = createMethod(token, methodName);
162                 if (method == null) {
163                     throw new WebdavException(WebdavStatus.SC_METHOD_NOT_ALLOWED);
164                 } else {
165                     method.run(req, resp);
166                 }
167             }
168         } catch (WebdavException e) {
169             // There has been an error somewhere ...
170
token.getLogger().log(e,LOG_CHANNEL, Logger.ERROR);
171             try { resp.sendError(e.getStatusCode()); } catch (Throwable JavaDoc ex) { }
172             if (e.getStatusCode() == WebdavStatus.SC_UNAUTHORIZED) {
173                 resp.addHeader("WWW-Authenticate", "BASIC realm=\"" + ((NamespaceAccessToken) req.getAttribute(HttpRequestWrapper.TOKEN_ATTRIBUTE)).getName() + "\"");
174             }
175         } catch (Throwable JavaDoc e) {
176             // If something goes really wrong ...
177
token.getLogger().log(e,LOG_CHANNEL, Logger.ERROR);
178             try { resp.sendError(WebdavStatus.SC_INTERNAL_SERVER_ERROR); } catch (Throwable JavaDoc ex) { }
179         }
180         finally {
181             if( token.getLogger().isEnabled(LOG_CHANNEL, Logger.DEBUG) )
182                 token.getLogger().log("<== "+req.getMethod()+" end: "+sdf.format(new Date JavaDoc(System.currentTimeMillis()))+" ["+Thread.currentThread().getName()+"]", LOG_CHANNEL, Logger.DEBUG);
183
184             ConnectionDispenser.terminateConnection();
185             CacheFactory.getInstance().syncCachesNow();
186         }
187
188     }
189
190     private boolean isCollection(NamespaceAccessToken token, HttpServletRequest JavaDoc req) {
191         SlideToken slideToken = new SlideTokenWrapper(WebdavUtils.getSlideToken(req));
192         slideToken.setForceSecurity(false);
193         slideToken.setForceLock(false);
194         return WebdavUtils.isCollection(token, slideToken, WebdavUtils.getRelativePath(req, (WebdavServletConfig)getServletConfig()));
195     }
196
197     /**
198      * Implemented to wrap the ServletConfig object inside a
199      * WebdavServletConfig
200      */

201     public void init(ServletConfig JavaDoc config)
202         throws ServletException JavaDoc {
203
204         JahiaWebdavServletConfig webdavServletConfig = new JahiaWebdavServletConfig(config);
205         webdavServletConfig.setTransformDirnames(Jahia.getSettings().isTransformDirnames());
206         webdavServletConfig.setTransformFilenames(Jahia.getSettings().isTransformFilenames());
207
208         super.init(webdavServletConfig);
209
210         // all the actual initialization is inside init()
211

212         ConnectionDispenser.terminateConnection();
213     }
214
215
216     /**
217      * Manages some initialization stuff on the server.
218      */

219     public void init()
220         throws ServletException JavaDoc {
221
222         if (!isDomLevel2Parser()) {
223             log("======================================================");
224             log("!!! Unable to start Slide Servlet !!!");
225             log("------------------------------------------------------");
226             log("======================================================");
227             log("You are using using an incorrect older XML parser");
228             log("that doesn't provide Element::getElementsByTagNameNS");
229             log("consult the documentation for a list of valid XML parsers.");
230             log("======================================================");
231             throw new ServletException JavaDoc("Invalid XML parser");
232         }
233
234         String JavaDoc value;
235
236         // Check whether directory browsing is enabled, and how it should be
237
// accomplished
238
value = getInitParameter("directory-browsing");
239         if (value != null) {
240             if (value.startsWith("/")) {
241                 directoryBrowsingTemplate =
242                     getServletContext().getRequestDispatcher(value);
243                 if (directoryBrowsingTemplate == null) {
244                     directoryBrowsing = false;
245                 }
246             } else {
247                 directoryBrowsing = Boolean.valueOf(value).booleanValue();
248             }
249         }
250
251         value = getInitParameter("authenticate");
252         if (value != null) {
253             authenticate = new Boolean JavaDoc(value).booleanValue();
254         }
255     }
256
257
258     /**
259      * Destroy servlet.
260      */

261     public void destroy() {
262     }
263
264
265
266     // ------------------------------------------------------ Protected Methods
267

268
269     /**
270      * Handle a GET request on a collection resource.
271      */

272     protected void doGet(HttpServletRequest JavaDoc req, HttpServletResponse JavaDoc res)
273         throws ServletException JavaDoc, IOException JavaDoc {
274
275
276         if (directoryBrowsing) {
277
278             NamespaceAccessToken token = (NamespaceAccessToken) req.getAttribute(ATTRIBUTE_NAME);
279
280             if (directoryBrowsingTemplate != null) {
281                 // attributes used by the tag library
282
req.setAttribute("org.apache.slide.NamespaceName",
283                                  token.getName());
284                 // attributes for general use
285
req.setAttribute("slide_namespace", token.getName());
286                 directoryBrowsingTemplate.forward(req, res);
287              } else {
288                 try {
289                     DirectoryIndexGenerator directoryIndexGenerator = new DirectoryIndexGenerator(token, (WebdavServletConfig) getServletConfig());
290                     SlideToken slideToken = new SlideTokenWrapper(WebdavUtils.getSlideToken(req));
291                     directoryIndexGenerator.generate(req, res, slideToken);
292                 } catch (AccessDeniedException e) {
293                     if (req.getUserPrincipal() == null) {
294                         res.addHeader("WWW-Authenticate", "BASIC realm=\"" + ((NamespaceAccessToken) req.getAttribute(HttpRequestWrapper.TOKEN_ATTRIBUTE)).getName() + "\"");
295                         res.sendError(HttpServletResponse.SC_UNAUTHORIZED);
296                     } else {
297                         res.setStatus(WebdavStatus.SC_FORBIDDEN);
298                         RequestDispatcher JavaDoc r = req.getRequestDispatcher("/jsp/jahia/errors/error_403.jsp");
299                         r.include(req,res);
300                     }
301                 } catch (ObjectNotFoundException e) {
302                     res.sendError(WebdavStatus.SC_NOT_FOUND);
303                 } catch (LinkedObjectNotFoundException e) {
304                     res.sendError(WebdavStatus.SC_NOT_FOUND);
305                 } catch (SlideException e) {
306                     res.setStatus(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
307                 }
308             }
309         } else {
310             res.setStatus(WebdavStatus.SC_FORBIDDEN);
311             RequestDispatcher JavaDoc r = req.getRequestDispatcher("/jsp/jahia/errors/error_403.jsp");
312             r.include(req,res);
313         }
314     }
315
316
317
318     private WebdavMethod createMethod(NamespaceAccessToken token, String JavaDoc name) {
319         WebdavServletConfig config = (WebdavServletConfig)getServletConfig();
320
321         if ((config == null) || (token == null)) {
322             throw new IllegalStateException JavaDoc();
323         }
324
325         if (name.equals("GET")) {
326             return new GetMethod(token, config) {
327                 protected void sendError( int statusCode, Throwable JavaDoc t ) {
328                     if (statusCode == WebdavStatus.SC_FORBIDDEN) {
329                         resp.setStatus(WebdavStatus.SC_FORBIDDEN);
330                         RequestDispatcher JavaDoc r = req.getRequestDispatcher("/jsp/jahia/errors/error_403.jsp");
331                         try {
332                             r.include(req,resp);
333                         } catch (Exception JavaDoc e) {
334                             super.sendError(statusCode, t);
335                         }
336                     } else {
337                         super.sendError(statusCode, t);
338                     }
339                 }
340             };
341         } else if (name.equals("PROPFIND")) {
342             return new PropFindMethod(token, config);
343         } else if (name.equals("HEAD")) {
344             return new HeadMethod(token, config);
345         } else if (name.equals("LOCK")) {
346             return new LockMethod(token, config);
347         } else if (name.equals("UNLOCK")) {
348             return new UnlockMethod(token, config);
349         } else if (name.equals("OPTIONS")) {
350             return new OptionsMethod(token, config);
351         } else if (name.equals("PUT")) {
352             return new PutMethod(token, config);
353         } else if (name.equals("MKCOL")) {
354             return new MkcolMethod(token, config);
355         } else if (name.equals("POST")) {
356             return new PostMethod(token, config);
357         } else if (name.equals("COPY")) {
358             return new CopyMethod(token, config);
359         } else if (name.equals("MOVE")) {
360             return new MoveMethod(token, config);
361         } else if (name.equals("DELETE")) {
362             return new DeleteMethod(token, config);
363         } else if (name.equals("PROPPATCH")) {
364             return new PropPatchMethod(token, config);
365         } else if (name.equals("REPORT")) {
366             return new ReportMethod(token, config);
367         } else {
368             if (Configuration.useIntegratedSecurity()) {
369                 if (name.equals("ACL")) {
370                     return new AclMethod(token, config);
371                 }
372             }
373             if (Configuration.useSearch()) {
374                 if (name.equals("SEARCH")) {
375                     return new SearchMethod(token, config);
376                 }
377             }
378             if (Configuration.useVersionControl()) {
379                 if (name.equals("VERSION-CONTROL")) {
380                     return new VersionControlMethod(token, config);
381                 } else if (name.equals("CHECKIN")) {
382                     return new CheckinMethod(token, config);
383                 } else if (name.equals("CHECKOUT")) {
384                     return new CheckoutMethod(token, config);
385                 } else if (name.equals("UNCHECKOUT")) {
386                     return new UncheckoutMethod(token, config);
387                 } else if (name.equals("MKWORKSPACE")) {
388                     return new MkworkspaceMethod(token, config);
389                 } else if (name.equals("LABEL")) {
390                     return new LabelMethod(token, config);
391                 } else if (name.equals("UPDATE")) {
392                     return new UpdateMethod(token, config);
393                 }
394             }
395             if (Configuration.useGlobalBinding()) {
396                 if (name.equals("BIND")) {
397                     return new BindMethod(token, config);
398                 } else if (name.equals("UNBIND")) {
399                     return new UnbindMethod(token, config);
400                 } else if (name.equals("REBIND")) {
401                     return new RebindMethod(token, config);
402                 }
403             }
404         }
405
406         return null;
407     }
408
409
410     static boolean isDomLevel2Parser() {
411         try {
412             return DocumentBuilderFactory.newInstance().newDocumentBuilder()
413                     .getDOMImplementation().hasFeature("Core", "2.0");
414         } catch (ParserConfigurationException JavaDoc e) {
415             return false;
416         } catch (FactoryConfigurationError JavaDoc e) {
417             return false;
418         }
419     }
420 }
421
Popular Tags