/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* 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 the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>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.jasig.portlet.calendar.adapter;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;
import javax.portlet.PortletRequest;
import javax.portlet.PortletSession;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import net.fortuna.ical4j.model.Component;
import net.fortuna.ical4j.model.Date;
import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.Period;
import net.fortuna.ical4j.model.PeriodList;
import net.fortuna.ical4j.model.Property;
import net.fortuna.ical4j.model.PropertyList;
import net.fortuna.ical4j.model.component.VEvent;
import net.fortuna.ical4j.model.property.CalScale;
import net.fortuna.ical4j.model.property.DtEnd;
import net.fortuna.ical4j.model.property.DtStart;
import net.fortuna.ical4j.model.property.Duration;
import net.fortuna.ical4j.model.property.Location;
import net.fortuna.ical4j.model.property.ProdId;
import net.fortuna.ical4j.model.property.RRule;
import net.fortuna.ical4j.model.property.Version;
import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;
import oracle.calendar.soap.client.CalendarUtils;
import oracle.calendar.soap.client.CalendaringResponse;
import oracle.calendar.soap.client.Calendarlet;
import oracle.calendar.soap.client.Reply;
import oracle.calendar.soap.client.SearchCommand;
import oracle.calendar.soap.client.authentication.BasicAuth;
import oracle.calendar.soap.client.query.vQuery;
import oracle.calendar.soap.iCal.iCalendar;
import oracle.calendar.soap.iCal.vCalendar;
import oracle.calendar.soap.iCal.vEvent;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.portlet.calendar.CalendarConfiguration;
import org.jasig.portlet.calendar.CalendarEvent;
/**
* OracleICalAdapter is a CalendarAdapter for Oracle Calendar. This adapter uses the Calendar Web
* Services Toolkit, See Chapter 9 of Oracle Calendar Application Developer's Guide
* (http://download-uk.oracle.com/docs/cd/B15595_01/calendar.101/b14477/adws_overview.htm)
*
* <p>Note: This class uses the BasicAuth method of logging in. Therefore the users credentials must
* be available from the Portal and mapped via portlet.xml
*
* @author Anthony Colebourne
*/
public class OracleICalAdapter implements ICalendarAdapter {
private static Log log = LogFactory.getLog(OracleICalAdapter.class);
public Set<CalendarEvent> getEvents(
CalendarConfiguration calendar, Period period, HttpServletRequest request)
throws CalendarException {
// get the session
HttpSession session = request.getSession(false);
if (session == null) {
log.warn("OracleICalAdapter requested with a null session");
throw new CalendarException();
}
String username = (String) session.getAttribute("subscribeId");
if (username == null) {
log.error("OracleICalAdapter cannot find the subscribeId");
throw new CalendarException();
}
String password = (String) session.getAttribute("password");
if (password == null) {
log.error(
"OracleICalAdapter cannot find the users password, try configuring the CachedCredentialsInitializationService");
throw new CalendarException();
}
return getEvents(calendar, period, username, password);
}
public Set<CalendarEvent> getEvents(
CalendarConfiguration calendar, Period period, PortletRequest request)
throws CalendarException {
// get the session
PortletSession session = request.getPortletSession(false);
if (session == null) {
log.warn("OracleICalAdapter requested with a null session");
throw new CalendarException();
}
String username = (String) session.getAttribute("subscribeId");
if (username == null) {
log.error("OracleICalAdapter cannot find the subscribeId");
throw new CalendarException();
}
String password = (String) session.getAttribute("password");
if (password == null) {
log.error(
"OracleICalAdapter cannot find the users password, try configuring the CachedCredentialsInitializationService");
throw new CalendarException();
}
return getEvents(calendar, period, username, password);
}
/*
* (non-Javadoc)
* @see org.jasig.portlet.calendar.CalendarAdapter#getEvents(org.jasig.portlet.calendar.CalendarDefinition, net.fortuna.ical4j.model.Period, java.util.Map)
*/
public Set<CalendarEvent> getEvents(
CalendarConfiguration calendarConfig, Period period, String username, String password)
throws CalendarException {
net.fortuna.ical4j.model.Calendar calendar = null;
// get the URL for this calendar
String url = (String) calendarConfig.getCalendarDefinition().getParameters().get("url");
// try to get the cached calendar
String key = getCacheKey(url, username, period);
Element cachedElement = cache.get(key);
if (cachedElement == null) {
// read in the calendar
calendar = getCalendar(url, username, password, period);
// save the calendar to the cache
cachedElement = new Element(key, calendar);
cache.put(cachedElement);
} else {
calendar = (net.fortuna.ical4j.model.Calendar) cachedElement.getValue();
}
// return the event list
return getEvents(calendarConfig.getId(), calendar, period);
}
/**
* Retrieve calendar data from Oracle and use it to build an iCal4j Calendar object.
*
* @param url URL of the calendar to be retrieved
* @param username Username to use to login to Oracle Calendar using Oracle's BasicAuth
* @param password Password to use to login to Oracle Calendar using Oracle's BasicAuth
* @return ical4j Calendar object
*/
protected net.fortuna.ical4j.model.Calendar getCalendar(
String url, String username, String password, Period period) throws CalendarException {
// initialize the authentication information and set the user id
BasicAuth auth = new BasicAuth();
auth.setName(username);
auth.setPassword(password);
// initialize the event search command and query
SearchCommand search = new SearchCommand();
search.setCmdId("uPortal");
// create a query to retrieve unconfirmed events
vQuery query = new vQuery();
query.setFrom(vQuery.k_queryFromEvent);
// query.setFrom(vQuery.k_queryFromTodo);
//java.util.Calendar today = CalendarUtils.getToday();
//java.util.Calendar begin = (java.util.Calendar) today.clone();
Calendar beginPeriod = Calendar.getInstance();
beginPeriod.setTime(period.getStart());
beginPeriod.set(Calendar.HOUR_OF_DAY, 0);
beginPeriod.set(Calendar.MINUTE, 0);
beginPeriod.set(Calendar.SECOND, 0);
beginPeriod.set(Calendar.MILLISECOND, 0);
Calendar endPeriod = Calendar.getInstance();
endPeriod.setTime(period.getEnd());
endPeriod.set(Calendar.HOUR_OF_DAY, 0);
endPeriod.set(Calendar.MINUTE, 0);
endPeriod.set(Calendar.SECOND, 0);
endPeriod.set(Calendar.MILLISECOND, 0);
query.setWhere(CalendarUtils.getDateRangeQuery(beginPeriod, endPeriod));
search.setQuery(query);
// create the calendar client SOAP stub
// and set the basic authentication header
Calendarlet cws = new Calendarlet();
// set the Web Services host URL
cws.setEndPointURL(url);
cws.setAuthenticationHeader(auth.getElement());
cws.setWantIOBuffers(log.isDebugEnabled());
cws.setWantIOBuffers(true);
// make the SOAP call
try {
CalendaringResponse response = cws.Search(search.getElement());
if (log.isDebugEnabled()) {
log.debug(response.getSendBuffer());
log.debug("\n-----------------------------");
log.debug(response.getReceiveBuffer());
}
// get the SOAP reply
Reply reply = (Reply) response.getCalendarReply();
if (reply == null) {
throw new CalendarException("Response could not be parsed");
}
net.fortuna.ical4j.model.Calendar iCal4j = new net.fortuna.ical4j.model.Calendar();
iCal4j.getProperties().add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN"));
iCal4j.getProperties().add(Version.VERSION_2_0);
iCal4j.getProperties().add(CalScale.GREGORIAN);
// traverse all the iCalendar objects
Vector entries = reply.getEntries();
Vector someiCalendars = iCalendar.unmarshallVector(entries);
int numiCalendars = someiCalendars.size();
log.debug(numiCalendars + " iCalendar entries found.");
for (int i = 0; i < numiCalendars; i++) {
iCalendar iCalObj = (iCalendar) someiCalendars.get(i);
Vector somevCalendars = iCalObj.getvCalendars();
int numvCalendars = somevCalendars.size();
log.debug(numvCalendars + " vCalendar entries found.");
for (int ii = 0; ii < numvCalendars; ii++) {
vCalendar vCalObj = (vCalendar) somevCalendars.get(ii);
Vector somevEvents = vCalObj.getComponents();
int numvEvents = somevEvents.size();
log.debug(numvEvents + " vEvents entries found.");
for (int iii = 0; iii < numvEvents; iii++) {
try {
vEvent vEventObj = (vEvent) somevEvents.get(iii);
log.debug("vEvents is " + vEventObj.getSummary());
log.debug("vEvents DT start " + vEventObj.getDtStart());
log.debug("vEvents DT end " + vEventObj.getDtEnd());
if (vEventObj.getXEventType().equals(vEvent.k_eventTypeDayEvent)) {
DateFormat parser = new SimpleDateFormat("yyyyMMdd");
Calendar endEvent = Calendar.getInstance();
endEvent.setTime(parser.parse(vEventObj.getDtStart()));
endEvent.roll(Calendar.DATE, true);
VEvent iCal4jEvent =
new VEvent(
new Date(vEventObj.getDtStart()),
new Date(endEvent.getTime()),
vEventObj.getSummary());
iCal4jEvent.getProperties().add(new Location(vEventObj.getLocation()));
iCal4j.getComponents().add(iCal4jEvent);
} else {
VEvent iCal4jEvent =
new VEvent(
new DateTime(vEventObj.getDtStart()),
new DateTime(vEventObj.getDtEnd()),
vEventObj.getSummary());
iCal4jEvent.getProperties().add(new Location(vEventObj.getLocation()));
iCal4j.getComponents().add(iCal4jEvent);
}
} catch (ParseException parseException) {
log.error("Problem parsing DateTime");
}
}
}
}
return iCal4j;
} catch (Exception ex) {
log.error("SOAP call failed", ex);
throw new CalendarException("SOAP call failed");
}
}
/**
* Extract a list of events from an iCal4j Calendar for a specified time period.
*
* @param calendarId id of the CalendarConfiguration
* @param calendar ical4j calendar object
* @param period time period to retrieve events for
* @return Set of calendar events
*/
protected Set<CalendarEvent> getEvents(
Long calendarId, net.fortuna.ical4j.model.Calendar calendar, Period period)
throws CalendarException {
Set<CalendarEvent> events = new HashSet<CalendarEvent>();
// if the calendar is null, throw an error
if (calendar == null) throw new CalendarException();
// retrieve the list of events for this calendar within the
// specified time period
for (Iterator<Component> i = calendar.getComponents().iterator(); i.hasNext(); ) {
Component component = i.next();
if (component.getName().equals("VEVENT")) {
VEvent event = (VEvent) component;
// calculate the recurrence set for this event
// for the specified time period
PeriodList periods = event.calculateRecurrenceSet(period);
// add each recurrence instance to the event list
for (Iterator<Period> iter = periods.iterator(); iter.hasNext(); ) {
Period eventper = iter.next();
PropertyList props = event.getProperties();
// create a new property list, setting the date
// information to this event period
PropertyList newprops = new PropertyList();
newprops.add(new DtStart(eventper.getStart()));
newprops.add(new DtEnd(eventper.getEnd()));
for (Iterator<Property> iter2 = props.iterator(); iter2.hasNext(); ) {
Property prop = iter2.next();
// only add non-date-related properties
if (!(prop instanceof DtStart)
&& !(prop instanceof DtEnd)
&& !(prop instanceof Duration)
&& !(prop instanceof RRule)) newprops.add(prop);
}
// create the new event from our property list
CalendarEvent newevent = new CalendarEvent(calendarId, newprops);
events.add(newevent);
}
}
}
return events;
}
/**
* Get a cache key for this calendar request.
*
* @param url URL of this calendar
* @param netid login id of the requesting user
* @return String representing this request
*/
private String getCacheKey(String url, String username, Period period) {
StringBuffer key = new StringBuffer();
// Unique to this class
key.append("OracleiCal.");
// Unique to the back end data source identified by url
key.append(url);
key.append(".");
// Unique to this user identified by username
key.append("username:");
key.append(username);
key.append(".");
// Unique to the time period identified hash code
key.append("period:");
key.append(period.hashCode());
return key.toString();
}
private Cache cache;
public void setCache(Cache cache) {
this.cache = cache;
}
}
/*
* OracleICalAdapter.java
*
* Copyright (c) Feb 13, 2008 The University of Manchester. All rights reserved.
*
* THIS SOFTWARE IS PROVIDED "AS IS," AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE, ARE EXPRESSLY DISCLAIMED. IN NO EVENT SHALL
* MANCHESTER UNIVERSITY OR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED, THE COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Redistribution and use of this software in source or binary forms, with or
* without modification, are permitted, provided that the following conditions
* are met.
*
* 1. Any redistribution must include the above copyright notice and disclaimer
* and this list of conditions in any related documentation and, if feasible, in
* the redistributed software.
*
* 2. Any redistribution must include the acknowledgment, "This product includes
* software developed by The University of Manchester," in any related documentation and, if
* feasible, in the redistributed software.
*
* 3. The names "The University of Manchester" and "Manchester University" must not be used to endorse or
* promote products derived from this software.
*/