KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sslexplorer > vfs > webdav > DAVServlet


1 /* ========================================================================== *
2  * Copyright (C) 2004-2005 Pier Fumagalli <http://www.betaversion.org/~pier/> *
3  * All rights reserved. *
4  * ========================================================================== *
5  * *
6  * Licensed under the Apache License, Version 2.0 (the "License"). You may *
7  * not use this file except in compliance with the License. You may obtain a *
8  * copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>. *
9  * *
10  * Unless required by applicable law or agreed to in writing, software *
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT *
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the *
13  * License for the specific language governing permissions and limitations *
14  * under the License. *
15  * *
16  * ========================================================================== */

17 package com.sslexplorer.vfs.webdav;
18
19 import java.io.IOException JavaDoc;
20 import java.util.ArrayList JavaDoc;
21 import java.util.Enumeration JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.List JavaDoc;
24
25 import javax.servlet.Servlet JavaDoc;
26 import javax.servlet.ServletConfig JavaDoc;
27 import javax.servlet.ServletContext JavaDoc;
28 import javax.servlet.ServletException JavaDoc;
29 import javax.servlet.ServletRequest JavaDoc;
30 import javax.servlet.ServletResponse JavaDoc;
31 import javax.servlet.http.HttpServletRequest JavaDoc;
32 import javax.servlet.http.HttpServletResponse JavaDoc;
33 import javax.servlet.http.HttpSessionBindingEvent JavaDoc;
34 import javax.servlet.http.HttpSessionBindingListener JavaDoc;
35
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38 import org.apache.struts.Globals;
39 import org.apache.struts.action.ActionMessages;
40 import org.apache.struts.util.MessageResources;
41
42 import com.sslexplorer.core.BundleActionMessage;
43 import com.sslexplorer.core.CoreException;
44 import com.sslexplorer.core.CoreUtil;
45 import com.sslexplorer.policyframework.LaunchSession;
46 import com.sslexplorer.properties.PropertyProfile;
47 import com.sslexplorer.security.Constants;
48 import com.sslexplorer.security.LogonControllerFactory;
49 import com.sslexplorer.security.SecurityErrorException;
50 import com.sslexplorer.security.SessionInfo;
51 import com.sslexplorer.security.User;
52 import com.sslexplorer.vfs.VFSRepository;
53 import com.sslexplorer.vfs.VFSResource;
54
55 /**
56  * <p>
57  * A very simple servlet capable of processing very simple <a
58  * HREF="http://www.rfc-editor.org/rfc/rfc2518.txt">WebDAV</a> requests.
59  * </p>
60  *
61  * <p>
62  * Modifications made to integrate with Commons-VFS and SSL-Explorer.
63  * </p>
64  *
65  * @author <a HREF="http://www.betaversion.org/~pier/">Pier Fumagalli</a>
66  * @author <a HREF="http://3sp.com/">Brett Smith</a>
67  *
68  */

69 public class DAVServlet implements Servlet JavaDoc, DAVListener {
70
71     final static Log log = LogFactory.getLog(DAVServlet.class);
72
73     /**
74      * <p>
75      * The session attribute in which the {@link DAVProcessor} is stored
76      */

77     private static String JavaDoc PROCESSOR_ATTR = "davServlet.processor";
78
79     /**
80      * <p>
81      * The session attribute in which the {@link SessionInvalidateListener} is
82      * stored
83      */

84     private static String JavaDoc SESSION_INVALIDATE_LISTENER_ATTR = "davServlet.sessionInvalidateListener";
85
86     /**
87      * <p>
88      * The version of this servlet.
89      * </p>
90      */

91     private static String JavaDoc SIGNATURE = DAVUtilities.getProperty("servlet.signature") + '/' + DAVUtilities.getProperty("version");
92     /**
93      * <p>
94      * The version of this servlet.
95      * </p>
96      */

97     private static String JavaDoc INFORMATION = DAVUtilities.getProperty("servlet.information") + " version "
98         + DAVUtilities.getProperty("version");
99     /**
100      * <p>
101      * The {@link ServletContext} associated with this instance.
102      * </p>
103      */

104     private ServletContext JavaDoc context = null;
105     /**
106      * <p>
107      * The {@link ServletConfig} associated with this instance.
108      * </p>
109      */

110     private ServletConfig JavaDoc config = null;
111     /**
112      * <p>
113      * A list of processors in use.
114      * </p>
115      */

116     private static List JavaDoc processors = new ArrayList JavaDoc();
117
118     /**
119      * <p>
120      * Create a new {@link DAVServlet} instance.
121      * </p>
122      */

123     public DAVServlet() {
124         super();
125     }
126
127     /**
128      * <p>
129      * Initialize this {@link Servlet} instance.
130      * </p>
131      *
132      * <p>
133      * The only initialization parameter required by this servlet is the &quot;<code>rootPath</code>&quot;
134      * parameter specifying the path of the repository root (either absolute or
135      * relative to the configured {@link ServletContext}.
136      * </p>
137      *
138      * <p>
139      * If the specified root is relative, it will be considered to be relative
140      * to the {@link ServletContext} deployment path.
141      * </p>
142      *
143      * <p>
144      * In any case, the specified root must ultimately point to an existing
145      * directory on a locally-accessible file system.
146      * </p>
147      *
148      * <p>
149      * When set to <code>true</code>, an optional parameter called
150      * <code>xmlOnly</code> will force this {@link DAVServlet} to use an
151      * {@link XMLRepository} instead of the default {@link VFSRepository}.
152      * </p>
153      *
154      * <p>
155      * Finally, when set to <code>true</code>, the optional parameter
156      * <code>debugEnabled</code> will enable logging of method invocation and
157      * events in the repository.
158      * </p>
159      */

160     public void init(ServletConfig JavaDoc config) throws ServletException JavaDoc {
161         /* Remember the configuration instance */
162         this.context = config.getServletContext();
163         this.config = config;
164
165     }
166
167     /**
168      * <p>
169      * Detroy this {@link Servlet} instance.
170      * </p>
171      */

172     public void destroy() {
173         for (Iterator JavaDoc i = processors.iterator(); i.hasNext();) {
174             ((DAVProcessor) i.next()).getRepository().removeListener(this);
175         }
176     }
177
178     /**
179      * <p>
180      * Return the {@link ServletConfig} associated with this instance.
181      * </p>
182      */

183     public ServletConfig JavaDoc getServletConfig() {
184         return (this.config);
185     }
186
187     /**
188      * <p>
189      * Return the {@link ServletContext} associated with this instance.
190      * </p>
191      */

192     public ServletContext JavaDoc getServletContext() {
193         return (this.context);
194     }
195
196     /**
197      * <p>
198      * Return a informative {@link String} about this servlet.
199      * </p>
200      */

201     public String JavaDoc getServletInfo() {
202         return INFORMATION;
203     }
204
205     public static DAVSession updateDAVSession(HttpServletRequest JavaDoc request, String JavaDoc resourcePath) {
206         // This provides a key on which the store can lookup up webdav session
207
// ids
208

209         request.getSession().setAttribute("com.sslexplorer.vfs.webdav.DAVMethod", request.getSession().getId());
210         DAVSession webdavSession = DAVSessionStore.getInstance().getSession(request.getSession().getId());
211         if (webdavSession == null) {
212             webdavSession = new DAVSession(request.getSession().getId());
213             DAVSessionStore.getInstance().addSession(webdavSession);
214         }
215         PropertyProfile profile = (PropertyProfile) request.getSession().getAttribute(Constants.SELECTED_PROFILE);
216         if (profile != null) {
217             webdavSession.setAttribute(DAVSession.ATTR_PROFILE, profile);
218         }
219         try {
220             User user = LogonControllerFactory.getInstance().getUser(request);
221             if (user != null) {
222                 webdavSession.setAttribute(DAVSession.ATTR_USER, user);
223             }
224         } catch (SecurityErrorException e1) {
225         }
226         if (resourcePath != null) {
227             webdavSession.setAttribute(DAVSession.ATTR_RESOURCE_PATH, resourcePath);
228         }
229         return webdavSession;
230     }
231
232     public static DAVProcessor getDAVProcessor(HttpServletRequest JavaDoc req) throws CoreException, Exception JavaDoc {
233         SessionInfo session = LogonControllerFactory.getInstance().getSessionInfo(req);
234         return getDAVProcessor(session);
235     }
236
237     public static DAVProcessor getDAVProcessor(SessionInfo session) throws Exception JavaDoc {
238         DAVProcessor processor = (DAVProcessor) session.getHttpSession().getAttribute(PROCESSOR_ATTR);
239         if (processor == null) {
240             VFSRepository repository = VFSRepository.getRepository(session);
241             processor = new DAVProcessor(repository, session);
242             processors.add(processor);
243             session.getHttpSession().setAttribute(PROCESSOR_ATTR, processor);
244             session.getHttpSession().setAttribute(SESSION_INVALIDATE_LISTENER_ATTR, new SessionInvalidateListener(processor));
245             if (log.isInfoEnabled())
246                 log.info("Initialized repository");
247         }
248         return processor;
249     }
250
251     public static VFSResource getDAVResource(LaunchSession launchSession, HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, String JavaDoc path)
252                     throws DAVBundleActionMessageException, Exception JavaDoc {
253         VFSResource res = null;
254         try {
255             DAVProcessor processor = getDAVProcessor(request);
256             DAVTransaction transaction = new DAVTransaction(request, response);
257             res = processor.getRepository().getResource(launchSession, path, transaction.getCredentials());
258             // res.start(transaction);
259
res.verifyAccess();
260         } catch (DAVAuthenticationRequiredException e) {
261             DAVServlet.sendAuthorizationError(request, response, e.getHttpRealm());
262             throw e;
263         }
264         return res;
265     }
266
267     /**
268      * <p>
269      * Execute the current request.
270      * </p>
271      */

272     public void service(ServletRequest JavaDoc request, ServletResponse JavaDoc response) throws ServletException JavaDoc, IOException JavaDoc {
273         HttpServletRequest JavaDoc req = (HttpServletRequest JavaDoc) request;
274         HttpServletResponse JavaDoc res = (HttpServletResponse JavaDoc) response;
275
276         if (System.getProperty("sslexplorer.webdav.debug", "false").equalsIgnoreCase("true")) {
277             for (Enumeration JavaDoc e = req.getHeaderNames(); e.hasMoreElements();) {
278                 String JavaDoc header = (String JavaDoc) e.nextElement();
279                 for (Enumeration JavaDoc e2 = req.getHeaders(header); e2.hasMoreElements();) {
280                     log.info(header + ": " + (String JavaDoc) e2.nextElement());
281                 }
282             }
283         }
284
285         if (log.isDebugEnabled())
286             log.debug("Processing " + req.getMethod() + " " + req.getPathInfo());
287
288         DAVTransaction transaction = new DAVTransaction(req, res);
289
290         try {
291
292             if (transaction.verifyAuthorization()) {
293                 DAVServlet.updateDAVSession(req, transaction.getPath());
294
295                 DAVProcessor processor = null;
296                 try {
297                     processor = DAVServlet.getDAVProcessor(req);
298                 } catch (CoreException e) {
299                     ActionMessages mesgs = (ActionMessages) request.getAttribute(Globals.ERROR_KEY);
300                     if (mesgs == null) {
301                         mesgs = new ActionMessages();
302                         request.setAttribute(Globals.ERROR_KEY, mesgs);
303                     }
304                     mesgs.add(Globals.MESSAGE_KEY, e.getBundleActionMessage());
305                     return;
306                 } catch (Exception JavaDoc e1) {
307                     throw new IOException JavaDoc(e1.getMessage());
308                 }
309
310                 /**
311                  * LDP - JB I have removed the authentication code here and
312                  * instead placed in DAVTransaction. This allows the transaction
313                  * to correctly obtain sessionInfo through WEBDav.
314                  */

315                 /* Mark our presence */
316                 res.setHeader("Server", this.context.getServerInfo() + ' ' + SIGNATURE);
317                 res.setHeader("MS-Author-Via", "DAV");
318                 res.setHeader("DAV", "1");
319
320                 SessionInfo sessionInfo = transaction.getSessionInfo();
321                 int timeoutId = sessionInfo == null ? -1 : LogonControllerFactory.getInstance()
322                                 .addSessionTimeoutBlock(transaction.getSessionInfo().getHttpSession(), "DAV Transaction");
323                 ;
324                 try {
325                     processor.process(transaction);
326                 } finally {
327                     if (timeoutId != -1)
328                         LogonControllerFactory.getInstance().removeSessionTimeoutBlock(transaction.getSessionInfo()
329                                         .getHttpSession(),
330                             timeoutId);
331                 }
332             }
333         } catch (DAVRedirection redir) {
334             String JavaDoc redirPath = "/fs" + redir.getLocation().getFullPath();
335             req.getRequestDispatcher(redirPath).forward(req, res);
336         } catch (DAVAuthenticationRequiredException e) {
337             // We need to be able to authenticate the SSL-Explorer session was well
338
// sendAuthorizationError(req, res, e.getMount().getMountString());
339
sendAuthorizationError(req, res, e.getHttpRealm());
340         } catch(DAVBundleActionMessageException ex) {
341             log.error("Network Places Request Failed: " + req.getPathInfo(), ex);
342             BundleActionMessage bam = ex.getBundleActionMessage();
343             MessageResources mr = CoreUtil.getMessageResources(req.getSession(), bam.getBundle());
344             // TODO locale
345
String JavaDoc val = mr == null ? null : mr.getMessage(bam.getKey());
346             res.sendError(DAVStatus.SC_INTERNAL_SERVER_ERROR,
347                 val == null ? ( ex.getMessage() == null ? "No message supplied." : ex.getMessage()) : val);
348         } catch (DAVException ex) {
349             res.setStatus(ex.getStatus());
350         } catch (LockedException ex) {
351             res.sendError(DAVStatus.SC_LOCKED, ex.getMessage());
352         } catch (Throwable JavaDoc t) {
353             log.error("Network Places Request Failed: " + req.getPathInfo(), t);
354             res.sendError(DAVStatus.SC_INTERNAL_SERVER_ERROR, t.getMessage() == null ? "<null>" : t.getMessage());
355         }
356     }
357
358     private boolean isWebDAVMethod(HttpServletRequest JavaDoc request) {
359         return
360
361         /*
362          * BPS - WE *MUST* support GET at least for get file resources as it is
363          * used by application shortcuts HTML templates and other stuff GETing a
364          * directory listing iis also very *useful*
365          */

366
367         // !request.getMethod().equalsIgnoreCase("get") &&
368
!request.getMethod().equalsIgnoreCase("head") && !request.getMethod().equalsIgnoreCase("post");
369     }
370
371     public static void sendAuthorizationError(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, String JavaDoc realm)
372                     throws IOException JavaDoc {
373         if (log.isDebugEnabled())
374             log.debug("Sending auth request for realm " + realm);
375         response.setHeader("WWW-Authenticate", "Basic realm=\"" + realm + "\"");
376         response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
377     }
378
379     /**
380      * <p>
381      * Receive notification of an event occurred in a specific
382      * {@link VFSRepository}.
383      * </p>
384      */

385     public void notify(VFSResource resource, int event) {
386         String JavaDoc message = "Unknown event";
387         switch (event) {
388             case DAVListener.COLLECTION_CREATED:
389                 message = "Collection created";
390                 break;
391             case DAVListener.COLLECTION_REMOVED:
392                 message = "Collection removed";
393                 break;
394             case DAVListener.RESOURCE_CREATED:
395                 message = "Resource created";
396                 break;
397             case DAVListener.RESOURCE_REMOVED:
398                 message = "Resource removed";
399                 break;
400             case DAVListener.RESOURCE_MODIFIED:
401                 message = "Resource modified";
402                 break;
403         }
404         if (log.isDebugEnabled())
405             log.debug(message + ": \"" + resource.getRelativePath() + "\"");
406     }
407
408     static class SessionInvalidateListener implements HttpSessionBindingListener JavaDoc {
409
410         private DAVProcessor processor;
411
412         /**
413          *
414          */

415         SessionInvalidateListener(DAVProcessor processor) {
416             this.processor = processor;
417         }
418
419         /*
420          * (non-Javadoc)
421          *
422          * @see javax.servlet.http.HttpSessionBindingListener#valueBound(javax.servlet.http.HttpSessionBindingEvent)
423          */

424         public void valueBound(HttpSessionBindingEvent JavaDoc arg0) {
425         }
426
427         /*
428          * (non-Javadoc)
429          *
430          * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(javax.servlet.http.HttpSessionBindingEvent)
431          */

432         public void valueUnbound(HttpSessionBindingEvent JavaDoc arg0) {
433             processors.remove(processor);
434             // processor.getRepository().removeListener(DAVServlet.this);
435
}
436
437     }
438 }
439
Popular Tags