| /******************************************************************************* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| *******************************************************************************/ |
| |
| package org.apache.ofbiz.workeffort.workeffort; |
| |
| import java.io.IOException; |
| import java.io.Writer; |
| import java.util.Date; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.servlet.ServletContext; |
| import javax.servlet.ServletException; |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| import javax.servlet.http.HttpSession; |
| |
| import org.apache.ofbiz.base.util.Debug; |
| import org.apache.ofbiz.base.util.UtilGenerics; |
| import org.apache.ofbiz.base.util.UtilHttp; |
| import org.apache.ofbiz.base.util.UtilValidate; |
| import org.apache.ofbiz.base.util.UtilXml; |
| import org.apache.ofbiz.entity.Delegator; |
| import org.apache.ofbiz.entity.GenericEntityException; |
| import org.apache.ofbiz.entity.GenericValue; |
| import org.apache.ofbiz.entity.util.EntityQuery; |
| import org.apache.ofbiz.service.GenericServiceException; |
| import org.apache.ofbiz.service.LocalDispatcher; |
| import org.apache.ofbiz.service.ServiceUtil; |
| import org.apache.ofbiz.webapp.stats.VisitHandler; |
| import org.apache.ofbiz.webapp.webdav.PropFindHelper; |
| import org.apache.ofbiz.webapp.webdav.ResponseHelper; |
| import org.apache.ofbiz.webapp.webdav.WebDavUtil; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| |
| /** iCalendar worker class. This class handles the WebDAV requests and |
| * delegates the calendar conversion tasks to <code>ICalConverter</code>. |
| */ |
| public final class ICalWorker { |
| |
| public static final String module = ICalWorker.class.getName(); |
| |
| private ICalWorker() {}; |
| |
| public static final class ResponseProperties { |
| public final int statusCode; |
| public final String statusMessage; |
| public ResponseProperties(int statusCode, String statusMessage) { |
| this.statusCode = statusCode; |
| this.statusMessage = statusMessage; |
| } |
| } |
| |
| private static Map<String, Object> createConversionContext(HttpServletRequest request) { |
| Map<String, Object> context = new HashMap<String, Object>(); |
| Enumeration<String> attributeEnum = UtilGenerics.cast(request.getAttributeNames()); |
| while (attributeEnum.hasMoreElements()) { |
| String attributeName = attributeEnum.nextElement(); |
| context.put(attributeName, request.getAttribute(attributeName)); |
| } |
| context.put("parameters", request.getParameterMap()); |
| context.put("locale", UtilHttp.getLocale(request)); |
| return context; |
| } |
| |
| /** Create an HTTP Forbidden response. The calendar converter will use this |
| * response when a user is logged in, but they don't have the basic CRUD |
| * permissions to perform an action. Returning a Forbidden status will |
| * prevent the client from trying the operation again. |
| * |
| * @param statusMessage Optional status message - usually <code>null</code> |
| * for security reasons |
| * @return Create an HTTP Forbidden response |
| */ |
| public static ResponseProperties createForbiddenResponse(String statusMessage) { |
| return new ResponseProperties(HttpServletResponse.SC_FORBIDDEN, statusMessage); |
| } |
| |
| /** Create an HTTP Unauthorized response. The calendar converter will use this |
| * response when a user is not logged in, and basic CRUD permissions are |
| * needed to perform an action. Returning an Unauthorized status will |
| * force the client to authenticate the user, then try the operation again. |
| * |
| * @param statusMessage Optional status message - usually <code>null</code> |
| * for security reasons |
| * @return Create an HTTP Unauthorized response |
| */ |
| public static ResponseProperties createNotAuthorizedResponse(String statusMessage) { |
| return new ResponseProperties(HttpServletResponse.SC_UNAUTHORIZED, statusMessage); |
| } |
| |
| public static ResponseProperties createNotFoundResponse(String statusMessage) { |
| return new ResponseProperties(HttpServletResponse.SC_NOT_FOUND, statusMessage); |
| } |
| |
| public static ResponseProperties createOkResponse(String statusMessage) { |
| return new ResponseProperties(HttpServletResponse.SC_OK, statusMessage); |
| } |
| |
| /** Create an HTTP Partial Content response. The calendar converter will use this |
| * response when a calendar is only partially updated. |
| * |
| * @param statusMessage A message describing which calendar components were |
| * not updated |
| * @return Create an HTTP Partial Content response. |
| */ |
| public static ResponseProperties createPartialContentResponse(String statusMessage) { |
| return new ResponseProperties(HttpServletResponse.SC_PARTIAL_CONTENT, statusMessage); |
| } |
| |
| private static Date getLastModifiedDate(HttpServletRequest request) throws GenericEntityException { |
| String workEffortId = (String) request.getAttribute("workEffortId"); |
| Delegator delegator = (Delegator) request.getAttribute("delegator"); |
| GenericValue publishProperties = EntityQuery.use(delegator).from("WorkEffort").where("workEffortId", workEffortId).queryOne(); |
| GenericValue iCalData = publishProperties.getRelatedOne("WorkEffortIcalData", false); |
| if (iCalData != null) { |
| return iCalData.getTimestamp("lastUpdatedStamp"); |
| } else { |
| return publishProperties.getTimestamp("lastUpdatedStamp"); |
| } |
| } |
| |
| public static void handleGetRequest(HttpServletRequest request, HttpServletResponse response, ServletContext context) throws ServletException, IOException { |
| if (!isValidRequest(request, response)) { |
| return; |
| } |
| String workEffortId = (String) request.getAttribute("workEffortId"); |
| Debug.logInfo("[handleGetRequest] workEffortId = " + workEffortId, module); |
| ResponseProperties responseProps = null; |
| try { |
| responseProps = ICalConverter.getICalendar(workEffortId, createConversionContext(request)); |
| } catch (Exception e) { |
| Debug.logError(e, "[handleGetRequest] Error while sending calendar: ", module); |
| response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |
| return; |
| } |
| if (responseProps.statusCode == HttpServletResponse.SC_OK) { |
| response.setContentType("text/calendar"); |
| } |
| writeResponse(responseProps, request, response, context); |
| } |
| |
| public static void handlePropFindRequest(HttpServletRequest request, HttpServletResponse response, ServletContext context) throws ServletException, IOException { |
| if (!isValidRequest(request, response)) { |
| return; |
| } |
| String workEffortId = (String) request.getAttribute("workEffortId"); |
| Debug.logInfo("[handlePropFindRequest] workEffortId = " + workEffortId, module); |
| try { |
| Document requestDocument = WebDavUtil.getDocumentFromRequest(request); |
| if (Debug.verboseOn()) { |
| Debug.logVerbose("[handlePropFindRequest] PROPFIND body:\r\n" + UtilXml.writeXmlDocument(requestDocument), module); |
| } |
| PropFindHelper helper = new PropFindHelper(requestDocument); |
| if (!helper.isAllProp() && !helper.isPropName()) { |
| Document responseDocument = helper.getResponseDocument(); |
| List<Element> supportedProps = new LinkedList<Element>(); |
| List<Element> unSupportedProps = new LinkedList<Element>(); |
| List<Element> propElements = helper.getFindPropsList(ResponseHelper.DAV_NAMESPACE_URI); |
| for (Element propElement : propElements) { |
| if ("getetag".equals(propElement.getNodeName())) { |
| Element etagElement = helper.createElementSetValue("D:getetag", String.valueOf(System.currentTimeMillis())); |
| supportedProps.add(etagElement); |
| continue; |
| } |
| if ("getlastmodified".equals(propElement.getNodeName())) { |
| Date lastModified = getLastModifiedDate(request); |
| Element lmElement = helper.createElementSetValue("D:getlastmodified", WebDavUtil.formatDate(WebDavUtil.getRFC1123DateFormat(), lastModified)); |
| supportedProps.add(lmElement); |
| continue; |
| } |
| unSupportedProps.add(responseDocument.createElementNS(propElement.getNamespaceURI(), propElement.getTagName())); |
| } |
| Element responseElement = helper.createResponseElement(); |
| responseElement.appendChild(helper.createHrefElement("/" + workEffortId + "/")); |
| if (supportedProps.size() > 0) { |
| Element propElement = helper.createPropElement(supportedProps); |
| responseElement.appendChild(helper.createPropStatElement(propElement, ResponseHelper.STATUS_200)); |
| } |
| if (unSupportedProps.size() > 0) { |
| Element propElement = helper.createPropElement(unSupportedProps); |
| responseElement.appendChild(helper.createPropStatElement(propElement, ResponseHelper.STATUS_404)); |
| } |
| Element rootElement = helper.createMultiStatusElement(); |
| rootElement.appendChild(responseElement); |
| responseDocument.appendChild(rootElement); |
| if (Debug.verboseOn()) { |
| Debug.logVerbose("[handlePropFindRequest] PROPFIND response:\r\n" + UtilXml.writeXmlDocument(responseDocument), module); |
| } |
| ResponseHelper.prepareResponse(response, 207, "Multi-Status"); |
| Writer writer = response.getWriter(); |
| try { |
| helper.writeResponse(response, writer); |
| } finally { |
| writer.close(); |
| } |
| return; |
| } |
| } catch (Exception e) { |
| Debug.logError(e, "PROPFIND error: ", module); |
| } |
| response.setStatus(HttpServletResponse.SC_OK); |
| response.flushBuffer(); |
| } |
| |
| public static void handlePutRequest(HttpServletRequest request, HttpServletResponse response, ServletContext context) throws ServletException, IOException { |
| if (!isValidRequest(request, response)) { |
| return; |
| } |
| String contentType = request.getContentType(); |
| if (contentType != null && !"text/calendar".equals(contentType)) { |
| Debug.logInfo("[handlePutRequest] invalid content type", module); |
| response.sendError(HttpServletResponse.SC_CONFLICT); |
| return; |
| } |
| String workEffortId = (String) request.getAttribute("workEffortId"); |
| Debug.logInfo("[handlePutRequest] workEffortId = " + workEffortId, module); |
| ResponseProperties responseProps = null; |
| try { |
| responseProps = ICalConverter.storeCalendar(request.getInputStream(), createConversionContext(request)); |
| } catch (Exception e) { |
| Debug.logError(e, "[handlePutRequest] Error while updating calendar: ", module); |
| response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |
| return; |
| } |
| writeResponse(responseProps, request, response, context); |
| } |
| |
| private static boolean isValidRequest(HttpServletRequest request, HttpServletResponse response) throws IOException { |
| if (!request.isSecure()) { |
| response.sendError(HttpServletResponse.SC_BAD_REQUEST); |
| return false; |
| } |
| setupRequest(request, response); |
| String workEffortId = (String) request.getAttribute("workEffortId"); |
| if (workEffortId == null) { |
| response.sendError(HttpServletResponse.SC_BAD_REQUEST); |
| return false; |
| } |
| return true; |
| } |
| |
| private static void logInUser(HttpServletRequest request, HttpServletResponse response) throws GenericServiceException, GenericEntityException { |
| Map<String, Object> serviceMap = WebDavUtil.getCredentialsFromRequest(request); |
| if (serviceMap == null) { |
| return; |
| } |
| serviceMap.put("locale", UtilHttp.getLocale(request)); |
| GenericValue userLogin = null; |
| HttpSession session = request.getSession(); |
| LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher"); |
| Map<String, Object> result = dispatcher.runSync("userLogin", serviceMap); |
| if (ServiceUtil.isError(result) || ServiceUtil.isFailure(result)) { |
| return; |
| } |
| userLogin = (GenericValue) result.get("userLogin"); |
| request.setAttribute("userLogin", userLogin); |
| session.setAttribute("userLogin", userLogin); |
| VisitHandler.getVisitor(request, response); |
| GenericValue person = userLogin.getRelatedOne("Person", false); |
| if (person != null) { |
| request.setAttribute("person", person); |
| } else { |
| GenericValue partyGroup = userLogin.getRelatedOne("PartyGroup", false); |
| if (partyGroup != null) { |
| request.setAttribute("partyGroup", partyGroup); |
| } |
| } |
| } |
| |
| private static void setupRequest(HttpServletRequest request, HttpServletResponse response) { |
| String path = request.getPathInfo(); |
| if (UtilValidate.isEmpty(path)) { |
| path = "/"; |
| } |
| String workEffortId = path.substring(1); |
| if (workEffortId.contains("/")) { |
| workEffortId = workEffortId.substring(0, workEffortId.indexOf("/")); |
| } |
| if (workEffortId.length() < 1) { |
| return; |
| } |
| request.setAttribute("workEffortId", workEffortId); |
| try { |
| logInUser(request, response); |
| } catch (Exception e) { |
| Debug.logError(e, "Error while logging in user: ", module); |
| } |
| } |
| |
| private static void writeResponse(ResponseProperties responseProps, HttpServletRequest request, HttpServletResponse response, ServletContext context) throws IOException { |
| if (Debug.verboseOn()) { |
| Debug.logVerbose("Returning response: code = " + responseProps.statusCode + |
| ", message = " + responseProps.statusMessage, module); |
| } |
| response.setStatus(responseProps.statusCode); |
| if (responseProps.statusCode == HttpServletResponse.SC_UNAUTHORIZED) { |
| response.setHeader("WWW-Authenticate", "Basic realm=\"OFBiz iCalendar " + request.getAttribute("workEffortId") + "\""); |
| } |
| if (responseProps.statusMessage != null) { |
| response.setContentLength(responseProps.statusMessage.length()); |
| Writer writer = response.getWriter(); |
| try { |
| writer.write(responseProps.statusMessage); |
| } finally { |
| writer.close(); |
| } |
| } |
| } |
| } |