/* ********************************************************************
Licensed to Jasig under one or more contributor license
agreements. See the NOTICE file distributed with this work
for additional information regarding copyright ownership.
Jasig 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.bedework.calsvc.scheduling;
import org.bedework.calfacade.BwCalendar;
import org.bedework.calfacade.BwEvent;
import org.bedework.calfacade.RecurringRetrievalMode;
import org.bedework.calfacade.exc.CalFacadeException;
import org.bedework.calfacade.svc.EventInfo;
import org.bedework.calsvc.CalSvc;
import org.bedework.util.calendar.IcalDefs;
import org.bedework.util.misc.Util;
import java.util.Collection;
/** Rather than have a single class steering calls to a number of smaller classes
* we will build up a full implementation by progressively implementing abstract
* classes.
*
* <p>That allows us to split up some rather complex code into appropriate pieces.
*
* <p>This piece handles a few general methods. Work down the chain of extends
* (or look in the package) to find the other parts of the story.
*
* @author Mike Douglass
*
*/
public class Scheduling extends ImplicitSchedulingHandler {
/** Constructor
*
* @param svci
*/
public Scheduling(final CalSvc svci) {
super(svci);
}
/* (non-Javadoc)
* @see org.bedework.calsvci.SchedulingI#getStoredMeeting(org.bedework.calfacade.BwEvent)
*/
@Override
public EventInfo getStoredMeeting(final BwEvent ev) throws CalFacadeException {
String preferred = getSvc().getCalendarsHandler().
getPreferred(IcalDefs.entityTypeIcalNames[ev.getEntityType()]);
if (preferred == null) {
throw new CalFacadeException(CalFacadeException.schedulingNoCalendar);
}
Collection<EventInfo> evs = getSvc().getEventsHandler().
getByUid(preferred,
ev.getUid(),
null,
RecurringRetrievalMode.overrides);
if (Util.isEmpty(evs)) {
return null;
}
/* Return the active meeting */
for (EventInfo ei: evs) {
BwEvent e = ei.getEvent();
// Skip anything other than a calendar collection
BwCalendar evcal = getSvc().getCalendarsHandler().get(e.getColPath());
if (!evcal.getCollectionInfo().scheduling) {
continue;
}
if (e.getOrganizerSchedulingObject() || e.getAttendeeSchedulingObject()) {
return ei;
}
if (e.getSuppressed()) {
// See if the overrrides are scheduling objects
for (BwEvent oe: ei.getOverrideProxies()) {
if (oe.getOrganizerSchedulingObject() ||
oe.getAttendeeSchedulingObject()) {
return ei;
}
}
}
}
// Not found.
return null;
}
/*
* 2.1.5 Message Sequencing
CUAs that handle the [iTIP] application protocol must often correlate
a component in a calendar store with a component received in the
[iTIP] message. For example, an event may be updated with a later
revision of the same event. To accomplish this, a CUA must correlate
the version of the event already in its calendar store with the
version sent in the [iTIP] message. In addition to this correlation,
there are several factors that can cause [iTIP] messages to arrive in
an unexpected order. That is, an "Organizer" could receive a reply
to an earlier revision of a component AFTER receiving a reply to a
later revision.
To maximize interoperability and to handle messages that arrive in an
unexpected order, use the following rules:
1. The primary key for referencing a particular iCalendar component
is the "UID" property value. To reference an instance of a
recurring component, the primary key is composed of the "UID" and
the "RECURRENCE-ID" properties.
2. The secondary key for referencing a component is the "SEQUENCE"
property value. For components where the "UID" is the same, the
component with the highest numeric value for the "SEQUENCE"
property obsoletes all other revisions of the component with
lower values.
3. "Attendees" send "REPLY" messages to the "Organizer". For
replies where the "UID" property value is the same, the value of
the "SEQUENCE" property indicates the revision of the component
to which the "Attendee" is replying. The reply with the highest
numeric value for the "SEQUENCE" property obsoletes all other
replies with lower values.
4. In situations where the "UID" and "SEQUENCE" properties match,
the "DTSTAMP" property is used as the tie-breaker. The component
with the latest "DTSTAMP" overrides all others. Similarly, for
"Attendee" responses where the "UID" property values match and
the "SEQUENCE" property values match, the response with the
latest "DTSTAMP" overrides all others.
We compare two events for order according to the above rules. We retrieved
the second event from the outbox or inbox using the uid so we know the uids
match.
return 0 for equal.
-1 for event 1 < event 2
1 for event 1 > event 2
* /
private int checkSequence(BwEvent ev1, BwEvent ev2) {
int seq1 = ev1.getSequence();
int seq2 = ev2.getSequence();
if (seq1 < seq2) {
return -1;
}
if (seq1 > seq2) {
return 1;
}
String dtstamp1 = ev1.getDtstamp();
String dtstamp2 = ev2.getDtstamp();
return CalFacadeUtil.compareStrings(dtstamp1, dtstamp2);
}*/
}