You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by ad...@apache.org on 2009/06/24 08:58:54 UTC
svn commit: r787927 [1/2] - in /ofbiz/trunk/applications/workeffort: data/
entitydef/ script/org/ofbiz/workeffort/permission/
script/org/ofbiz/workeffort/workeffort/ servicedef/
src/org/ofbiz/workeffort/workeffort/ webapp/ical/WEB-INF/
Author: adrianc
Date: Wed Jun 24 06:58:54 2009
New Revision: 787927
URL: http://svn.apache.org/viewvc?rev=787927&view=rev
Log:
Improved Work Effort iCalendar support:
1. Improved work effort field-to-iCalendar property mapping.
2. Work efforts can be updated from 3rd party calendar clients.
3. The publish point scope controls calendar access
4. Some iCalendar WebDAV servlet operations use services - so the iCalendar integration can be modified or enhanced.
TODO: I'm not an expert on SSL - the request handler needs more work to enforce SSL. Allow third party calendar programs to create new work efforts. Implement a subset of CalDAV. Authentication is done with URL parameters - that needs to be improved.
I replaced the work effort aatribute services I set up earlier. The attributes were too limited.
I will create a Wiki page soon to explain all of this.
Many thanks to David Jones for his advice, and to Hans Bakker for his calendar demo data.
Added:
ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalConverter.java (with props)
ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalHandlerFactory.java (with props)
Removed:
ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalServlet.java
Modified:
ofbiz/trunk/applications/workeffort/data/WorkEffortDemoData.xml
ofbiz/trunk/applications/workeffort/entitydef/entitymodel.xml
ofbiz/trunk/applications/workeffort/script/org/ofbiz/workeffort/permission/WorkEffortPermissionServices.xml
ofbiz/trunk/applications/workeffort/script/org/ofbiz/workeffort/workeffort/WorkEffortSimpleServices.xml
ofbiz/trunk/applications/workeffort/servicedef/services.xml
ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalWorker.java
ofbiz/trunk/applications/workeffort/webapp/ical/WEB-INF/web.xml
Modified: ofbiz/trunk/applications/workeffort/data/WorkEffortDemoData.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/data/WorkEffortDemoData.xml?rev=787927&r1=787926&r2=787927&view=diff
==============================================================================
--- ofbiz/trunk/applications/workeffort/data/WorkEffortDemoData.xml (original)
+++ ofbiz/trunk/applications/workeffort/data/WorkEffortDemoData.xml Wed Jun 24 06:58:54 2009
@@ -47,7 +47,7 @@
<WorkEffortAssoc workEffortIdFrom="CALENDAR_PUB_DEMO" workEffortIdTo="PrivateDemoEmployee1" workEffortAssocTypeId="WORK_EFF_DEPENDENCY" fromDate="2008-01-01 00:00:00.0"/>
<WorkEffortPartyAssignment workEffortId="PrivateDemoEmployee1" partyId="DemoEmployee1" statusId="PRTYASGN_ASSIGNED" roleTypeId="CAL_OWNER" availabilityStatusId="WEPA_AV_BUSY" fromDate="2008-01-01 00:00:00.0"/>
<!-- public event -->
- <WorkEffort workEffortId="PublicEvent" workEffortTypeId="MEETING" currentStatusId="CAL_TENTATIVE" lastStatusUpdate="2008-01-01 00:00:00.0" scopeEnumId="WES_PUBLIC" workEffortName="The general company party june 17" description="General Party" estimatedStartDate="2009-06-17 19:00:00.0" estimatedCompletionDate="2009-06-17 23:00:00.0"/>
+ <WorkEffort workEffortId="PublicEvent" workEffortTypeId="MEETING" currentStatusId="CAL_TENTATIVE" lastStatusUpdate="2008-01-01 00:00:00.0" scopeEnumId="WES_PUBLIC" workEffortName="The general company party june 17" description="General Party" locationDesc="Tom's Banquet Hall" estimatedStartDate="2009-06-17 19:00:00.0" estimatedCompletionDate="2009-06-17 23:00:00.0"/>
<WorkEffortAssoc workEffortIdFrom="CALENDAR_PUB_DEMO" workEffortIdTo="PublicEvent" workEffortAssocTypeId="WORK_EFF_DEPENDENCY" fromDate="2008-01-01 00:00:00.0"/>
</entity-engine-xml>
Modified: ofbiz/trunk/applications/workeffort/entitydef/entitymodel.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/entitydef/entitymodel.xml?rev=787927&r1=787926&r2=787927&view=diff
==============================================================================
--- ofbiz/trunk/applications/workeffort/entitydef/entitymodel.xml (original)
+++ ofbiz/trunk/applications/workeffort/entitydef/entitymodel.xml Wed Jun 24 06:58:54 2009
@@ -578,6 +578,18 @@
<key-map field-name="parentTypeId" rel-field-name="workEffortGoodStdTypeId"/>
</relation>
</entity>
+ <entity entity-name="WorkEffortIcalData"
+ package-name="org.ofbiz.workeffort.workeffort"
+ title="Work Effort iCalendar Data">
+ <field name="workEffortId" type="id-ne"></field>
+ <field name="icalData" type="very-long">
+ <description>iCalender Data</description>
+ </field>
+ <prim-key field="workEffortId"/>
+ <relation type="one" fk-name="WKEFF_ICAL_DATA" rel-entity-name="WorkEffort">
+ <key-map field-name="workEffortId"/>
+ </relation>
+ </entity>
<entity entity-name="WorkEffortInventoryAssign"
package-name="org.ofbiz.workeffort.workeffort"
title="Work Effort Inventory Assignment Entity">
Modified: ofbiz/trunk/applications/workeffort/script/org/ofbiz/workeffort/permission/WorkEffortPermissionServices.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/script/org/ofbiz/workeffort/permission/WorkEffortPermissionServices.xml?rev=787927&r1=787926&r2=787927&view=diff
==============================================================================
--- ofbiz/trunk/applications/workeffort/script/org/ofbiz/workeffort/permission/WorkEffortPermissionServices.xml (original)
+++ ofbiz/trunk/applications/workeffort/script/org/ofbiz/workeffort/permission/WorkEffortPermissionServices.xml Wed Jun 24 06:58:54 2009
@@ -303,4 +303,80 @@
</while>
</simple-method>
+ <simple-method method-name="workEffortICalendarPermission" short-description="Check iCalendar Permission">
+ <!-- Note: the iCalendar servlet will call the permission service under two conditions - to grant
+ VIEW access to a calendar that isn't PUBLIC, or to grant UPDATE access to a work effort -->
+ <log level="verbose" message="workEffortICalendarPermission invoked for workEffortId ${parameters.workEffortId},
+ user login partyId = ${userLogin.partyId}"/>
+ <call-simple-method method-name="workEffortManagerPermission"/>
+ <if-compare field="hasPermission" value="true" operator="equals">
+ <set field="hasPermission" value="false" type="Boolean"/>
+ <set field="workEffortId" from-field="parameters.workEffortId"/>
+ <entity-one value-field="workEffort" entity-name="WorkEffort"/>
+ <if-not-empty field="workEffort">
+ <entity-condition list="partyAssignments" entity-name="WorkEffortPartyAssignment" filter-by-date="true">
+ <condition-list combine="and">
+ <condition-expr field-name="workEffortId" from-field="workEffortId"/>
+ <condition-expr field-name="partyId" from-field="userLogin.partyId"/>
+ <condition-list combine="or">
+ <condition-expr field-name="roleTypeId" value="CAL_OWNER"/>
+ <condition-expr field-name="roleTypeId" value="CAL_ORGANIZER"/>
+ <condition-expr field-name="roleTypeId" value="CAL_DELEGATE"/>
+ </condition-list>
+ </condition-list>
+ </entity-condition>
+ <set field="isDelegate" value="false"/>
+ <set field="isOwner" value="false"/>
+ <set field="isOrganizer" value="false"/>
+ <iterate list="partyAssignments" entry="partyAssignment">
+ <if-compare field="partyAssignment.roleTypeId" operator="equals" value="CAL_OWNER">
+ <set field="isDelegate" value="true"/>
+ <set field="isOwner" value="true"/>
+ <set field="isOrganizer" value="true"/>
+ <else>
+ <if-compare field="partyAssignment.roleTypeId" operator="equals" value="CAL_ORGANIZER">
+ <set field="isOrganizer" value="true"/>
+ <else>
+ <if-compare field="partyAssignment.roleTypeId" operator="equals" value="CAL_DELEGATE">
+ <set field="isDelegate" value="true"/>
+ </if-compare>
+ </else>
+ </if-compare>
+ </else>
+ </if-compare>
+ </iterate>
+ <if-compare value="PUBLISH_PROPS" field="workEffort.workEffortTypeId" operator="equals">
+ <log level="verbose" message="Checking publish properties permission, isOwner = ${isOwner}, isDelegate = ${isDelegate}"/>
+ <if>
+ <condition>
+ <or>
+ <and>
+ <!-- The calendar is private and the user is the calendar owner -->
+ <if-compare field="workEffort.scopeEnumId" operator="equals" value="WES_PRIVATE"/>
+ <if-compare field="isOwner" operator="equals" value="true"/>
+ </and>
+ <and>
+ <!-- The calendar is confidential and the user is a delegate of the calendar -->
+ <if-compare field="workEffort.scopeEnumId" operator="equals" value="WES_CONFIDENTIAL"/>
+ <if-compare field="isDelegate" operator="equals" value="true"/>
+ </and>
+ </or>
+ </condition>
+ <then>
+ <set field="hasPermission" value="true" type="Boolean"/>
+ </then>
+ </if>
+ <else>
+ <!-- RFC 2445 3.5 Only an ORGANIZER can update a VEVENT or VTODO. -->
+ <log level="verbose" message="Checking work effort update permission, isOrganizer = ${isOrganizer}"/>
+ <if-compare field="isOrganizer" operator="equals" value="true">
+ <set field="hasPermission" value="true" type="Boolean"/>
+ </if-compare>
+ </else>
+ </if-compare>
+ </if-not-empty>
+ <field-to-result field="hasPermission"/>
+ </if-compare>
+ </simple-method>
+
</simple-methods>
Modified: ofbiz/trunk/applications/workeffort/script/org/ofbiz/workeffort/workeffort/WorkEffortSimpleServices.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/script/org/ofbiz/workeffort/workeffort/WorkEffortSimpleServices.xml?rev=787927&r1=787926&r2=787927&view=diff
==============================================================================
--- ofbiz/trunk/applications/workeffort/script/org/ofbiz/workeffort/workeffort/WorkEffortSimpleServices.xml (original)
+++ ofbiz/trunk/applications/workeffort/script/org/ofbiz/workeffort/workeffort/WorkEffortSimpleServices.xml Wed Jun 24 06:58:54 2009
@@ -1472,4 +1472,66 @@
<store-value value-field="lookedUpValue"/>
</simple-method>
+ <!-- iCalendar services -->
+
+ <simple-method method-name="getICalWorkEfforts" short-description="Get All Work Efforts Related To An iCalendar Publish Point">
+ <!-- Servlet already confirmed workEffortId is a valid publish point -->
+ <set field="workEffortId" from-field="parameters.workEffortId"/>
+ <entity-condition list="assignedParties" entity-name="WorkEffortPartyAssignment" filter-by-date="true">
+ <condition-list combine="and">
+ <condition-expr field-name="workEffortId" from-field="workEffortId"/>
+ <!-- DELEGATE has special meaning in publish properties - it's
+ another party in an ORGANIZER role, NOT a party whose work efforts
+ are included in a calendar. We need another role to define calendar
+ members. -->
+ <condition-expr field-name="roleTypeId" value="CAL_DELEGATE" operator="not-equals"/>
+ </condition-list>
+ </entity-condition>
+ <iterate entry="assignedParty" list="assignedParties">
+ <entity-condition list="resultList" entity-name="WorkEffortAndPartyAssign" filter-by-date="true">
+ <condition-list combine="and">
+ <condition-expr field-name="scopeEnumId" value="WES_PUBLIC"/>
+ <condition-expr field-name="workEffortTypeId" value="PUBLISH_PROPS" operator="not-equals"/>
+ <condition-expr field-name="partyId" from-field="assignedParty.partyId"/>
+ </condition-list>
+ </entity-condition>
+ <list-to-list list="resultList" to-list="workEfforts"/>
+ </iterate>
+ <entity-and list="assignedFixedAssets" entity-name="WorkEffortFixedAssetAssign" filter-by-date="true">
+ <field-map field-name="workEffortId" from-field="workEffortId"/>
+ </entity-and>
+ <iterate entry="assignedFixedAsset" list="assignedFixedAssets">
+ <entity-condition list="resultList" entity-name="WorkEffortAndFixedAssetAssign" filter-by-date="true">
+ <condition-list combine="and">
+ <condition-expr field-name="scopeEnumId" value="WES_PUBLIC"/>
+ <condition-expr field-name="workEffortTypeId" value="PUBLISH_PROPS" operator="not-equals"/>
+ <condition-expr field-name="fixedAssetId" from-field="assignedFixedAsset.fixedAssetId"/>
+ </condition-list>
+ </entity-condition>
+ <list-to-list list="resultList" to-list="workEfforts"/>
+ </iterate>
+ <entity-and list="resultList" entity-name="WorkEffortAssocToView" filter-by-date="true">
+ <field-map field-name="workEffortIdFrom" from-field="workEffortId"/>
+ </entity-and>
+ <list-to-list list="resultList" to-list="workEfforts"/>
+ <field-to-result field="workEfforts"/>
+ </simple-method>
+
+ <simple-method method-name="getPartyICalUri" short-description="Get The Party iCalendar URI">
+ <!-- RFC 2445 4.8.4.1 and 4.8.4.3 Value must be a URI (4.3.3) -->
+ <!-- For now we just look for a primary email address. This could be expanded later. -->
+ <set field="partyId" from-field="parameters.partyId"/>
+ <entity-condition list="emailAddresses" entity-name="PartyContactWithPurpose">
+ <condition-list combine="and">
+ <condition-expr field-name="partyId" from-field="partyId"/>
+ <condition-expr field-name="contactMechPurposeTypeId" value="PRIMARY_EMAIL"/>
+ <condition-expr field-name="purposeThruDate" from-field="null"/>
+ </condition-list>
+ </entity-condition>
+ <if-compare field="util:size(emailAddresses)" operator="not-equals" value="0" type="Integer">
+ <set field="iCalUri" value="MAILTO:${emailAddresses[0].infoString}"/>
+ <field-to-result field="iCalUri"/>
+ </if-compare>
+ </simple-method>
+
</simple-methods>
Modified: ofbiz/trunk/applications/workeffort/servicedef/services.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/servicedef/services.xml?rev=787927&r1=787926&r2=787927&view=diff
==============================================================================
--- ofbiz/trunk/applications/workeffort/servicedef/services.xml (original)
+++ ofbiz/trunk/applications/workeffort/servicedef/services.xml Wed Jun 24 06:58:54 2009
@@ -662,24 +662,44 @@
<auto-attributes mode="IN" include="pk" optional="false"/>
</service>
- <!-- WorkEffort Attribute Services -->
- <service name="createWorkEffortAttribute" default-entity-name="WorkEffortAttribute" engine="entity-auto" invoke="create" auth="true">
- <description>Create a WorkEffort Attribute</description>
- <permission-service service-name="workEffortGenericPermission" main-action="CREATE"/>
+ <!-- WorkEffort iCalendar Services -->
+ <service name="createWorkEffortICalData" default-entity-name="WorkEffortIcalData" engine="entity-auto" invoke="create" auth="true">
+ <description>Create WorkEffort iCalendar Data</description>
+ <permission-service service-name="workEffortICalendarPermission" main-action="CREATE"/>
<auto-attributes include="pk" mode="IN" optional="false"/>
<auto-attributes include="nonpk" mode="IN" optional="true"/>
</service>
- <service name="updateWorkEffortAttribute" default-entity-name="WorkEffortAttribute" engine="entity-auto" invoke="update" auth="true">
- <description>Update a WorkEffort Attribute</description>
- <permission-service service-name="workEffortGenericPermission" main-action="UPDATE"/>
+ <service name="updateWorkEffortICalData" default-entity-name="WorkEffortIcalData" engine="entity-auto" invoke="update" auth="true">
+ <description>Update WorkEffort iCalendar Data</description>
+ <permission-service service-name="workEffortICalendarPermission" main-action="UPDATE"/>
<auto-attributes include="pk" mode="IN" optional="false"/>
<auto-attributes include="nonpk" mode="IN" optional="true"/>
</service>
- <service name="deleteWorkEffortAttribute" default-entity-name="WorkEffortAttribute" engine="entity-auto" invoke="delete" auth="true">
- <description>Delete a WorkEffort Attribute</description>
- <permission-service service-name="workEffortGenericPermission" main-action="DELETE"/>
+ <service name="deleteWorkEffortICalData" default-entity-name="WorkEffortIcalData" engine="entity-auto" invoke="delete" auth="true">
+ <description>Delete WorkEffort iCalendar Data</description>
+ <permission-service service-name="workEffortICalendarPermission" main-action="DELETE"/>
<auto-attributes include="pk" mode="IN" optional="false"/>
</service>
+ <service name="workEffortICalendarPermission" engine="simple"
+ location="component://workeffort/script/org/ofbiz/workeffort/permission/WorkEffortPermissionServices.xml" invoke="workEffortICalendarPermission">
+ <description>iCalendar Permission Check</description>
+ <implements service="permissionInterface"/>
+ <attribute type="String" mode="IN" name="workEffortId" optional="false"/>
+ </service>
+ <service name="getICalWorkEfforts" engine="simple"
+ location="component://workeffort/script/org/ofbiz/workeffort/workeffort/WorkEffortSimpleServices.xml" invoke="getICalWorkEfforts">
+ <description>Get iCalendar Work Efforts</description>
+ <!-- No permission checking - the servlet handles that -->
+ <attribute type="String" mode="IN" name="workEffortId" optional="false"/>
+ <attribute type="List" mode="OUT" name="workEfforts"/>
+ </service>
+ <service name="getPartyICalUri" engine="simple"
+ location="component://workeffort/script/org/ofbiz/workeffort/workeffort/WorkEffortSimpleServices.xml" invoke="getPartyICalUri">
+ <description>Get Party iCalendar URI</description>
+ <!-- No permission checking - the servlet handles that -->
+ <attribute type="String" mode="IN" name="partyId" optional="false"/>
+ <attribute type="String" mode="OUT" name="iCalUri" optional="true"/>
+ </service>
<!-- WorkEffort Event Reminder Services -->
<service name="createWorkEffortEventReminder" default-entity-name="WorkEffortEventReminder" engine="entity-auto" invoke="create" auth="true">
Added: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalConverter.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalConverter.java?rev=787927&view=auto
==============================================================================
--- ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalConverter.java (added)
+++ ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalConverter.java Wed Jun 24 06:58:54 2009
@@ -0,0 +1,878 @@
+/*******************************************************************************
+ * 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.ofbiz.workeffort.workeffort;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.StringReader;
+import java.net.URISyntaxException;
+import java.sql.Timestamp;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import javolution.util.FastList;
+import javolution.util.FastMap;
+import javolution.util.FastSet;
+
+import net.fortuna.ical4j.data.CalendarBuilder;
+import net.fortuna.ical4j.data.ParserException;
+import net.fortuna.ical4j.model.*;
+import net.fortuna.ical4j.model.component.*;
+import net.fortuna.ical4j.model.parameter.*;
+import net.fortuna.ical4j.model.property.*;
+
+import org.ofbiz.base.util.DateRange;
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.ObjectType;
+import org.ofbiz.base.util.TimeDuration;
+import org.ofbiz.base.util.UtilMisc;
+import org.ofbiz.base.util.UtilProperties;
+import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.entity.GenericDelegator;
+import org.ofbiz.entity.GenericEntityException;
+import org.ofbiz.entity.GenericValue;
+import org.ofbiz.entity.condition.EntityCondition;
+import org.ofbiz.entity.condition.EntityExpr;
+import org.ofbiz.entity.condition.EntityOperator;
+import org.ofbiz.entity.util.EntityUtil;
+import org.ofbiz.service.GenericServiceException;
+import org.ofbiz.service.LocalDispatcher;
+import org.ofbiz.service.ModelParam;
+import org.ofbiz.service.ModelService;
+import org.ofbiz.service.ServiceUtil;
+import org.ofbiz.service.calendar.TemporalExpression;
+import org.ofbiz.service.calendar.TemporalExpressionWorker;
+
+/** iCalendar converter class. This class uses the <a href="http://ical4j.sourceforge.net/index.html">
+ * iCal4J</a> library.
+ */
+public class ICalConverter {
+
+ protected static final String module = ICalConverter.class.getName();
+ protected static final String contactMechIdXParamName = "X-ORG-APACHE-OFBIZ-CONTACT-MECH-ID";
+ protected static final String partyIdXParamName = "X-ORG-APACHE-OFBIZ-PARTY-ID";
+ protected static final ProdId prodId = new ProdId("-//Apache Open For Business//Work Effort Calendar//EN");
+ protected static final String workEffortIdParamName = "X-ORG-APACHE-OFBIZ-WORKEFFORT-ID";
+ protected static final String uidPrefix = "ORG-APACHE-OFBIZ-WE-";
+ protected static final String workEffortIdXPropName = "X-ORG-APACHE-OFBIZ-WORKEFFORT-ID";
+ protected static final String reminderXPropName = "X-ORG-APACHE-OFBIZ-REMINDER-ID";
+ protected static final Map<String, String> fromStatusMap = UtilMisc.toMap("TENTATIVE", "CAL_TENTATIVE",
+ "CONFIRMED", "CAL_CONFIRMED", "CANCELLED", "CAL_CANCELLED", "NEEDS-ACTION", "CAL_NEEDS_ACTION",
+ "COMPLETED", "CAL_COMPLETED", "IN-PROCESS", "CAL_ACCEPTED");
+ protected static final Map<String, Status> toStatusMap = UtilMisc.toMap("CAL_TENTATIVE", Status.VEVENT_TENTATIVE,
+ "CAL_CONFIRMED", Status.VEVENT_CONFIRMED, "CAL_CANCELLED", Status.VEVENT_CANCELLED,
+ "CAL_NEEDS_ACTION", Status.VTODO_NEEDS_ACTION, "CAL_COMPLETED", Status.VTODO_COMPLETED,
+ "CAL_ACCEPTED", Status.VTODO_IN_PROCESS);
+ protected static final Map<String, PartStat> toPartStatusMap = UtilMisc.toMap(
+ "PRTYASGN_OFFERED", PartStat.TENTATIVE, "PRTYASGN_ASSIGNED", PartStat.ACCEPTED);
+ protected static final Map<String, String> fromPartStatusMap = UtilMisc.toMap(
+ "TENTATIVE", "PRTYASGN_OFFERED", "ACCEPTED", "PRTYASGN_ASSIGNED");
+
+ protected static VAlarm createAlarm(GenericValue workEffortEventReminder) {
+ VAlarm alarm = null;
+ Timestamp reminderStamp = workEffortEventReminder.getTimestamp("reminderDateTime");
+ if (reminderStamp != null) {
+ alarm = new VAlarm(new DateTime(reminderStamp));
+ } else {
+ long reminderOffset = workEffortEventReminder.get("reminderOffset") == null ? 0 : workEffortEventReminder.getLong("reminderOffset").longValue();
+ TimeDuration duration = TimeDuration.fromLong(reminderOffset);
+ alarm = new VAlarm(new Dur(duration.days(), duration.hours(), duration.minutes(), duration.seconds()));
+ }
+ return alarm;
+ }
+
+ protected static Attendee createAttendee(GenericValue partyValue, Map<String, Object> context) {
+ Attendee attendee = new Attendee();
+ loadPartyAssignment(attendee, partyValue, context);
+ return attendee;
+ }
+
+ protected static Organizer createOrganizer(GenericValue partyValue, Map<String, Object> context) {
+ Organizer organizer = new Organizer();
+ loadPartyAssignment(organizer, partyValue, context);
+ return organizer;
+ }
+
+ protected static String fromClazz(PropertyList propertyList) {
+ Clazz iCalObj = (Clazz) propertyList.getProperty(Clazz.CLASS);
+ if (iCalObj == null) {
+ return null;
+ }
+ return "WES_".concat(iCalObj.getValue());
+ }
+
+ protected static Timestamp fromCompleted(PropertyList propertyList) {
+ Completed iCalObj = (Completed) propertyList.getProperty(Completed.COMPLETED);
+ if (iCalObj == null) {
+ return null;
+ }
+ Date date = iCalObj.getDate();
+ return new Timestamp(date.getTime());
+ }
+
+ protected static String fromDescription(PropertyList propertyList) {
+ Description iCalObj = (Description) propertyList.getProperty(Description.DESCRIPTION);
+ if (iCalObj == null) {
+ return null;
+ }
+ return iCalObj.getValue();
+ }
+
+ protected static Timestamp fromDtEnd(PropertyList propertyList) {
+ DtEnd iCalObj = (DtEnd) propertyList.getProperty(DtEnd.DTEND);
+ if (iCalObj == null) {
+ return null;
+ }
+ Date date = iCalObj.getDate();
+ return new Timestamp(date.getTime());
+ }
+
+ protected static Timestamp fromDtStart(PropertyList propertyList) {
+ DtStart iCalObj = (DtStart) propertyList.getProperty(DtStart.DTSTART);
+ if (iCalObj == null) {
+ return null;
+ }
+ Date date = iCalObj.getDate();
+ return new Timestamp(date.getTime());
+ }
+
+ protected static Double fromDuration(PropertyList propertyList) {
+ Duration iCalObj = (Duration) propertyList.getProperty(Duration.DURATION);
+ if (iCalObj == null) {
+ return null;
+ }
+ Dur dur = iCalObj.getDuration();
+ TimeDuration td = new TimeDuration(0, 0, (dur.getWeeks() * 7) + dur.getDays(), dur.getHours(), dur.getMinutes(), dur.getSeconds(), 0);
+ return new Double(TimeDuration.toLong(td));
+ }
+
+ protected static Timestamp fromLastModified(PropertyList propertyList) {
+ LastModified iCalObj = (LastModified) propertyList.getProperty(LastModified.LAST_MODIFIED);
+ if (iCalObj == null) {
+ return null;
+ }
+ Date date = iCalObj.getDate();
+ return new Timestamp(date.getTime());
+ }
+
+ protected static String fromLocation(PropertyList propertyList) {
+ Location iCalObj = (Location) propertyList.getProperty(Location.LOCATION);
+ if (iCalObj == null) {
+ return null;
+ }
+ return iCalObj.getValue();
+ }
+
+ protected static String fromParticipationStatus(Parameter status) {
+ if (status == null) {
+ return null;
+ }
+ return fromPartStatusMap.get(status.getValue());
+ }
+
+ protected static Long fromPercentComplete(PropertyList propertyList) {
+ PercentComplete iCalObj = (PercentComplete) propertyList.getProperty(PercentComplete.PERCENT_COMPLETE);
+ if (iCalObj == null) {
+ return null;
+ }
+ return new Long((long)iCalObj.getPercentage());
+ }
+
+ protected static Double fromPriority(PropertyList propertyList) {
+ Priority iCalObj = (Priority) propertyList.getProperty(Priority.PRIORITY);
+ if (iCalObj == null) {
+ return null;
+ }
+ return new Double(iCalObj.getLevel());
+ }
+
+ protected static String fromStatus(PropertyList propertyList) {
+ Status iCalObj = (Status) propertyList.getProperty(Status.STATUS);
+ if (iCalObj == null) {
+ return null;
+ }
+ return fromStatusMap.get(iCalObj.getValue());
+ }
+
+ protected static String fromSummary(PropertyList propertyList) {
+ Summary iCalObj = (Summary) propertyList.getProperty(Summary.SUMMARY);
+ if (iCalObj == null) {
+ return null;
+ }
+ return iCalObj.getValue();
+ }
+
+ protected static String fromXParameter(ParameterList parameterList, String parameterName) {
+ if (parameterName == null) {
+ return null;
+ }
+ Parameter parameter = parameterList.getParameter(parameterName);
+ if (parameter != null) {
+ return parameter.getValue();
+ }
+ return null;
+ }
+
+ protected static String fromXProperty(PropertyList propertyList, String propertyName) {
+ if (propertyName == null) {
+ return null;
+ }
+ Property property = propertyList.getProperty(propertyName);
+ if (property != null) {
+ return property.getValue();
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected static void getAlarms(GenericValue workEffort, ComponentList alarms) throws GenericEntityException {
+ Description description = null;
+ if (workEffort.get("description") != null) {
+ description = new Description(workEffort.getString("description"));
+ } else {
+ description = new Description(workEffort.getString("workEffortName"));
+ }
+ Summary summary = new Summary(UtilProperties.getMessage("WorkEffortUiLabels", "WorkEffortEventReminder", Locale.getDefault()));
+ GenericDelegator delegator = workEffort.getDelegator();
+ String workEffortId = workEffort.getString("workEffortId");
+ List<GenericValue> reminderList = delegator.findList("WorkEffortEventReminder", EntityCondition.makeCondition("workEffortId", EntityOperator.EQUALS, workEffort.get("workEffortId")), null, null, null, false);
+ for (GenericValue reminder : reminderList) {
+ String reminderId = workEffortId + "-" + reminder.getString("sequenceId");
+ VAlarm alarm = null;
+ PropertyList alarmProps = null;
+ boolean newAlarm = true;
+ Iterator<VAlarm> i = alarms.iterator();
+ while (i.hasNext()) {
+ alarm = i.next();
+ Property xProperty = alarm.getProperty(reminderXPropName);
+ if (xProperty != null && reminderId.equals(xProperty.getValue())) {
+ newAlarm = false;
+ alarmProps = alarm.getProperties();
+ // TODO: Write update code. For now, just re-create
+ alarmProps.clear();
+ break;
+ }
+ }
+ if (newAlarm) {
+ alarm = createAlarm(reminder);
+ alarms.add(alarm);
+ alarmProps = alarm.getProperties();
+ alarmProps.add(new XProperty(reminderXPropName, reminderId));
+ }
+ GenericValue contactMech = reminder.getRelatedOne("ContactMech");
+ if (contactMech != null && "EMAIL_ADDRESS".equals(contactMech.get("contactMechTypeId"))) {
+ try {
+ alarmProps.add(new Attendee(contactMech.getString("infoString")));
+ alarmProps.add(Action.EMAIL);
+ alarmProps.add(summary);
+ alarmProps.add(description);
+ } catch (URISyntaxException e) {
+ alarmProps.add(Action.DISPLAY);
+ alarmProps.add(new Description("Error encountered while creating iCalendar: " + e));
+ }
+ } else {
+ alarmProps.add(Action.DISPLAY);
+ alarmProps.add(description);
+ }
+ if (Debug.verboseOn()) {
+ try {
+ alarm.validate(true);
+ Debug.logVerbose("iCalendar alarm passes validation", module);
+ } catch (ValidationException e) {
+ Debug.logVerbose("iCalendar alarm fails validation: " + e, module);
+ }
+ }
+ }
+ }
+
+ protected static void getPartyPrimaryEmailAddress(Property property, GenericValue partyAssign, Map<String, Object> context) {
+ Map<String, ? extends Object> serviceMap = UtilMisc.toMap("partyId", partyAssign.get("partyId"));
+ Map<String, Object> resultMap = invokeService("getPartyICalUri", serviceMap, context);
+ String iCalUri = (String) resultMap.get("iCalUri");
+ if (iCalUri != null) {
+ try {
+ property.setValue(iCalUri);
+ } catch (Exception e) {
+ Debug.logError(e, "Error while setting party URI: ", module);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ protected static List<GenericValue> getRelatedWorkEfforts(GenericValue workEffort, Map<String, Object> context) throws GenericEntityException {
+ Map<String, ? extends Object> serviceMap = UtilMisc.toMap("workEffortId", workEffort.getString("workEffortId"));
+ Map<String, Object> resultMap = invokeService("getICalWorkEfforts", serviceMap, context);
+ List<GenericValue> workEfforts = (List) resultMap.get("workEfforts");
+ if (workEfforts != null) {
+ return WorkEffortWorker.removeDuplicateWorkEfforts(workEfforts);
+ }
+ return null;
+ }
+
+ protected static Map<String, Object> invokeService(String serviceName, Map<String, ? extends Object> serviceMap, Map<String, Object> context) {
+ LocalDispatcher dispatcher = (LocalDispatcher) context.get("dispatcher");
+ Map<String, Object> localMap = FastMap.newInstance();
+ try {
+ ModelService modelService = null;
+ modelService = dispatcher.getDispatchContext().getModelService(serviceName);
+ for (ModelParam modelParam: modelService.getInModelParamList()) {
+ if (serviceMap.containsKey(modelParam.name)) {
+ Object value = serviceMap.get(modelParam.name);
+ if (UtilValidate.isNotEmpty(modelParam.type)) {
+ value = ObjectType.simpleTypeConvert(value, modelParam.type, null, null, null, true);
+ }
+ localMap.put(modelParam.name, value);
+ }
+ }
+ } catch (Exception e) {
+ String errMsg = "Error while creating service Map for service " + serviceName + ": ";
+ Debug.logError(e, errMsg, module);
+ return ServiceUtil.returnError(errMsg + e);
+ }
+ if (context.get("userLogin") != null) {
+ localMap.put("userLogin", context.get("userLogin"));
+ }
+ localMap.put("locale", context.get("locale"));
+ try {
+ return dispatcher.runSync(serviceName, localMap);
+ } catch (GenericServiceException e) {
+ String errMsg = "Error while invoking service " + serviceName + ": ";
+ Debug.logError(e, errMsg, module);
+ return ServiceUtil.returnError(errMsg + e);
+ }
+ }
+
+ protected static void loadPartyAssignment(Property property, GenericValue partyAssign, Map<String, Object> context) {
+ getPartyPrimaryEmailAddress(property, partyAssign, context);
+ if (UtilValidate.isEmpty(property.getValue())) {
+ try {
+ // RFC 2445 4.8.4.1 and 4.8.4.3 Value must be a URL
+ property.setValue("MAILTO:ofbiz-test@yahoo.com");
+ } catch (Exception e) {
+ Debug.logError(e, "Error while setting Property value: ", module);
+ }
+ }
+ ParameterList parameterList = property.getParameters();
+ if (partyAssign != null) {
+ replaceParameter(parameterList, toXParameter(partyIdXParamName, partyAssign.getString("partyId")));
+ replaceParameter(parameterList, new Cn(makePartyName(partyAssign)));
+ replaceParameter(parameterList, toParticipationStatus(partyAssign.getString("assignmentStatusId")));
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ protected static void loadRelatedParties(List<GenericValue> relatedParties, PropertyList componentProps, Map<String, Object> context) {
+ PropertyList attendees = componentProps.getProperties("ATTENDEE");
+ for (GenericValue partyValue : relatedParties) {
+ if ("CAL_ORGANIZER~CAL_OWNER".contains(partyValue.getString("roleTypeId"))) {
+ // RFC 2445 4.6.1, 4.6.2, and 4.6.3 ORGANIZER can appear only once
+ replaceProperty(componentProps, createOrganizer(partyValue, context));
+ } else {
+ String partyId = partyValue.getString("partyId");
+ boolean newAttendee = true;
+ Attendee attendee = null;
+ Iterator<Attendee> i = attendees.iterator();
+ while (i.hasNext()) {
+ attendee = i.next();
+ Parameter xParameter = attendee.getParameter(partyIdXParamName);
+ if (xParameter != null && partyId.equals(xParameter.getValue())) {
+ loadPartyAssignment(attendee, partyValue, context);
+ newAttendee = false;
+ break;
+ }
+ }
+ if (newAttendee) {
+ attendee = createAttendee(partyValue, context);
+ componentProps.add(attendee);
+ }
+ }
+ }
+ }
+
+ protected static void loadWorkEffort(PropertyList componentProps, GenericValue workEffort) {
+ replaceProperty(componentProps, new DtStamp()); // iCalendar object created date/time
+ replaceProperty(componentProps, toClazz(workEffort.getString("scopeEnumId")));
+ replaceProperty(componentProps, toCreated(workEffort.getTimestamp("createdDate")));
+ replaceProperty(componentProps, toDescription(workEffort.getString("description")));
+ replaceProperty(componentProps, toDtStart(workEffort.getTimestamp("estimatedStartDate")));
+ replaceProperty(componentProps, toLastModified(workEffort.getTimestamp("lastModifiedDate")));
+ replaceProperty(componentProps, toPriority(workEffort.getLong("priority")));
+ replaceProperty(componentProps, toLocation(workEffort.getString("locationDesc")));
+ replaceProperty(componentProps, toStatus(workEffort.getString("currentStatusId")));
+ replaceProperty(componentProps, toSummary(workEffort.getString("workEffortName")));
+ replaceProperty(componentProps, toUid(workEffort.getString("workEffortId")));
+ replaceProperty(componentProps, toXProperty(workEffortIdXPropName, workEffort.getString("workEffortId")));
+ }
+
+ protected static String makePartyName(GenericValue partyAssign) {
+ String partyName = partyAssign.getString("groupName");
+ if (UtilValidate.isEmpty(partyName)) {
+ partyName = partyAssign.getString("firstName") + " " + partyAssign.getString("lastName");
+ }
+ return partyName;
+ }
+
+ protected static void replaceParameter(ParameterList parameterList, Parameter parameter) {
+ if (parameter == null) {
+ return;
+ }
+ Parameter existingParam = parameterList.getParameter(parameter.getName());
+ if (existingParam != null) {
+ parameterList.remove(existingParam);
+ }
+ parameterList.add(parameter);
+ }
+
+ protected static void replaceProperty(PropertyList propertyList, Property property) {
+ if (property == null) {
+ return;
+ }
+ Property existingProp = propertyList.getProperty(property.getName());
+ if (existingProp != null) {
+ propertyList.remove(existingProp);
+ }
+ propertyList.add(property);
+ }
+
+ protected static void setMapElement(Map<String, Object> map, String key, Object value) {
+ if (map == null || key == null || value == null) {
+ return;
+ }
+ map.put(key, value);
+ }
+
+ protected static boolean isCalendarPublished(GenericValue publishProperties) {
+ if (publishProperties == null || !"PUBLISH_PROPS".equals(publishProperties.get("workEffortTypeId"))) {
+ return false;
+ }
+ DateRange range = new DateRange(publishProperties.getTimestamp("actualStartDate"), publishProperties.getTimestamp("actualCompletionDate"));
+ return range.includesDate(new Date());
+ }
+
+ @SuppressWarnings("unchecked")
+ public static void storeCalendar(InputStream is, Map<String, Object> context) throws IOException, ParserException, GenericEntityException, GenericServiceException {
+ CalendarBuilder builder = new CalendarBuilder();
+ Calendar calendar = null;
+ try {
+ calendar = builder.build(is);
+ } catch (IOException e) {
+ Debug.logError(e, "Error while updating calendar: ", module);
+ throw e;
+ } finally {
+ if (is != null) {
+ is.close();
+ }
+ }
+ Debug.logInfo("Processing calendar:\r\n" + calendar, module);
+ String workEffortId = fromXProperty(calendar.getProperties(), workEffortIdXPropName);
+ if (workEffortId == null) {
+ // TODO: Create new publish point
+ Debug.logWarning("Warning: Not an OFBiz calendar: \r\n" + calendar, module);
+ return;
+ }
+ if (!workEffortId.equals(context.get("workEffortId"))) {
+ Debug.logWarning("Spoof attempt: received calendar workEffortId " + workEffortId +
+ " on URL workEffortId " + context.get("workEffortId"), module);
+ return;
+ }
+ Map<String, ? extends Object> serviceMap = UtilMisc.toMap("workEffortId", workEffortId, "icalData", calendar.toString());
+ GenericDelegator delegator = (GenericDelegator) context.get("delegator");
+ GenericValue publishProperties = delegator.findOne("WorkEffort", UtilMisc.toMap("workEffortId", workEffortId), false);
+ if (!isCalendarPublished(publishProperties)) {
+ Debug.logInfo("WorkEffort calendar is not published: " + workEffortId, module);
+ return;
+ }
+ GenericValue iCalData = publishProperties.getRelatedOne("WorkEffortIcalData");
+ if (iCalData == null) {
+ invokeService("createWorkEffortICalData", serviceMap, context);
+ } else {
+ invokeService("updateWorkEffortICalData", serviceMap, context);
+ }
+ List<GenericValue> workEfforts = getRelatedWorkEfforts(publishProperties, context);
+ if (workEfforts == null || workEfforts.size() == 0) {
+ return;
+ }
+ // Security issue: make sure only related work efforts get updated
+ Set validWorkEfforts = FastSet.newInstance();
+ for (GenericValue workEffort : workEfforts) {
+ validWorkEfforts.add(workEffort.getString("workEffortId"));
+ }
+ List<Component> components = calendar.getComponents();
+ for (Component component : components) {
+ if (Component.VEVENT.equals(component.getName()) || Component.VTODO.equals(component.getName())) {
+ workEffortId = fromXProperty(component.getProperties(), workEffortIdXPropName);
+ if (workEffortId != null) {
+ if (validWorkEfforts.contains(workEffortId)) {
+ storeWorkEffort(component, context);
+ } else {
+ Debug.logWarning("Spoof attempt: unrelated workEffortId " + workEffortId +
+ " on URL workEffortId " + context.get("workEffortId"), module);
+ continue;
+ }
+ }
+ }
+ }
+ }
+
+ protected static boolean hasPermission(String workEffortId, String action, Map<String, Object> context) {
+ if (context.get("userLogin") == null) {
+ return false;
+ }
+ Map<String, ? extends Object> serviceMap = UtilMisc.toMap("workEffortId", workEffortId, "mainAction", action);
+ Map<String, Object> serviceResult = invokeService("workEffortICalendarPermission", serviceMap, context);
+ Boolean hasPermission = (Boolean) serviceResult.get("hasPermission");
+ if (hasPermission != null) {
+ return hasPermission.booleanValue();
+ } else {
+ return false;
+ }
+ }
+
+ /** Returns a calendar derived from a Work Effort calendar publish point.
+ *
+ * @param delegator
+ * @param workEffortId ID of a work effort with <code>workEffortTypeId</code> equal to
+ * <code>PUBLISH_PROPS</code>.
+ * @return An iCalendar as a <code>String</code>, or <code>null</code>
+ * if <code>workEffortId</code> is invalid.
+ * @throws GenericEntityException
+ */
+ public static String getICalendar(String workEffortId, Map<String, Object> context) throws GenericEntityException {
+ GenericDelegator delegator = (GenericDelegator) context.get("delegator");
+ GenericValue publishProperties = delegator.findOne("WorkEffort", UtilMisc.toMap("workEffortId", workEffortId), false);
+ if (!isCalendarPublished(publishProperties)) {
+ Debug.logInfo("WorkEffort calendar is not published: " + workEffortId, module);
+ return null;
+ }
+ if (!"WES_PUBLIC".equals(publishProperties.get("scopeEnumId")) && !hasPermission(workEffortId, "VIEW", context)) {
+ return null;
+ }
+ Calendar calendar = makeCalendar(publishProperties, context);
+ ComponentList components = calendar.getComponents();
+ List<GenericValue> workEfforts = getRelatedWorkEfforts(publishProperties, context);
+ if (workEfforts != null) {
+ for (GenericValue workEffort : workEfforts) {
+ toCalendarComponent(components, workEffort, context);
+ }
+ }
+ if (Debug.verboseOn()) {
+ try {
+ calendar.validate(true);
+ Debug.logVerbose("iCalendar passes validation", module);
+ } catch (ValidationException e) {
+ Debug.logVerbose("iCalendar fails validation: " + e, module);
+ }
+ }
+ // TODO: Remove this before commit
+ try {
+ calendar.validate(true);
+ Debug.logInfo("iCalendar passes validation", module);
+ } catch (ValidationException e) {
+ Debug.logInfo("iCalendar fails validation: " + e, module);
+ }
+ return calendar.toString();
+ }
+
+ protected static Calendar makeCalendar(GenericValue workEffort, Map<String, Object> context) throws GenericEntityException {
+ String iCalData = null;
+ GenericValue iCalValue = workEffort.getRelatedOne("WorkEffortIcalData");
+ if (iCalValue != null) {
+ iCalData = iCalValue.getString("icalData");
+ }
+ boolean newCalendar = true;
+ Calendar calendar = null;
+ if (iCalData == null) {
+ Debug.logVerbose("iCalendar Data not found, creating new Calendar", module);
+ calendar = new Calendar();
+ } else {
+ Debug.logVerbose("iCalendar Data found, using saved Calendar", module);
+ StringReader reader = new StringReader(iCalData);
+ CalendarBuilder builder = new CalendarBuilder();
+ try {
+ calendar = builder.build(reader);
+ newCalendar = false;
+ } catch (Exception e) {
+ Debug.logError(e, "Error while parsing saved iCalendar, creating new iCalendar: ", module);
+ calendar = new Calendar();
+ }
+ }
+ PropertyList propList = calendar.getProperties();
+ replaceProperty(propList, prodId);
+ replaceProperty(propList, new XProperty(workEffortIdXPropName, workEffort.getString("workEffortId")));
+ if (newCalendar) {
+ propList.add(Version.VERSION_2_0);
+ propList.add(CalScale.GREGORIAN);
+ // TODO: Get time zone from publish properties value
+ java.util.TimeZone tz = java.util.TimeZone.getDefault();
+ TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry();
+ net.fortuna.ical4j.model.TimeZone timezone = registry.getTimeZone(tz.getID());
+ calendar.getComponents().add(timezone.getVTimeZone());
+ }
+ return calendar;
+ }
+
+ protected static void storeWorkEffort(Component component, Map<String, Object> context) throws GenericEntityException, GenericServiceException {
+ PropertyList propertyList = component.getProperties();
+ String workEffortId = fromXProperty(propertyList, workEffortIdXPropName);
+ GenericDelegator delegator = (GenericDelegator) context.get("delegator");
+ GenericValue workEffort = delegator.findOne("WorkEffort", UtilMisc.toMap("workEffortId", workEffortId), false);
+ if (workEffort == null) {
+ return;
+ }
+ if (!hasPermission(workEffortId, "UPDATE", context)) {
+ return;
+ }
+ Map<String, Object> serviceMap = FastMap.newInstance();
+ serviceMap.put("workEffortId", workEffortId);
+ setMapElement(serviceMap, "scopeEnumId", fromClazz(propertyList));
+ setMapElement(serviceMap, "description", fromDescription(propertyList));
+ setMapElement(serviceMap, "estimatedStartDate", fromDtStart(propertyList));
+ setMapElement(serviceMap, "estimatedMilliSeconds", fromDuration(propertyList));
+ setMapElement(serviceMap, "lastModifiedDate", fromLastModified(propertyList));
+ setMapElement(serviceMap, "locationDesc", fromLocation(propertyList));
+ setMapElement(serviceMap, "priority", fromPriority(propertyList));
+ setMapElement(serviceMap, "currentStatusId", fromStatus(propertyList));
+ setMapElement(serviceMap, "workEffortName", fromSummary(propertyList));
+ if ("VTODO".equals(component.getName())) {
+ setMapElement(serviceMap, "actualCompletionDate", fromCompleted(propertyList));
+ setMapElement(serviceMap, "percentComplete", fromPercentComplete(propertyList));
+ } else {
+ setMapElement(serviceMap, "estimatedCompletionDate", fromDtEnd(propertyList));
+ }
+ invokeService("updateWorkEffort", serviceMap, context);
+ }
+
+ @SuppressWarnings("unchecked")
+ protected static void toCalendarComponent(ComponentList components, GenericValue workEffort, Map<String, Object> context) throws GenericEntityException {
+ GenericDelegator delegator = workEffort.getDelegator();
+ String workEffortId = workEffort.getString("workEffortId");
+ context.put("workEffortId", workEffortId);
+ String workEffortTypeId = workEffort.getString("workEffortTypeId");
+ GenericValue typeValue = delegator.findOne("WorkEffortType", UtilMisc.toMap("workEffortTypeId", workEffortTypeId), true);
+ boolean isTask = false;
+ boolean newComponent = true;
+ ComponentList resultList = null;
+ ComponentList alarms = null;
+ Component result = null;
+ if ("TASK".equals(workEffortTypeId) || (typeValue != null && "TASK".equals(typeValue.get("parentTypeId")))) {
+ isTask = true;
+ resultList = components.getComponents("VTODO");
+ } else if ("EVENT".equals(workEffortTypeId) || (typeValue != null && "EVENT".equals(typeValue.get("parentTypeId")))){
+ resultList = components.getComponents("VEVENT");
+ } else {
+ return;
+ }
+ Iterator<Component> i = resultList.iterator();
+ while (i.hasNext()) {
+ result = i.next();
+ Property xProperty = result.getProperty(workEffortIdXPropName);
+ if (xProperty != null && workEffortId.equals(xProperty.getValue())) {
+ newComponent = false;
+ break;
+ }
+ }
+ if (isTask) {
+ VToDo toDo = null;
+ if (newComponent) {
+ toDo = new VToDo();
+ result = toDo;
+ } else {
+ toDo = (VToDo) result;
+ }
+ alarms = toDo.getAlarms();
+ } else {
+ VEvent event = null;
+ if (newComponent) {
+ event = new VEvent();
+ result = event;
+ } else {
+ event = (VEvent) result;
+ }
+ alarms = event.getAlarms();
+ }
+ if (newComponent) {
+ components.add(result);
+ }
+ PropertyList componentProps = result.getProperties();
+ loadWorkEffort(componentProps, workEffort);
+ if (isTask) {
+ replaceProperty(componentProps, toCompleted(workEffort.getTimestamp("actualCompletionDate")));
+ replaceProperty(componentProps, toPercentComplete(workEffort.getLong("percentComplete")));
+ } else {
+ replaceProperty(componentProps, toDtEnd(workEffort.getTimestamp("estimatedCompletionDate")));
+ }
+ if (workEffort.get("estimatedCompletionDate") == null) {
+ replaceProperty(componentProps, toDuration(workEffort.getDouble("estimatedMilliSeconds")));
+ }
+ List<GenericValue> relatedParties = EntityUtil.filterByDate(delegator.findList("WorkEffortPartyAssignView", EntityCondition.makeCondition("workEffortId", EntityOperator.EQUALS, workEffortId), null, null, null, true));
+ if (relatedParties.size() > 0) {
+ loadRelatedParties(relatedParties, componentProps, context);
+ }
+ if (newComponent) {
+ DateRange range = new DateRange(workEffort.getTimestamp("estimatedStartDate"), workEffort.getTimestamp("estimatedCompletionDate"));
+ if (UtilValidate.isNotEmpty(workEffort.getString("tempExprId"))) {
+ TemporalExpression tempExpr = TemporalExpressionWorker.getTemporalExpression(delegator, workEffort.getString("tempExprId"));
+ if (tempExpr != null) {
+ try {
+ ICalRecurConverter.convert(tempExpr, componentProps);
+ } catch (Exception e) {
+ replaceProperty(componentProps, new Description("Error while converting recurrence: " + e));
+ }
+ }
+ } else {
+ componentProps.add(new DtEnd(new DateTime(range.end())));
+ }
+ getAlarms(workEffort, alarms);
+ }
+ if (Debug.verboseOn()) {
+ try {
+ result.validate(true);
+ Debug.logVerbose("iCalendar component passes validation", module);
+ } catch (ValidationException e) {
+ Debug.logVerbose(e, "iCalendar component fails validation: ", module);
+ }
+ }
+ }
+
+ protected static Clazz toClazz(String javaObj) {
+ if (javaObj == null) {
+ return null;
+ }
+ return new Clazz(javaObj.replace("WES_", ""));
+ }
+
+ protected static Completed toCompleted(Timestamp javaObj) {
+ if (javaObj == null) {
+ return null;
+ }
+ return new Completed(new DateTime(javaObj));
+ }
+
+ protected static Created toCreated(Timestamp javaObj) {
+ if (javaObj == null) {
+ return null;
+ }
+ return new Created(new DateTime(javaObj));
+ }
+
+ protected static Description toDescription(String javaObj) {
+ if (javaObj == null) {
+ return null;
+ }
+ return new Description(javaObj);
+ }
+
+ protected static DtEnd toDtEnd(Timestamp javaObj) {
+ if (javaObj == null) {
+ return null;
+ }
+ return new DtEnd(new DateTime(javaObj));
+ }
+
+ protected static DtStart toDtStart(Timestamp javaObj) {
+ if (javaObj == null) {
+ return null;
+ }
+ return new DtStart(new DateTime(javaObj));
+ }
+
+ protected static Duration toDuration(Double javaObj) {
+ if (javaObj == null) {
+ return null;
+ }
+ TimeDuration duration = TimeDuration.fromLong(javaObj.longValue());
+ return new Duration(new Dur(duration.days(), duration.hours(), duration.minutes(), duration.seconds()));
+ }
+
+ protected static LastModified toLastModified(Timestamp javaObj) {
+ if (javaObj == null) {
+ return null;
+ }
+ return new LastModified(new DateTime(javaObj));
+ }
+
+ protected static Location toLocation(String javaObj) {
+ if (javaObj == null) {
+ return null;
+ }
+ return new Location(javaObj);
+ }
+
+ protected static PartStat toParticipationStatus(String statusId) {
+ if (statusId == null) {
+ return null;
+ }
+ return toPartStatusMap.get(statusId);
+ }
+
+ protected static PercentComplete toPercentComplete(Long javaObj) {
+ if (javaObj == null) {
+ return null;
+ }
+ return new PercentComplete(javaObj.intValue());
+ }
+
+ protected static Priority toPriority(Long javaObj) {
+ if (javaObj == null) {
+ return null;
+ }
+ return new Priority(javaObj.intValue());
+ }
+
+ protected static Status toStatus(String javaObj) {
+ if (javaObj == null) {
+ return null;
+ }
+ return toStatusMap.get(javaObj);
+ }
+
+ protected static Summary toSummary(String javaObj) {
+ if (javaObj == null) {
+ return null;
+ }
+ return new Summary(javaObj);
+ }
+
+ protected static Uid toUid(String javaObj) {
+ if (javaObj == null) {
+ return null;
+ }
+ return new Uid(uidPrefix.concat(javaObj));
+ }
+
+ protected static XParameter toXParameter(String name, String value) {
+ if (name == null || value == null) {
+ return null;
+ }
+ return new XParameter(name, value);
+ }
+
+ protected static XProperty toXProperty(String name, String value) {
+ if (name == null || value == null) {
+ return null;
+ }
+ return new XProperty(name, value);
+ }
+}
Propchange: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalConverter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalConverter.java
------------------------------------------------------------------------------
svn:keywords = "Date Rev Author URL Id"
Propchange: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalConverter.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalHandlerFactory.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalHandlerFactory.java?rev=787927&view=auto
==============================================================================
--- ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalHandlerFactory.java (added)
+++ ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalHandlerFactory.java Wed Jun 24 06:58:54 2009
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * 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.ofbiz.workeffort.workeffort;
+
+import java.io.IOException;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import javolution.util.FastMap;
+
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.webapp.webdav.RequestHandler;
+import org.ofbiz.webapp.webdav.RequestHandlerFactory;
+
+/** WebDAV request handler factory for iCalendar. This class is a simple connector
+ * between the WebDAV servlet and the <code>ICalWorker</code> class.
+ */
+@SuppressWarnings("serial")
+public class ICalHandlerFactory implements RequestHandlerFactory {
+
+ public static final String module = ICalHandlerFactory.class.getName();
+
+ protected final Map<String, RequestHandler> handlerMap;
+ protected final RequestHandler invalidMethodHandler = new InvalidMethodHandler();
+ protected final RequestHandler doNothingHandler = new DoNothingHandler();
+
+ public ICalHandlerFactory() {
+ this.handlerMap = FastMap.newInstance();
+ this.handlerMap.put("COPY", doNothingHandler);
+ this.handlerMap.put("DELETE", doNothingHandler);
+ this.handlerMap.put("GET", new GetHandler());
+ this.handlerMap.put("HEAD", doNothingHandler);
+ this.handlerMap.put("LOCK", doNothingHandler);
+ this.handlerMap.put("MKCOL", doNothingHandler);
+ this.handlerMap.put("MOVE", doNothingHandler);
+ this.handlerMap.put("POST", doNothingHandler);
+ this.handlerMap.put("PROPFIND", new PropFindHandler());
+ this.handlerMap.put("PROPPATCH", doNothingHandler);
+ this.handlerMap.put("PUT", new PutHandler());
+ this.handlerMap.put("UNLOCK", doNothingHandler);
+ }
+
+ public RequestHandler getHandler(String method) {
+ RequestHandler handler = this.handlerMap.get(method);
+ if (handler == null) {
+ return invalidMethodHandler;
+ }
+ return handler;
+ }
+
+ protected static class InvalidMethodHandler implements RequestHandler {
+ public void handleRequest(HttpServletRequest request, HttpServletResponse response, ServletContext context) throws ServletException, IOException {
+ Debug.logInfo("[InvalidMethodHandler] method = " + request.getMethod(), module);
+ response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
+ }
+ }
+
+ protected static class DoNothingHandler implements RequestHandler {
+ public void handleRequest(HttpServletRequest request, HttpServletResponse response, ServletContext context) throws ServletException, IOException {
+ Debug.logInfo("[DoNothingHandler] method = " + request.getMethod(), module);
+ response.setStatus(HttpServletResponse.SC_OK);
+ }
+ }
+
+ protected static class GetHandler implements RequestHandler {
+ public void handleRequest(HttpServletRequest request, HttpServletResponse response, ServletContext context) throws ServletException, IOException {
+ Debug.logInfo("[GetHandler] starting request", module);
+ ICalWorker.handleGetRequest(request, response, context);
+ Debug.logInfo("[GetHandler] finished request", module);
+ }
+ }
+
+ protected static class PutHandler implements RequestHandler {
+ public void handleRequest(HttpServletRequest request, HttpServletResponse response, ServletContext context) throws ServletException, IOException {
+ Debug.logInfo("[PutHandler] starting request", module);
+ ICalWorker.handlePutRequest(request, response, context);
+ Debug.logInfo("[PutHandler] finished request", module);
+ }
+ }
+
+ protected static class PropFindHandler implements RequestHandler {
+ public void handleRequest(HttpServletRequest request, HttpServletResponse response, ServletContext context) throws ServletException, IOException {
+ Debug.logInfo("[PropFindHandler] starting request", module);
+ ICalWorker.handlePropFindRequest(request, response, context);
+ Debug.logInfo("[PropFindHandler] finished request", module);
+ }
+ }
+
+};
Propchange: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalHandlerFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalHandlerFactory.java
------------------------------------------------------------------------------
svn:keywords = "Date Rev Author URL Id"
Propchange: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalHandlerFactory.java
------------------------------------------------------------------------------
svn:mime-type = text/plain