001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/access/tags/sakai_2-4-1/access-impl/impl/src/java/org/sakaiproject/access/tool/WebServlet.java $
003: * $Id: WebServlet.java 22234 2007-03-06 19:45:31Z bkirschn@umich.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.access.tool;
021:
022: import java.io.IOException;
023: import java.util.Enumeration;
024:
025: import javax.servlet.ServletException;
026: import javax.servlet.http.HttpServletRequest;
027: import javax.servlet.http.HttpServletResponse;
028:
029: import org.apache.commons.fileupload.FileItem;
030: import org.apache.commons.fileupload.FileUpload;
031: import org.apache.commons.logging.Log;
032: import org.apache.commons.logging.LogFactory;
033: import org.sakaiproject.content.api.ContentCollection;
034: import org.sakaiproject.content.api.ContentResource;
035: import org.sakaiproject.content.api.ContentResourceEdit;
036: import org.sakaiproject.content.cover.ContentHostingService;
037: import org.sakaiproject.entity.api.Entity;
038: import org.sakaiproject.entity.api.Reference;
039: import org.sakaiproject.entity.api.ResourceProperties;
040: import org.sakaiproject.entity.api.ResourcePropertiesEdit;
041: import org.sakaiproject.entity.cover.EntityManager;
042: import org.sakaiproject.event.cover.NotificationService;
043: import org.sakaiproject.exception.IdUnusedException;
044: import org.sakaiproject.exception.IdUsedException;
045: import org.sakaiproject.exception.InconsistentException;
046: import org.sakaiproject.time.api.TimeBreakdown;
047: import org.sakaiproject.time.cover.TimeService;
048: import org.sakaiproject.user.api.User;
049: import org.sakaiproject.user.cover.UserDirectoryService;
050: import org.sakaiproject.tool.api.Session;
051: import org.sakaiproject.tool.cover.SessionManager;
052:
053: /**
054: * <p>
055: * Web extends access: all references are assumed to be under "/content", and POST to add a file is supported.
056: * </p>
057: *
058: * @author Sakai Software Development Team
059: */
060: public class WebServlet extends AccessServlet {
061: /** Our log (commons). */
062: private static Log M_log = LogFactory.getLog(WebServlet.class);
063:
064: /**
065: * Set active session according to sessionId parameter
066: */
067: private void setSession(HttpServletRequest req) {
068: String sessionId = req.getParameter("session");
069: if (sessionId != null) {
070: Session session = SessionManager.getSession(sessionId);
071:
072: if (session != null) {
073: session.setActive();
074: SessionManager.setCurrentSession(session);
075: }
076: }
077: }
078:
079: /**
080: * respond to an HTTP GET request
081: *
082: * @param req
083: * HttpServletRequest object with the client request
084: * @param res
085: * HttpServletResponse object back to the client
086: * @exception ServletException
087: * in case of difficulties
088: * @exception IOException
089: * in case of difficulties
090: */
091: public void doGet(HttpServletRequest req, HttpServletResponse res)
092: throws ServletException, IOException {
093: setSession(req);
094: super .dispatch(req, res);
095: }
096:
097: /**
098: * respond to an HTTP POST request; only to handle the login process
099: *
100: * @param req
101: * HttpServletRequest object with the client request
102: * @param res
103: * HttpServletResponse object back to the client
104: * @exception ServletException
105: * in case of difficulties
106: * @exception IOException
107: * in case of difficulties
108: */
109: public void doPost(HttpServletRequest req, HttpServletResponse res)
110: throws ServletException, IOException {
111: // catch the login helper posts
112: String option = req.getPathInfo();
113: String[] parts = option.split("/");
114: if ((parts.length == 2) && ((parts[1].equals("login")))) {
115: doLogin(req, res, null);
116: }
117:
118: else if (FileUpload.isMultipartContent(req)) {
119: setSession(req);
120: postUpload(req, res);
121: }
122:
123: else {
124: sendError(res, HttpServletResponse.SC_NOT_FOUND);
125: }
126: }
127:
128: /**
129: * Make any changes needed to the path before final "ref" processing.
130: *
131: * @param path
132: * The path from the request.
133: * @param req
134: * The request object.
135: * @return The path to use to make the Reference for further processing.
136: */
137: protected String preProcessPath(String path, HttpServletRequest req) {
138: // everything we work with is down the "content" part of the Sakai access URL space
139:
140: // if path is just "/", we don't really know if the request was to .../SERVLET or .../SERVLET/ - we want to preserve the trailing slash
141: // the request URI will tell us
142: if ("/".equals(path) && !(req.getRequestURI().endsWith("/")))
143: return "/content";
144:
145: return "/content" + path;
146: }
147:
148: /**
149: * Handle file upload requests.
150: *
151: * @param req
152: * @param res
153: */
154: protected void postUpload(HttpServletRequest req,
155: HttpServletResponse res) {
156: String path = req.getPathInfo();
157: // System.out.println("path " + path);
158: if (path == null)
159: path = "";
160: // assume caller has verified that it is a request for content and that it's multipart
161: // loop over attributes in request, picking out the ones
162: // that are file uploads and doing them
163: for (Enumeration e = req.getAttributeNames(); e
164: .hasMoreElements();) {
165: String iname = (String) e.nextElement();
166: // System.out.println("Item " + iname);
167: Object o = req.getAttribute(iname);
168: // NOTE: Fileitem is from
169: // org.apache.commons.fileupload.FileItem, not
170: // sakai's parameterparser version
171: if (o != null && o instanceof FileItem) {
172: FileItem fi = (FileItem) o;
173: // System.out.println("found file " + fi.getName());
174: if (!writeFile(fi.getName(), fi.getContentType(), fi
175: .get(), path, req, res, true))
176: return;
177: }
178: }
179: }
180:
181: protected boolean writeFile(String name, String type, byte[] data,
182: String dir, HttpServletRequest req,
183: HttpServletResponse resp, boolean mkdir) {
184: try {
185: // validate filename. Need to be fairly careful.
186: int i = name.lastIndexOf(Entity.SEPARATOR);
187: if (i >= 0)
188: name = name.substring(i + 1);
189: if (name.length() < 1) {
190: // System.out.println("no name left / removal");
191: resp.sendError(HttpServletResponse.SC_FORBIDDEN);
192: return false;
193: }
194:
195: // do our web thing with the path
196: dir = preProcessPath(dir, req);
197:
198: // make sure there's a trailing separator
199: if (!dir.endsWith(Entity.SEPARATOR))
200: dir = dir + Entity.SEPARATOR;
201:
202: // get a reference to the content collection - this lets us use alias and short refs
203: Reference ref = EntityManager.newReference(dir);
204:
205: // the reference id replaces the dir - as a fully qualified path (no alias, no short ref)
206: dir = ref.getId();
207:
208: String path = dir + name;
209:
210: ResourcePropertiesEdit resourceProperties = ContentHostingService
211: .newResourceProperties();
212:
213: // Try to delete the resource
214: try {
215: // System.out.println("Trying Del " + path);
216: // The existing document may be a collection or a file.
217: boolean isCollection = ContentHostingService
218: .getProperties(path).getBooleanProperty(
219: ResourceProperties.PROP_IS_COLLECTION);
220:
221: if (isCollection) {
222: // System.out.println("Can't del, iscoll");
223: resp.sendError(HttpServletResponse.SC_FORBIDDEN);
224: return false;
225: } else {
226: // not sure why removeesource(path) didn't
227: // work for my workspace
228: ContentResourceEdit edit = ContentHostingService
229: .editResource(path);
230: // if (edit != null)
231: // System.out.println("Got edit");
232: ContentHostingService.removeResource(edit);
233: }
234: } catch (IdUnusedException e) {
235: // Normal situation - nothing to do
236: } catch (Exception e) {
237: // System.out.println("Can't del, exception " + e.getClass() + ": " + e.getMessage());
238: resp.sendError(HttpServletResponse.SC_FORBIDDEN);
239: return false;
240: }
241:
242: // Add the resource
243:
244: try {
245: User user = UserDirectoryService.getCurrentUser();
246:
247: TimeBreakdown timeBreakdown = TimeService.newTime()
248: .breakdownLocal();
249: String mycopyright = "copyright (c)" + " "
250: + timeBreakdown.getYear() + ", "
251: + user.getDisplayName()
252: + ". All Rights Reserved. ";
253:
254: resourceProperties.addProperty(
255: ResourceProperties.PROP_COPYRIGHT, mycopyright);
256:
257: resourceProperties.addProperty(
258: ResourceProperties.PROP_DISPLAY_NAME, name);
259:
260: // System.out.println("Trying Add " + path);
261: ContentResource resource = ContentHostingService
262: .addResource(path, type, data,
263: resourceProperties,
264: NotificationService.NOTI_NONE);
265:
266: } catch (InconsistentException e) {
267: // get this error if containing dir doesn't exist
268: if (mkdir) {
269: try {
270: ContentCollection collection = ContentHostingService
271: .addCollection(dir, resourceProperties);
272: return writeFile(name, type, data, dir, req,
273: resp, false);
274: } catch (Throwable ee) {
275: }
276: }
277: // System.out.println("Add fail, inconsistent");
278: resp.sendError(HttpServletResponse.SC_CONFLICT);
279: return false;
280: } catch (IdUsedException e) {
281: // Should not happen because we deleted above (unless tawo requests at same time)
282: // System.out.println("Add fail, in use");
283: M_log.warn("access post IdUsedException:"
284: + e.getMessage());
285:
286: resp.sendError(HttpServletResponse.SC_CONFLICT);
287: return false;
288: } catch (Exception e) {
289: // System.out.println("Add failed, exception " + e.getClass() + ": " + e.getMessage());
290: resp.sendError(HttpServletResponse.SC_FORBIDDEN);
291: return false;
292: }
293: } catch (IOException e) {
294: // System.out.println("overall fail IOException " + e);
295: }
296: return true;
297: }
298: }
|