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 2008/11/18 19:56:12 UTC
svn commit: r718684 - in /ofbiz/trunk: ./ applications/workeffort/
applications/workeffort/data/ applications/workeffort/entitydef/
applications/workeffort/src/org/ofbiz/workeffort/workeffort/
applications/workeffort/webapp/ical/ applications/workeffor...
Author: adrianc
Date: Tue Nov 18 10:56:11 2008
New Revision: 718684
URL: http://svn.apache.org/viewvc?rev=718684&view=rev
Log:
A rudimentary iCalendar integration implementation. Work efforts can be published in iCalendar format. The published calendar is read-only.
Run ant run-install, then navigate to:
https://localhost:8443/iCalendar/CALENDAR_PUB_DEMO/MyCalendar.ics
for a demonstration.
I will continue to build this out as I have time.
Added:
ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalRecurConverter.java (with props)
ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalServlet.java (with props)
ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalendarWorker.java (with props)
ofbiz/trunk/applications/workeffort/webapp/ical/
ofbiz/trunk/applications/workeffort/webapp/ical/WEB-INF/
ofbiz/trunk/applications/workeffort/webapp/ical/WEB-INF/web.xml (with props)
ofbiz/trunk/framework/base/lib/ical4j-1.0-beta5.jar (with props)
Modified:
ofbiz/trunk/.classpath
ofbiz/trunk/LICENSE
ofbiz/trunk/applications/workeffort/build.xml
ofbiz/trunk/applications/workeffort/data/WorkEffortTypeData.xml
ofbiz/trunk/applications/workeffort/entitydef/entitymodel_view.xml
ofbiz/trunk/applications/workeffort/ofbiz-component.xml
ofbiz/trunk/specialpurpose/projectmgr/data/ProjectMgrDemoData.xml
Modified: ofbiz/trunk/.classpath
URL: http://svn.apache.org/viewvc/ofbiz/trunk/.classpath?rev=718684&r1=718683&r2=718684&view=diff
==============================================================================
--- ofbiz/trunk/.classpath (original)
+++ ofbiz/trunk/.classpath Tue Nov 18 10:56:11 2008
@@ -90,6 +90,7 @@
<classpathentry kind="lib" path="framework/geronimo/lib/geronimo-transaction-2.1.1.jar"/>
<classpathentry kind="lib" path="framework/entity/lib/ofbiz-minerva.jar"/>
<classpathentry kind="lib" path="framework/entity/lib/commons-dbcp-1.3-20080708-r674758.jar"/>
+ <classpathentry kind="lib" path="framework/base/lib/ical4j-1.0-beta5.jar"/>
<classpathentry kind="lib" path="framework/base/lib/Tidy.jar"/>
<classpathentry kind="lib" path="framework/base/lib/mx4j-remote-3.0.1.jar"/>
<classpathentry kind="lib" path="framework/base/lib/mx4j-3.0.1.jar"/>
Modified: ofbiz/trunk/LICENSE
URL: http://svn.apache.org/viewvc/ofbiz/trunk/LICENSE?rev=718684&r1=718683&r2=718684&view=diff
==============================================================================
--- ofbiz/trunk/LICENSE (original)
+++ ofbiz/trunk/LICENSE Tue Nov 18 10:56:11 2008
@@ -420,21 +420,22 @@
=========================================================================
The following libraries distributed with Apache OFBiz are licensed under the
BSD License:
-ofbiz/trunk/framework/base/lib/javacc/javacc-4.1.jar
-ofbiz/trunk/framework/base/lib/httpunit.jar
ofbiz/trunk/framework/base/lib/freemarker-2.3.10.jar
+ofbiz/trunk/framework/base/lib/httpunit.jar
+ofbiz/trunk/framework/base/lib/ical4j-1.0-beta5.jar
+ofbiz/trunk/framework/base/lib/javacc/javacc-4.1.jar
+ofbiz/trunk/framework/base/lib/javolution-5.2.3.jar
ofbiz/trunk/framework/base/lib/junitperf.jar
ofbiz/trunk/framework/base/lib/scripting/antlr-2.7.6.jar
ofbiz/trunk/framework/base/lib/scripting/asm-2.2.jar
ofbiz/trunk/framework/base/lib/scripting/asm-analysis-2.2.jar
ofbiz/trunk/framework/base/lib/scripting/asm-tree-2.2.jar
ofbiz/trunk/framework/base/lib/scripting/asm-util-2.2.jar
-ofbiz/trunk/specialpurpose/pos/lib/looks-2.0.2.jar
-ofbiz/trunk/framework/base/lib/javolution-5.2.3.jar
-ofbiz/trunk/framework/images/webapp/images/dojo/*
-ofbiz/trunk/specialpurpose/ldap/lib/cas-server-core-3.3.jar
ofbiz/trunk/framework/images/webapp/images/jsgantt.css
ofbiz/trunk/framework/images/webapp/images/jsgantt.js
+ofbiz/trunk/framework/images/webapp/images/dojo/*
+ofbiz/trunk/specialpurpose/ldap/lib/cas-server-core-3.3.jar
+ofbiz/trunk/specialpurpose/pos/lib/looks-2.0.2.jar
=========================================================================
The BSD License
Modified: ofbiz/trunk/applications/workeffort/build.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/build.xml?rev=718684&r1=718683&r2=718684&view=diff
==============================================================================
--- ofbiz/trunk/applications/workeffort/build.xml (original)
+++ ofbiz/trunk/applications/workeffort/build.xml Tue Nov 18 10:56:11 2008
@@ -35,6 +35,7 @@
<fileset dir="../../framework/base/lib/j2eespecs" includes="*.jar"/>
<fileset dir="../../framework/base/lib/scripting" includes="*.jar"/>
<fileset dir="../../framework/base/build/lib" includes="*.jar"/>
+ <fileset dir="../../framework/catalina/lib" includes="*.jar"/>
<fileset dir="../../framework/entity/lib" includes="*.jar"/>
<fileset dir="../../framework/entity/build/lib" includes="*.jar"/>
<fileset dir="../../framework/security/build/lib" includes="*.jar"/>
Modified: ofbiz/trunk/applications/workeffort/data/WorkEffortTypeData.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/data/WorkEffortTypeData.xml?rev=718684&r1=718683&r2=718684&view=diff
==============================================================================
--- ofbiz/trunk/applications/workeffort/data/WorkEffortTypeData.xml (original)
+++ ofbiz/trunk/applications/workeffort/data/WorkEffortTypeData.xml Tue Nov 18 10:56:11 2008
@@ -180,7 +180,8 @@
<WorkEffortType description="Business Travel" hasTable="N" parentTypeId="EVENT" workEffortTypeId="BUSINESS_TRAVEL"/>
<WorkEffortType description="Meeting" hasTable="N" parentTypeId="EVENT" workEffortTypeId="MEETING"/>
<WorkEffortType description="Personal Time Off" hasTable="N" parentTypeId="EVENT" workEffortTypeId="PERSONAL_TIMEOFF"/>
-
+ <WorkEffortType description="Publish Properties" hasTable="N" workEffortTypeId="PUBLISH_PROPS"/>
+
<!-- Routing status, (workEffort Template) -->
<StatusType description="Manufacturing Task and Routing status" hasTable="N" parentTypeId="WORK_EFFORT_STATUS" statusTypeId="ROUTING_STATUS"/>
Modified: ofbiz/trunk/applications/workeffort/entitydef/entitymodel_view.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/entitydef/entitymodel_view.xml?rev=718684&r1=718683&r2=718684&view=diff
==============================================================================
--- ofbiz/trunk/applications/workeffort/entitydef/entitymodel_view.xml (original)
+++ ofbiz/trunk/applications/workeffort/entitydef/entitymodel_view.xml Tue Nov 18 10:56:11 2008
@@ -258,6 +258,30 @@
<key-map field-name="workEffortIdFrom" rel-field-name="workEffortId"/>
</relation>
</view-entity>
+ <view-entity entity-name="WorkEffortAssocToView"
+ package-name="org.ofbiz.workeffort.workeffort"
+ title="Work Effort Association To (Child) View">
+ <member-entity entity-alias="WEA" entity-name="WorkEffortAssoc"/>
+ <member-entity entity-alias="WETO" entity-name="WorkEffort"/>
+ <alias-all entity-alias="WEA"/>
+ <alias-all entity-alias="WETO"/>
+ <view-link entity-alias="WEA" rel-entity-alias="WETO">
+ <key-map field-name="workEffortIdTo" rel-field-name="workEffortId"/>
+ </view-link>
+ </view-entity>
+ <!--
+ <view-entity entity-name="WorkEffortAssocFromView"
+ package-name="org.ofbiz.workeffort.workeffort"
+ title="Work Effort Association From (Parent) View">
+ <member-entity entity-alias="WEA" entity-name="WorkEffortAssoc"/>
+ <member-entity entity-alias="WEFR" entity-name="WorkEffort"/>
+ <alias-all entity-alias="WEA"/>
+ <alias-all entity-alias="WEFR"/>
+ <view-link entity-alias="WEA" rel-entity-alias="WEFR">
+ <key-map field-name="workEffortIdFrom" rel-field-name="workEffortId"/>
+ </view-link>
+ </view-entity>
+ -->
<view-entity entity-name="WorkEffortNoteAndData"
package-name="org.ofbiz.workeffort.workeffort"
title="Work Effort Note And Note Data Entity">
Modified: ofbiz/trunk/applications/workeffort/ofbiz-component.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/ofbiz-component.xml?rev=718684&r1=718683&r2=718684&view=diff
==============================================================================
--- ofbiz/trunk/applications/workeffort/ofbiz-component.xml (original)
+++ ofbiz/trunk/applications/workeffort/ofbiz-component.xml Tue Nov 18 10:56:11 2008
@@ -43,4 +43,11 @@
location="webapp/workeffort"
base-permission="OFBTOOLS,WORKEFFORTMGR"
mount-point="/workeffort"/>
+
+ <webapp name="ical"
+ title="iCalendar"
+ app-bar-display="false"
+ server="default-server"
+ location="webapp/ical"
+ mount-point="/iCalendar"/>
</ofbiz-component>
Added: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalRecurConverter.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalRecurConverter.java?rev=718684&view=auto
==============================================================================
--- ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalRecurConverter.java (added)
+++ ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalRecurConverter.java Tue Nov 18 10:56:11 2008
@@ -0,0 +1,293 @@
+/*******************************************************************************
+ * 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.util.List;
+import java.util.Set;
+import java.util.Stack;
+
+import javolution.util.FastList;
+import javolution.util.FastSet;
+
+import net.fortuna.ical4j.model.*;
+import net.fortuna.ical4j.model.property.*;
+
+import org.ofbiz.service.calendar.TemporalExpression;
+import org.ofbiz.service.calendar.TemporalExpressions;
+import org.ofbiz.service.calendar.TemporalExpressionVisitor;
+import org.ofbiz.service.calendar.TemporalExpressions.*;
+
+/** Temporal Expression to iCalendar recurrence converter. The conversion results
+ * (or conversion success) are unpredictable since the OFBiz Temporal Expressions
+ * are more sophisticated than iCalendar recurrences. This class attempts to
+ * make a best attempt at conversion and throws <code>IllegalStateException</code>
+ * when conversion is not possible.
+ */
+public class ICalRecurConverter implements TemporalExpressionVisitor {
+ protected static final WeekDay dayOfWeekArray[] = {WeekDay.SU, WeekDay.MO, WeekDay.TU, WeekDay.WE, WeekDay.TH, WeekDay.FR, WeekDay.SA};
+ protected DtStart dateStart = null;
+ protected List<DateListProperty> incDateList = FastList.newInstance();
+ protected List<DateListProperty> exDateList = FastList.newInstance();
+ protected List<RRule> incRuleList = FastList.newInstance();
+ protected List<ExRule> exRuleList = FastList.newInstance();
+ protected VisitorState state = new VisitorState();
+ protected Stack<VisitorState> stateStack = new Stack<VisitorState>();
+
+ protected ICalRecurConverter() {}
+
+ @SuppressWarnings("unchecked")
+ public static void convert(TemporalExpression expr, PropertyList eventProps) {
+ ICalRecurConverter converter = new ICalRecurConverter();
+ expr.accept(converter);
+ DtStart dateStart = (DtStart) eventProps.getProperty(Property.DTSTART);
+ if (converter.dateStart != null) {
+ if (dateStart != null) {
+ eventProps.remove(dateStart);
+ }
+ dateStart = converter.dateStart;
+ eventProps.add(dateStart);
+ }
+ if (dateStart != null && converter.exRuleList.size() > 0) {
+ // iCalendar quirk - if exclusions exist, then the start date must be excluded also
+ ExDate exdate = new ExDate();
+ exdate.getDates().add(dateStart.getDate());
+ converter.exDateList.add(exdate);
+ }
+ eventProps.addAll(converter.incDateList);
+ eventProps.addAll(converter.incRuleList);
+ eventProps.addAll(converter.exDateList);
+ eventProps.addAll(converter.exRuleList);
+ }
+
+ // ----- TemporalExpressionVisitor Implementation ----- //
+
+ public void visit(Null expr) {}
+
+ public void visit(Union expr) {
+ for (TemporalExpression childExpr : expr.getExpressionSet()) {
+ childExpr.accept(this);
+ }
+ }
+
+ public void visit(Intersection expr) {
+ this.stateStack.push(this.state);
+ VisitorState newState = new VisitorState();
+ newState.isExcluded = this.state.isExcluded;
+ newState.isIntersection = true;
+ this.state = newState;
+ for (TemporalExpression childExpr : expr.getExpressionSet()) {
+ childExpr.accept(this);
+ }
+ this.state = this.stateStack.pop();
+ if (newState.inclRecurList.size() > 0) {
+ this.incRuleList.add(new RRule(this.consolidateRecurs(newState.inclRecurList)));
+ }
+ if (newState.exRecurList.size() > 0) {
+ this.exRuleList.add(new ExRule(this.consolidateRecurs(newState.exRecurList)));
+ }
+ }
+
+ public void visit(Difference expr) {
+ VisitorState newState = new VisitorState();
+ newState.isIntersection = this.state.isIntersection;
+ this.stateStack.push(this.state);
+ this.state = newState;
+ expr.getIncluded().accept(this);
+ newState.isExcluded = true;
+ expr.getExcluded().accept(this);
+ this.state = this.stateStack.pop();
+ if (this.state.isIntersection) {
+ this.state.inclRecurList.addAll(newState.inclRecurList);
+ this.state.exRecurList.addAll(newState.exRecurList);
+ }
+ }
+
+ public void visit(TemporalExpressions.DateRange expr) {
+ if (this.state.isExcluded) {
+ throw new IllegalStateException("iCalendar does not support excluded date ranges");
+ }
+ org.ofbiz.base.util.DateRange range = expr.getDateRange();
+ PeriodList periodList = new PeriodList();
+ periodList.add(new Period(new DateTime(range.start()), new DateTime(range.end())));
+ this.incDateList.add(new RDate(periodList));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void visit(TimeOfDayRange expr) {
+ // TODO: this needs a better conversion
+ int startHr = expr.getStartHours();
+ int endHr = expr.getEndHours();
+ NumberList hourList = new NumberList();
+ hourList.add(startHr);
+ while (startHr != endHr) {
+ startHr++;
+ if (startHr == 24) {
+ startHr = 0;
+ }
+ hourList.add(startHr);
+ }
+ Recur recur = new Recur(Recur.HOURLY, 0);
+ recur.getHourList().addAll(hourList);
+ this.state.addRecur(recur);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void visit(TemporalExpressions.DayOfWeekRange expr) {
+ int startDay = expr.getStartDay();
+ int endDay = expr.getEndDay();
+ WeekDayList dayList = new WeekDayList();
+ dayList.add(dayOfWeekArray[startDay - 1]);
+ while (startDay != endDay) {
+ startDay++;
+ if (startDay > java.util.Calendar.SATURDAY) {
+ startDay = java.util.Calendar.SUNDAY;
+ }
+ dayList.add(dayOfWeekArray[startDay - 1]);
+ }
+ Recur recur = new Recur(Recur.DAILY, 0);
+ recur.getDayList().addAll(dayList);
+ this.state.addRecur(recur);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void visit(TemporalExpressions.MonthRange expr) {
+ int startMonth = expr.getStartMonth();
+ int endMonth = expr.getEndMonth();
+ java.util.Calendar cal = java.util.Calendar.getInstance();
+ int maxMonth = cal.getActualMaximum(java.util.Calendar.MONTH);
+ NumberList monthList = new NumberList();
+ monthList.add(startMonth + 1);
+ while (startMonth != endMonth) {
+ startMonth++;
+ if (startMonth > maxMonth) {
+ startMonth = java.util.Calendar.JANUARY;
+ }
+ monthList.add(startMonth + 1);
+ }
+ Recur recur = new Recur(Recur.MONTHLY, 0);
+ recur.getMonthList().addAll(monthList);
+ this.state.addRecur(recur);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void visit(TemporalExpressions.DayOfMonthRange expr) {
+ int startDay = expr.getStartDay();
+ int endDay = expr.getEndDay();
+ NumberList dayList = new NumberList();
+ dayList.add(startDay);
+ while (startDay != endDay) {
+ startDay++;
+ dayList.add(startDay);
+ }
+ Recur recur = new Recur(Recur.DAILY, 0);
+ recur.getMonthDayList().addAll(dayList);
+ this.state.addRecur(recur);
+ }
+
+ public void visit(TemporalExpressions.DayInMonth expr) {
+ Recur recur = new Recur(Recur.MONTHLY, 0);
+ recur.getDayList().add(new WeekDay(dayOfWeekArray[expr.getDayOfWeek() - 1], expr.getOccurrence()));
+ this.state.addRecur(recur);
+ }
+
+ public void visit(TemporalExpressions.Frequency expr) {
+ if (this.dateStart == null) {
+ this.dateStart = new DtStart(new net.fortuna.ical4j.model.Date(expr.getStartDate()));
+ }
+ int freqCount = expr.getFreqCount();
+ int freqType = expr.getFreqType();
+ switch (freqType) {
+ case java.util.Calendar.SECOND:
+ this.state.addRecur((new Recur(Recur.SECONDLY, freqCount)));
+ case java.util.Calendar.MINUTE:
+ this.state.addRecur((new Recur(Recur.MINUTELY, freqCount)));
+ case java.util.Calendar.HOUR:
+ this.state.addRecur((new Recur(Recur.HOURLY, freqCount)));
+ case java.util.Calendar.DAY_OF_MONTH:
+ this.state.addRecur((new Recur(Recur.DAILY, freqCount)));
+ case java.util.Calendar.MONTH:
+ this.state.addRecur((new Recur(Recur.MONTHLY, freqCount)));
+ case java.util.Calendar.YEAR:
+ this.state.addRecur((new Recur(Recur.YEARLY, freqCount)));
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ protected Recur consolidateRecurs(List<Recur> recurList) {
+ // Try to consolidate a list of Recur instances into one instance
+ Set<Integer> monthList = FastSet.newInstance();
+ Set<Integer> monthDayList = FastSet.newInstance();
+ Set<WeekDay> weekDayList = FastSet.newInstance();
+ Set<Integer> hourList = FastSet.newInstance();
+ String freq = null;
+ int freqCount = 0;
+ for (Recur recur : recurList) {
+ monthList.addAll(recur.getMonthList());
+ monthDayList.addAll(recur.getMonthDayList());
+ weekDayList.addAll(recur.getDayList());
+ hourList.addAll(recur.getHourList());
+ if (recur.getInterval() != 0 && freq == null) {
+ freq = recur.getFrequency();
+ freqCount = recur.getInterval();
+ }
+ }
+ if (freq == null && monthList.size() > 0) {
+ freq = Recur.MONTHLY;
+ } else if (freq == null && (monthDayList.size() > 0 || weekDayList.size() > 0)) {
+ freq = Recur.DAILY;
+ } else if (freq == null && hourList.size() > 0) {
+ freq = Recur.HOURLY;
+ }
+ if (freq == null) {
+ throw new IllegalStateException("Unable to convert intersection");
+ }
+ Recur newRecur = new Recur(freq, 0);
+ if (freqCount != 0) {
+ newRecur.setInterval(freqCount);
+ }
+ newRecur.getMonthList().addAll(monthList);
+ newRecur.getMonthDayList().addAll(monthDayList);
+ newRecur.getDayList().addAll(weekDayList);
+ newRecur.getHourList().addAll(hourList);
+ return newRecur;
+ }
+
+ protected class VisitorState {
+ public boolean isExcluded = false;
+ public boolean isIntersection = false;
+ public List<Recur> inclRecurList = FastList.newInstance();
+ public List<Recur> exRecurList = FastList.newInstance();
+ public void addRecur(Recur recur) {
+ if (this.isIntersection) {
+ if (this.isExcluded) {
+ this.exRecurList.add(recur);
+ } else {
+ this.inclRecurList.add(recur);
+ }
+ } else {
+ if (this.isExcluded) {
+ exRuleList.add(new ExRule(recur));
+ } else {
+ incRuleList.add(new RRule(recur));
+ }
+ }
+ }
+ }
+}
Propchange: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalRecurConverter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalRecurConverter.java
------------------------------------------------------------------------------
svn:keywords = "Date Rev Author URL Id"
Propchange: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalRecurConverter.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalServlet.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalServlet.java?rev=718684&view=auto
==============================================================================
--- ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalServlet.java (added)
+++ ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalServlet.java Tue Nov 18 10:56:11 2008
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * 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.io.OutputStreamWriter;
+import java.io.Writer;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import net.fortuna.ical4j.model.Calendar;
+
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.UtilJ2eeCompat;
+import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.entity.GenericDelegator;
+
+@SuppressWarnings("serial")
+public class ICalServlet extends HttpServlet {
+ public static final String module = ICalServlet.class.getName();
+
+ /** Initialize this servlet. */
+ public void init() throws ServletException {
+ super.init();
+ if (Debug.infoOn()) {
+ Debug.logInfo("[ICalServlet.init] Loading iCalendar Servlet mounted on path " + this.getServletContext().getRealPath("/"), module);
+ }
+ }
+
+ public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ String path = req.getPathInfo();
+ if (UtilValidate.isEmpty(path)) {
+ path = "/";
+ }
+ String workEffortId = path.substring(1);
+ if (workEffortId.contains("/")) {
+ workEffortId = workEffortId.substring(0, workEffortId.indexOf("/"));
+ }
+ if (workEffortId.length() < 1) {
+ resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ return;
+ }
+ if (Debug.infoOn()) {
+ Debug.logInfo("[ICalServlet.doGet] workEffortId = " + workEffortId, module);
+ }
+ GenericDelegator delegator = null;
+ HttpSession session = req.getSession();
+ String delegatorName = (String) session.getAttribute("delegatorName");
+ if (UtilValidate.isNotEmpty(delegatorName)) {
+ delegator = GenericDelegator.getGenericDelegator(delegatorName);
+ }
+ if (delegator == null) {
+ delegator = (GenericDelegator) this.getServletContext().getAttribute("delegator");
+ }
+ if (delegator == null) {
+ Debug.logError("[ICalServlet.doGet] ERROR: delegator not found in ServletContext", module);
+ resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ return;
+ }
+ Calendar calendar = null;
+ try {
+ calendar = ICalendarWorker.getICalendar(delegator, workEffortId);
+ } catch (Exception e) {
+ Debug.logError("[ICalServlet.doGet] Error while getting iCalendar: " + e, module);
+ resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ return;
+ }
+ if (calendar == null) {
+ resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
+ resp.setContentType("text/calendar");
+ resp.setStatus(HttpServletResponse.SC_OK);
+ Writer writer = null;
+ if (UtilJ2eeCompat.useOutputStreamNotWriter(this.getServletContext())) {
+ ServletOutputStream ros = resp.getOutputStream();
+ writer = new OutputStreamWriter(ros, "UTF-8");
+ } else {
+ writer = resp.getWriter();
+ }
+ writer.write(calendar.toString());
+ writer.close();
+ if (Debug.infoOn()) {
+ Debug.logInfo("[ICalServlet.doGet] finished request", module);
+ }
+ }
+};
Propchange: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalServlet.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalServlet.java
------------------------------------------------------------------------------
svn:keywords = "Date Rev Author URL Id"
Propchange: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalServlet.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalendarWorker.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalendarWorker.java?rev=718684&view=auto
==============================================================================
--- ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalendarWorker.java (added)
+++ ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalendarWorker.java Tue Nov 18 10:56:11 2008
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * 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.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+
+import javolution.util.FastList;
+
+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.TimeDuration;
+import org.ofbiz.base.util.UtilMisc;
+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.EntityConditionList;
+import org.ofbiz.entity.condition.EntityExpr;
+import org.ofbiz.entity.condition.EntityOperator;
+import org.ofbiz.entity.util.EntityUtil;
+import org.ofbiz.service.calendar.TemporalExpression;
+import org.ofbiz.service.calendar.TemporalExpressionWorker;
+
+/** iCalendar worker class. */
+public class ICalendarWorker {
+ public static final String module = ICalendarWorker.class.getName();
+ protected static ProdId prodId = new ProdId("-//Apache Open For Business//Work Effort Calendar//EN");
+ protected static Map<String, Status> statusMap = UtilMisc.toMap("CAL_TENTATIVE", Status.VEVENT_TENTATIVE,
+ "CAL_CONFIRMED", Status.VEVENT_CONFIRMED, "CAL_CANCELLED", Status.VEVENT_CANCELLED);
+ protected static String workEffortIdPropName = "X-ORG-OFBIZ-WORKEFFORT-ID";
+
+ public static net.fortuna.ical4j.model.Calendar getICalendar(GenericDelegator delegator, String workEffortId) throws GenericEntityException {
+ GenericValue calendarProperties = delegator.findByPrimaryKey("WorkEffort", UtilMisc.toMap("workEffortId", workEffortId));
+ if (calendarProperties == null || !"PUBLISH_PROPS".equals(calendarProperties.get("workEffortTypeId"))) {
+ return null;
+ }
+ net.fortuna.ical4j.model.Calendar calendar = makeCalendar(calendarProperties);
+ ComponentList components = calendar.getComponents();
+ List<GenericValue> workEfforts = getRelatedWorkEfforts(calendarProperties);
+ for (GenericValue workEffort : workEfforts) {
+ components.add(makeEvent(workEffort));
+ }
+ return calendar;
+ }
+
+ public static List<GenericValue> getRelatedWorkEfforts(GenericValue workEffort) throws GenericEntityException {
+ GenericDelegator delegator = workEffort.getDelegator();
+ String workEffortId = workEffort.getString("workEffortId");
+ List<GenericValue> relatedParties = EntityUtil.filterByDate(delegator.findList("WorkEffortPartyAssignment", EntityCondition.makeCondition("workEffortId", EntityOperator.EQUALS, workEffortId), null, null, null, false));
+ List<GenericValue> relatedFixedAssets = EntityUtil.filterByDate(delegator.findList("WorkEffortFixedAssetAssign", EntityCondition.makeCondition("workEffortId", EntityOperator.EQUALS, workEffortId), null, null, null, false));
+ List<GenericValue> workEfforts = FastList.newInstance();
+ List<EntityCondition> conditionList = UtilMisc.<EntityCondition>toList(
+ EntityCondition.makeCondition("scopeEnumId", EntityOperator.EQUALS, "WES_PUBLIC"),
+ EntityCondition.makeCondition("workEffortTypeId", EntityOperator.NOT_EQUAL, "PUBLISH_PROPS"));
+ EntityExpr variableExpr = EntityCondition.makeCondition("partyId", EntityOperator.EQUALS, "");
+ conditionList.add(variableExpr);
+ EntityCondition workEffortCond = EntityCondition.makeCondition(conditionList);
+ for (GenericValue partyValue : relatedParties) {
+ variableExpr.init("partyId", EntityOperator.EQUALS, partyValue.get("partyId"));
+ workEfforts.addAll(delegator.findList("WorkEffortAndPartyAssign", workEffortCond, null, null, null, false));
+ }
+ for (GenericValue fixedAssetValue : relatedFixedAssets) {
+ variableExpr.init("fixedAssetId", EntityOperator.EQUALS, fixedAssetValue.get("fixedAssetId"));
+ workEfforts.addAll(delegator.findList("WorkEffortAndPartyAssign", workEffortCond, null, null, null, false));
+ }
+ workEfforts.addAll(EntityUtil.filterByDate(delegator.findList("WorkEffortAssocToView", EntityCondition.makeCondition("workEffortIdFrom", EntityOperator.EQUALS, workEffortId), null, null, null, false)));
+ return WorkEffortWorker.removeDuplicateWorkEfforts(workEfforts);
+ }
+
+ public static VEvent makeEvent(GenericValue workEffort) throws GenericEntityException {
+ GenericDelegator delegator = workEffort.getDelegator();
+ String workEffortId = workEffort.getString("workEffortId");
+ PropertyList eventProps = new PropertyList();
+ eventProps.add(new DtStamp()); // iCalendar object created date/time
+ if (workEffort.getTimestamp("createdDate") != null) {
+ eventProps.add(new Created(new DateTime(workEffort.getTimestamp("createdDate"))));
+ }
+ if (workEffort.getTimestamp("lastModifiedDate") != null) {
+ eventProps.add(new LastModified(new DateTime(workEffort.getTimestamp("lastModifiedDate"))));
+ }
+ eventProps.add(new XProperty(workEffortIdPropName, workEffort.getString("workEffortId")));
+ eventProps.add(new Summary(workEffort.getString("workEffortName")));
+ Status eventStatus = statusMap.get(workEffort.getString("currentStatusId"));
+ if (eventStatus != null) {
+ eventProps.add(statusMap.get(workEffort.getString("currentStatusId")));
+ }
+ Double durationMillis = workEffort.getDouble("estimatedMilliSeconds");
+ if (durationMillis != null) {
+ TimeDuration duration = TimeDuration.fromLong(durationMillis.longValue());
+ eventProps.add(new Duration(new Dur(duration.days(), duration.hours(), duration.minutes(), duration.seconds())));
+ }
+ List<GenericValue> relatedParties = EntityUtil.filterByDate(delegator.findList("WorkEffortPartyAssignView", EntityCondition.makeCondition("workEffortId", EntityOperator.EQUALS, workEffortId), null, null, null, false));
+ for (GenericValue partyValue : relatedParties) {
+ ParameterList paramList = new ParameterList();
+ String partyName = partyValue.getString("groupName");
+ if (UtilValidate.isEmpty(partyName)) {
+ partyName = partyValue.getString("firstName") + " " + partyValue.getString("lastName");
+ }
+ paramList.add(new Cn(partyName));
+ // paramList.add(new XParameter(partyIdPropName, partyValue.getString("partyId")));
+ try {
+ if ("CAL_ORGANIZER~CAL_OWNER".contains(partyValue.getString("roleTypeId"))) {
+ eventProps.add(new Organizer(paramList, ""));
+ } else {
+ eventProps.add(new Attendee(paramList, ""));
+ }
+ } catch (Exception e) {}
+ }
+ DateRange range = new DateRange(workEffort.getTimestamp("estimatedStartDate"), workEffort.getTimestamp("estimatedCompletionDate"));
+ eventProps.add(new DtStart(new DateTime(range.start())));
+ if (UtilValidate.isNotEmpty(workEffort.getString("tempExprId"))) {
+ TemporalExpression tempExpr = TemporalExpressionWorker.getTemporalExpression(delegator, workEffort.getString("tempExprId"));
+ if (tempExpr != null) {
+ try {
+ ICalRecurConverter.convert(tempExpr, eventProps);
+ } catch (Exception e) {
+ eventProps.add(new Description("Error while converting recurrence: " + e));
+ eventProps.add(new DtStart());
+ eventProps.add(new DtEnd());
+ return new VEvent(eventProps);
+ }
+ }
+ } else {
+ eventProps.add(new DtEnd(new DateTime(range.end())));
+ }
+ if (workEffort.getString("description") != null) {
+ eventProps.add(new Description(workEffort.getString("description")));
+ }
+ return new VEvent(eventProps);
+ }
+
+ public static net.fortuna.ical4j.model.Calendar makeCalendar(GenericValue workEffort) throws GenericEntityException {
+ net.fortuna.ical4j.model.Calendar calendar = new net.fortuna.ical4j.model.Calendar();
+ PropertyList propList = calendar.getProperties();
+ propList.add(prodId);
+ propList.add(Version.VERSION_2_0);
+ propList.add(CalScale.GREGORIAN);
+ if (workEffort.get("description") != null) {
+ propList.add(new Description(workEffort.getString("description")));
+ } else {
+ propList.add(new Description(workEffort.getString("workEffortName")));
+ }
+ // 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;
+ }
+}
Propchange: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalendarWorker.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalendarWorker.java
------------------------------------------------------------------------------
svn:keywords = "Date Rev Author URL Id"
Propchange: ofbiz/trunk/applications/workeffort/src/org/ofbiz/workeffort/workeffort/ICalendarWorker.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: ofbiz/trunk/applications/workeffort/webapp/ical/WEB-INF/web.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/workeffort/webapp/ical/WEB-INF/web.xml?rev=718684&view=auto
==============================================================================
--- ofbiz/trunk/applications/workeffort/webapp/ical/WEB-INF/web.xml (added)
+++ ofbiz/trunk/applications/workeffort/webapp/ical/WEB-INF/web.xml Tue Nov 18 10:56:11 2008
@@ -0,0 +1,98 @@
+<?xml version="1.0"?>
+<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
+
+<!--
+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.
+-->
+
+<web-app>
+ <display-name>Open For Business - iCalendar Server</display-name>
+ <description>iCalendar Server Module of the Open For Business Project</description>
+
+ <context-param>
+ <param-name>entityDelegatorName</param-name>
+ <param-value>default</param-value>
+ <description>The Name of the Entity Delegator to use, defined in entityengine.xml</description>
+ </context-param>
+ <context-param>
+ <param-name>localDispatcherName</param-name>
+ <param-value>ical</param-value>
+ <description>A unique name used to identify/recognize the local dispatcher for the Service Engine</description>
+ </context-param>
+ <context-param>
+ <param-name>serviceReaderUrls</param-name>
+ <param-value>/WEB-INF/services.xml</param-value>
+ <description>Configuration File(s) For The Service Dispatcher</description>
+ </context-param>
+ <context-param>
+ <param-name>scriptLocationPath</param-name>
+ <param-value>/WEB-INF/bsh</param-value>
+ <description>BeanShell Script Location</description>
+ </context-param>
+
+ <filter>
+ <filter-name>ContextFilter</filter-name>
+ <display-name>ContextFilter</display-name>
+ <filter-class>org.ofbiz.webapp.control.ContextFilter</filter-class>
+ <init-param>
+ <param-name>disableContextSecurity</param-name>
+ <param-value>N</param-value>
+ </init-param>
+ <init-param>
+ <param-name>allowedPaths</param-name>
+ <param-value>/control:/select:/index.html:/index.jsp:/default.html:/default.jsp:/images:/includes/maincss.css</param-value>
+ </init-param>
+ <init-param>
+ <param-name>errorCode</param-name>
+ <param-value>403</param-value>
+ </init-param>
+ <init-param>
+ <param-name>redirectPath</param-name>
+ <param-value>/control/main</param-value>
+ </init-param>
+ </filter>
+ <filter-mapping>
+ <filter-name>ContextFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+
+ <listener><listener-class>org.ofbiz.webapp.control.ControlEventListener</listener-class></listener>
+ <listener><listener-class>org.ofbiz.webapp.control.LoginEventListener</listener-class></listener>
+ <!-- NOTE: not all app servers support mounting implementations of the HttpSessionActivationListener interface -->
+ <!-- <listener><listener-class>org.ofbiz.webapp.control.ControlActivationEventListener</listener-class></listener> -->
+
+ <servlet>
+ <servlet-name>iCalendarServlet</servlet-name>
+ <display-name>iCalendarServlet</display-name>
+ <description>Main Control Servlet</description>
+ <servlet-class>org.ofbiz.workeffort.workeffort.ICalServlet</servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>iCalendarServlet</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+
+ <session-config>
+ <session-timeout>60</session-timeout> <!-- in minutes -->
+ </session-config>
+
+ <welcome-file-list>
+ <welcome-file>index.jsp</welcome-file>
+ </welcome-file-list>
+</web-app>
Propchange: ofbiz/trunk/applications/workeffort/webapp/ical/WEB-INF/web.xml
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: ofbiz/trunk/applications/workeffort/webapp/ical/WEB-INF/web.xml
------------------------------------------------------------------------------
svn:keywords = "Date Rev Author URL Id"
Propchange: ofbiz/trunk/applications/workeffort/webapp/ical/WEB-INF/web.xml
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: ofbiz/trunk/framework/base/lib/ical4j-1.0-beta5.jar
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/lib/ical4j-1.0-beta5.jar?rev=718684&view=auto
==============================================================================
Binary file - no diff available.
Propchange: ofbiz/trunk/framework/base/lib/ical4j-1.0-beta5.jar
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Modified: ofbiz/trunk/specialpurpose/projectmgr/data/ProjectMgrDemoData.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/projectmgr/data/ProjectMgrDemoData.xml?rev=718684&r1=718683&r2=718684&view=diff
==============================================================================
--- ofbiz/trunk/specialpurpose/projectmgr/data/ProjectMgrDemoData.xml (original)
+++ ofbiz/trunk/specialpurpose/projectmgr/data/ProjectMgrDemoData.xml Tue Nov 18 10:56:11 2008
@@ -158,4 +158,8 @@
<WorkEffortPartyAssignment workEffortId="STAFF_MTG" partyId="DemoEmployee2" statusId="PRTYASGN_ASSIGNED" roleTypeId="CAL_ATTENDEE" availabilityStatusId="WEPA_AV_BUSY" fromDate="2008-01-01 00:00:00.0"/>
<WorkEffortPartyAssignment workEffortId="STAFF_MTG" partyId="DemoEmployee3" statusId="PRTYASGN_ASSIGNED" roleTypeId="CAL_ATTENDEE" availabilityStatusId="WEPA_AV_BUSY" fromDate="2008-01-01 00:00:00.0"/>
+ <!-- Publish the staff meeting calendar event -->
+ <WorkEffort workEffortId="CALENDAR_PUB_DEMO" workEffortTypeId="PUBLISH_PROPS" currentStatusId="CAL_CANCELLED" scopeEnumId="WES_PUBLIC" description="Demo Project 1 Customer 1" workEffortName="iCalendar Publish Demonstration"/>
+ <WorkEffortAssoc workEffortIdFrom="CALENDAR_PUB_DEMO" workEffortIdTo="STAFF_MTG" workEffortAssocTypeId="WORK_EFF_DEPENDENCY" fromDate="2008-01-01 00:00:00.0"/>
+
</entity-engine-xml>