/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/calendar/trunk/calendar-impl/impl/src/java/org/sakaiproject/calendar/impl/readers/MeetingMakerReader.java $
* $Id: MeetingMakerReader.java 105079 2012-02-24 23:08:11Z ottenhoff@longsight.com $
***********************************************************************************
*
* Copyright (c) 2003, 2004, 2005, 2006, 2008 The Sakai Foundation
*
* Licensed under the Educational Community 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.opensource.org/licenses/ECL-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.sakaiproject.calendar.impl.readers;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.sakaiproject.calendar.impl.GenericCalendarImporter;
import org.sakaiproject.exception.ImportException;
import org.sakaiproject.time.api.TimeBreakdown;
import org.sakaiproject.util.ResourceLoader;
/**
* This class parses an import file from MeetingMaker.
*/
public class MeetingMakerReader extends Reader
{
private ResourceLoader rb = new ResourceLoader("calendar");
private static final String CONTACT_SECTION_HEADER = "Contacts";
private static final String TODO_SECTION_HEADER = "Todos";
private static final String EVENT_SECTION_HEADER = "Events";
public static final String TITLE_HEADER = "Title";
public static final String LOCATION_HEADER = "Location";
public static final String DATE_HEADER = "Date";
public static final String START_TIME_HEADER = "Start Time";
public static final String DURATION_HEADER = "Duration";
public static final String AGENDA_NOTES_HEADER = "Agenda/Notes";
/**
* Default constructor
*/
public MeetingMakerReader()
{
super();
}
/* (non-Javadoc)
* @see org.sakaiproject.tool.calendar.ImportReader#importStreamFromDelimitedFile(java.io.InputStream, org.sakaiproject.tool.calendar.ImportReader.ReaderImportRowHandler)
*/
public void importStreamFromDelimitedFile(
InputStream stream,
ReaderImportRowHandler handler)
throws ImportException
{
boolean inEventSection = false;
boolean alreadySawEventSection = false;
BufferedReader bufferedReader = getReader(stream);
ColumnHeader columnDescriptionArray[] = null;
int lineNumber = 1;
boolean readDone = false;
while (!readDone)
{
try
{
// Prepare the column map on the first line.
String lineBuffer = bufferedReader.readLine();
// See if we have exhausted the input
if (lineBuffer == null)
{
break;
}
// See if we're in the "Event" section of the import file.
if (EVENT_SECTION_HEADER.equals(lineBuffer.trim()))
{
inEventSection = true;
alreadySawEventSection = true;
lineNumber++;
continue;
}
else
if (TODO_SECTION_HEADER.equals(lineBuffer.trim()))
{
inEventSection = false;
lineNumber++;
continue;
}
else
if (CONTACT_SECTION_HEADER.equals(lineBuffer.trim()))
{
inEventSection = false;
lineNumber++;
continue;
}
else
if ( lineBuffer.toString().startsWith("Time Zone:") )
{
// Ignore the timezone line.
lineNumber++;
continue;
}
// If we leave the event section and see another non-event section header,
// then stop reading the stream since there is only one event section.
if (alreadySawEventSection && !inEventSection)
{
readDone = true;
continue;
}
if (inEventSection)
{
if (columnDescriptionArray == null)
{
String[] columns = lineBuffer.split("\t");
trimLeadingTrailingQuotes(columns);
columnDescriptionArray =
buildColumnDescriptionArray(columns);
// Immediately start the next loop.
lineNumber++;
continue;
}
else
{
// Empty lines are preserved at some points, like in quoted string
// descriptions, but at this point, just skip over them.
if (lineBuffer.trim().length() == 0 )
{
lineNumber++;
continue;
}
String[] columns = lineBuffer.split("\t");
// If the last column starts with a double-quote, then keep
// concatentating lines until we see a line that ends
// with double-quotes.
String endingColumnValue = columns[columns.length - 1].trim();
if (endingColumnValue.startsWith("\"")
&& (!endingColumnValue.endsWith("\"")
|| endingColumnValue.length() == 1))
{
String continuationLineBuffer =
bufferedReader.readLine();
// See if we have exhausted the input
while ( continuationLineBuffer != null )
{
columns[columns.length - 1] =
columns[columns.length
- 1]
+ "\n"
+ continuationLineBuffer;
// Break out when we hit the end of the quoted string.
if ( continuationLineBuffer.trim().endsWith("\"") )
{
break;
}
continuationLineBuffer = bufferedReader.readLine();
}
}
// Remove trailing/leading quotes from all columns.
trimLeadingTrailingQuotes(columns);
handler.handleRow(
processLine(
columnDescriptionArray,
lineNumber,
columns));
}
}
}
catch (IOException e)
{
// We'll get an exception when we've exhauster
readDone = true;
}
// If we get this far, increment the line counter.
lineNumber++;
}
}
/* (non-Javadoc)
* @see org.sakaiproject.tool.calendar.schedimportreaders.Reader#filterEvents(java.util.List, java.lang.String[])
*/
public List filterEvents(List events, String[] customFieldNames) throws ImportException
{
Iterator it = events.iterator();
int lineNumber = 1;
//
// Convert the date/time fields as they appear in the Outlook import to
// be a synthesized start/end timerange.
//
while ( it.hasNext() )
{
Map eventProperties = (Map)it.next();
Date startTime = (Date) eventProperties.get(GenericCalendarImporter.START_TIME_PROPERTY_NAME);
TimeBreakdown startTimeBreakdown = null;
if ( startTime != null )
{
// if the source time zone were known, this would be
// a good place to set it: startCal.setTimeZone()
GregorianCalendar startCal = new GregorianCalendar();
startCal.setTimeInMillis( startTime.getTime() );
startTimeBreakdown =
getTimeService().newTimeBreakdown( 0, 0, 0,
startCal.get(Calendar.HOUR_OF_DAY),
startCal.get(Calendar.MINUTE),
startCal.get(Calendar.SECOND),
0 );
}
else
{
Integer line = Integer.valueOf(lineNumber);
String msg = (String)rb.getFormattedMessage("err_no_stime_on",
new Object[]{line});
throw new ImportException( msg );
}
Integer durationInMinutes = (Integer)eventProperties.get(GenericCalendarImporter.DURATION_PROPERTY_NAME);
if ( durationInMinutes == null )
{
Integer line = Integer.valueOf(lineNumber);
String msg = (String)rb.getFormattedMessage("err_no_dtime_on",
new Object[]{line});
throw new ImportException( msg );
}
Date endTime =
new Date(
startTime.getTime() + (durationInMinutes.longValue() * 60 * 1000) );
TimeBreakdown endTimeBreakdown = null;
if ( endTime != null )
{
// if the source time zone were known, this would be
// a good place to set it: endCal.setTimeZone()
GregorianCalendar endCal = new GregorianCalendar();
endCal.setTimeInMillis( endTime.getTime() );
endTimeBreakdown =
getTimeService().newTimeBreakdown( 0, 0, 0,
endCal.get(Calendar.HOUR_OF_DAY),
endCal.get(Calendar.MINUTE),
endCal.get(Calendar.SECOND),
0 );
}
Date startDate = (Date) eventProperties.get(GenericCalendarImporter.DATE_PROPERTY_NAME);
// if the source time zone were known, this would be
// a good place to set it: startCal.setTimeZone()
GregorianCalendar startCal = new GregorianCalendar();
if ( startDate != null )
startCal.setTimeInMillis( startDate.getTime() );
startTimeBreakdown.setYear( startCal.get(Calendar.YEAR) );
startTimeBreakdown.setMonth( startCal.get(Calendar.MONTH)+1 );
startTimeBreakdown.setDay( startCal.get(Calendar.DAY_OF_MONTH) );
endTimeBreakdown.setYear( startCal.get(Calendar.YEAR) );
endTimeBreakdown.setMonth( startCal.get(Calendar.MONTH)+1 );
endTimeBreakdown.setDay( startCal.get(Calendar.DAY_OF_MONTH) );
eventProperties.put(
GenericCalendarImporter.ACTUAL_TIMERANGE,
getTimeService().newTimeRange(
getTimeService().newTimeLocal(startTimeBreakdown),
getTimeService().newTimeLocal(endTimeBreakdown),
true,
false));
lineNumber++;
}
return events;
}
/* (non-Javadoc)
* @see org.sakaiproject.tool.calendar.schedimportreaders.Reader#getDefaultColumnMap()
*/
public Map getDefaultColumnMap()
{
Map columnHeaderMap = new HashMap();
columnHeaderMap.put(TITLE_HEADER, GenericCalendarImporter.TITLE_PROPERTY_NAME);
columnHeaderMap.put(AGENDA_NOTES_HEADER, GenericCalendarImporter.DESCRIPTION_PROPERTY_NAME);
columnHeaderMap.put(DATE_HEADER, GenericCalendarImporter.DATE_PROPERTY_NAME);
columnHeaderMap.put(START_TIME_HEADER, GenericCalendarImporter.START_TIME_PROPERTY_NAME);
columnHeaderMap.put(DURATION_HEADER, GenericCalendarImporter.DURATION_PROPERTY_NAME);
columnHeaderMap.put(LOCATION_HEADER, GenericCalendarImporter.LOCATION_PROPERTY_NAME);
return columnHeaderMap;
}
}