Source code: org/apache/slide/webdav/WebdavServlet.java
1 /*
2 * $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/WebdavServlet.java,v 1.63.2.1 2004/10/30 18:29:16 ozeigermann Exp $
3 * $Revision: 1.63.2.1 $
4 * $Date: 2004/10/30 18:29:16 $
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;
27 import java.net.URL;
28 import java.text.SimpleDateFormat;
29 import java.util.Date;
30
31 import javax.servlet.RequestDispatcher;
32 import javax.servlet.ServletConfig;
33 import javax.servlet.ServletException;
34 import javax.servlet.UnavailableException;
35 import javax.servlet.http.HttpServlet;
36 import javax.servlet.http.HttpServletRequest;
37 import javax.servlet.http.HttpServletResponse;
38 import javax.xml.parsers.DocumentBuilderFactory;
39 import javax.xml.parsers.FactoryConfigurationError;
40 import javax.xml.parsers.ParserConfigurationException;
41
42 import org.apache.slide.authenticate.SecurityToken;
43 import org.apache.slide.common.Domain;
44 import org.apache.slide.common.DomainInitializationFailedError;
45 import org.apache.slide.common.NamespaceAccessToken;
46 import org.apache.slide.common.SlideException;
47 import org.apache.slide.common.SlideToken;
48 import org.apache.slide.common.SlideTokenWrapper;
49 import org.apache.slide.security.AccessDeniedException;
50 import org.apache.slide.structure.LinkedObjectNotFoundException;
51 import org.apache.slide.structure.ObjectNotFoundException;
52 import org.apache.slide.util.logger.Logger;
53 import org.apache.slide.webdav.util.DirectoryIndexGenerator;
54 import org.apache.slide.webdav.util.WebdavConstants;
55 import org.apache.slide.webdav.util.WebdavStatus;
56 import org.apache.slide.webdav.util.WebdavUtils;
57
58 /**
59 * The WebDAV servlet. It is responsible for dispatching incoming requests to
60 * implementations of the WebdavMethod interface.
61 *
62 * @version $Revision: 1.63.2.1 $
63 */
64 public class WebdavServlet extends HttpServlet {
65
66 // -------------------------------------------------------------- Constants
67
68
69 /**
70 * Name of the log channel used by the WebDAV servlet.
71 */
72 private static final String LOG_CHANNEL = WebdavServlet.class.getName();
73
74
75 /**
76 * Name under which the namespace access token is stored in the application
77 * attributes. This is used when the WebDAV servlet doesn't initialize
78 * Slide itself, but rather the initialization is done outside.
79 */
80 public static final String ATTRIBUTE_NAME =
81 "org.apache.slide.NamespaceAccessToken";
82
83
84 // ----------------------------------------------------- Instance Variables
85
86
87 /**
88 * Access token to the namespace.
89 */
90 protected NamespaceAccessToken token;
91
92
93 /**
94 * Directory browsing enabled.
95 */
96 protected boolean directoryBrowsing = true;
97
98
99 /**
100 * RequestDispatcher to the directory browsing template, if specified.
101 */
102 protected RequestDispatcher directoryBrowsingTemplate;
103
104
105 /**
106 * Directory browsing enabled.
107 */
108 protected DirectoryIndexGenerator directoryIndexGenerator;
109
110
111 /**
112 * Set to true if the servlet is handling the lifecycle of the domain.
113 */
114 protected boolean handleLifecycle = true;
115
116
117 /**
118 * Instance of the WebdavMethodFactory to use by this servlet.
119 */
120 protected WebdavMethodFactory methodFactory;
121
122
123 // -------------------------------------------------------- Servlet Methods
124
125
126 protected void service (HttpServletRequest req, HttpServletResponse resp)
127 throws ServletException, IOException {
128
129 SimpleDateFormat sdf = new SimpleDateFormat();
130 if( token.getLogger().isEnabled(LOG_CHANNEL, Logger.DEBUG) )
131 token.getLogger().log("==> "+req.getMethod()+" start: "+sdf.format(new Date(System.currentTimeMillis()))+" ["+Thread.currentThread().getName()+"]", LOG_CHANNEL, Logger.DEBUG);
132
133 req.setAttribute("slide_uri", WebdavUtils.getRelativePath(req, (WebdavServletConfig) getServletConfig()));
134
135 try {
136
137 if (token == null) {
138 String 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 resp.setStatus(WebdavStatus.SC_OK);
149
150 String methodName = req.getMethod();
151 WebdavMethod method = methodFactory.createMethod(methodName);
152 if (method == null) {
153 throw new WebdavException(WebdavStatus.SC_METHOD_NOT_ALLOWED);
154 } else {
155 method.run(req, resp);
156 }
157 } catch (WebdavException e) {
158 // There has been an error somewhere ...
159 token.getLogger().log(e,LOG_CHANNEL, Logger.ERROR);
160 try { resp.sendError(e.getStatusCode()); } catch (Throwable ex) { }
161 } catch (Throwable e) {
162 // If something goes really wrong ...
163 token.getLogger().log(e,LOG_CHANNEL, Logger.ERROR);
164 try { resp.sendError(WebdavStatus.SC_INTERNAL_SERVER_ERROR); } catch (Throwable ex) { }
165 }
166 finally {
167 if( token.getLogger().isEnabled(LOG_CHANNEL, Logger.DEBUG) )
168 token.getLogger().log("<== "+req.getMethod()+" end: "+sdf.format(new Date(System.currentTimeMillis()))+" ["+Thread.currentThread().getName()+"]", LOG_CHANNEL, Logger.DEBUG);
169 }
170
171 }
172
173 private boolean isExtTx(HttpServletRequest req) {
174 String hTxIdStr = req.getHeader(WebdavConstants.H_TRANSACTION);
175 return (hTxIdStr != null);
176 }
177
178 private boolean isCollection(HttpServletRequest req) {
179 SlideToken slideToken = new SlideTokenWrapper(WebdavUtils.getSlideToken(req));
180 // necessary as no transaction has been started, yet
181 slideToken.setForceStoreEnlistment(false);
182 slideToken.setForceSecurity(false);
183 slideToken.setForceLock(false);
184
185 return WebdavUtils.isCollection(token, slideToken, WebdavUtils.getRelativePath(req, (WebdavServletConfig)getServletConfig()));
186 }
187
188 /**
189 * Implemented to wrap the ServletConfig object inside a
190 * WebdavServletConfig
191 */
192 public void init(ServletConfig config)
193 throws ServletException {
194
195 super.init(new WebdavServletConfig(config));
196
197 // all the actual initialization is inside init()
198 }
199
200
201 /**
202 * Manages some initialization stuff on the server.
203 */
204 public void init()
205 throws ServletException {
206
207 if (!isDomLevel2Parser()) {
208 System.out.println("======================================================");
209 System.out.println("!!! Unable to start Slide Servlet !!!");
210 System.out.println("------------------------------------------------------");
211 System.out.println("You are using using an incorrect older XML parser");
212 System.out.println("that doesn't provide Element::getElementsByTagNameNS");
213 System.out.println("consult the documentation for a list of valid XML parsers.");
214 System.out.println("======================================================");
215
216 log("======================================================");
217 log("!!! Unable to start Slide Servlet !!!");
218 log("------------------------------------------------------");
219 log("======================================================");
220 log("You are using using an incorrect older XML parser");
221 log("that doesn't provide Element::getElementsByTagNameNS");
222 log("consult the documentation for a list of valid XML parsers.");
223 log("======================================================");
224 throw new ServletException("Invalid XML parser");
225 }
226
227 String value = null;
228
229 // Lookup for the NAT using JNDI
230 // FIXME
231
232 // Lookup for the NAT using the servlet context
233 token = (NamespaceAccessToken)
234 getServletContext().getAttribute(ATTRIBUTE_NAME);
235 if (token == null) {
236 // Dafault initialization
237 String namespaceName = null;
238 String domainConfigFile = null;
239 value = getInitParameter("namespace");
240 if (value != null) {
241 namespaceName = value;
242 }
243 value = getInitParameter("domain");
244 if (value != null) {
245 domainConfigFile = value;
246 }
247 try {
248
249 if (domainConfigFile != null) {
250 URL domainConfigFileURL =
251 getServletContext().getResource(domainConfigFile);
252 if (domainConfigFileURL != null) {
253 Domain.init(domainConfigFileURL);
254 }
255 }
256
257 if (namespaceName == null) {
258 namespaceName = Domain.getDefaultNamespace();
259 log("No namespace specified, will use default namespace: " +
260 namespaceName);
261 }
262
263 token = Domain.accessNamespace
264 (new SecurityToken(this), namespaceName);
265 if (token == null) {
266 log("Could not access namespace " + namespaceName + ".");
267 throw new UnavailableException("Namespace " + namespaceName +
268 " not accessible");
269 }
270 getServletContext().setAttribute(ATTRIBUTE_NAME, token);
271
272 } catch (DomainInitializationFailedError e) {
273 log("Could not initialize domain", e);
274 throw new UnavailableException(e.toString());
275 } catch (Throwable t) {
276 t.printStackTrace();
277 throw new ServletException(t.toString());
278 }
279 } else {
280 handleLifecycle = false;
281 }
282
283 // Setup the method factory
284 methodFactory =
285 WebdavMethodFactory.newInstance((WebdavServletConfig)getServletConfig());
286
287 // Check whether directory browsing is enabled, and how it should be
288 // accomplished
289 // value = getInitParameter("directory-browsing");
290 // if (value != null) {
291 // if (value.startsWith("/")) {
292 // directoryBrowsingTemplate =
293 // getServletContext().getRequestDispatcher(value);
294 // if (directoryBrowsingTemplate == null) {
295 // directoryBrowsing = false;
296 // }
297 // } else {
298 // directoryBrowsing = Boolean.valueOf(value).booleanValue();
299 // }
300 // }
301 // if (directoryBrowsing) {
302 // directoryIndexGenerator =
303 // new DirectoryIndexGenerator
304 // (token, (WebdavServletConfig)getServletConfig());
305 // }
306 }
307
308
309 /**
310 * Destroy servlet.
311 */
312 public void destroy() {
313
314 if (handleLifecycle) {
315 if (token != null) {
316 Domain.closeNamespace(token);
317 }
318 }
319 }
320
321
322
323 // ------------------------------------------------------ Protected Methods
324
325
326 /**
327 * Handle a GET request on a collection resource.
328 */
329 // protected void doGet(HttpServletRequest req, HttpServletResponse res)
330 // throws ServletException, IOException {
331 //
332 // if (directoryBrowsing) {
333 // if (directoryBrowsingTemplate != null) {
334 // // attributes used by the tag library
335 // req.setAttribute("org.apache.slide.NamespaceName",
336 // token.getName());
337 // // attributes for general use
338 // req.setAttribute("slide_namespace", token.getName());
339 // directoryBrowsingTemplate.forward(req, res);
340 // } else {
341 // try {
342 // directoryIndexGenerator.generate(req, res);
343 // } catch (AccessDeniedException e) {
344 // res.sendError(WebdavStatus.SC_FORBIDDEN);
345 // } catch (ObjectNotFoundException e) {
346 // res.sendError(WebdavStatus.SC_NOT_FOUND);
347 // } catch (LinkedObjectNotFoundException e) {
348 // res.sendError(WebdavStatus.SC_NOT_FOUND);
349 // } catch (SlideException e) {
350 // res.setStatus(WebdavStatus.SC_INTERNAL_SERVER_ERROR);
351 // }
352 // }
353 // } else {
354 // res.sendError(WebdavStatus.SC_FORBIDDEN);
355 // }
356 // }
357
358 static boolean isDomLevel2Parser() {
359 try {
360 return DocumentBuilderFactory.newInstance().newDocumentBuilder()
361 .getDOMImplementation().hasFeature("Core", "2.0");
362 } catch (ParserConfigurationException e) {
363 return false;
364 } catch (FactoryConfigurationError e) {
365 return false;
366 }
367 }
368
369 }
370