/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/calendar/trunk/calendar-impl/impl/src/java/org/sakaiproject/calendar/impl/readers/Reader.java $ * $Id: Reader.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.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import org.sakaiproject.exception.ImportException; import org.sakaiproject.time.api.TimeService; /** * This class provides common functionality for parsers of various * calendar import formats. */ public abstract class Reader { protected Map columnHeaderMap; protected TimeService timeService; /** * Contains header information such as the text label used for the * header and the calendar event property with which it is associated. **/ public class ColumnHeader { private String columnProperty; private String columnHeader; /** * Default constructor */ public ColumnHeader() { super(); } /** * Construct a ColumnHeader with a specified text label used in the import * file and the Calendar Event property that is associated with it. * @param columnHeader * @param columnProperty */ public ColumnHeader(String columnHeader, String columnProperty) { this.columnHeader = columnHeader; this.columnProperty = columnProperty; } /** * Gets the column header as it appears in the import file. */ public String getColumnHeader() { return columnHeader; } /** * Gets the calendar event property name associated with this header. */ public String getColumnProperty() { return columnProperty; } } /** * Default Constructor */ public Reader() { super(); // Use whatever the default column mapping. this.setColumnHeaderToAtributeMapping(this.getDefaultColumnMap()); } /** * This class contains the information for a single cell in a given row/column. */ static public class ReaderImportCell { private String columnHeader; private String value; private int lineNumber; private int column; private String propertyName; /** * @param row * @param column * @param value * @param propertyName * @param columnHeader */ ReaderImportCell( int row, int column, String value, String propertyName, String columnHeader) { super(); this.lineNumber = row; this.column = column; this.value = value; this.propertyName = propertyName; this.columnHeader = columnHeader; } /** * Gets the calendar event property name associated with this header. */ public String getPropertyName() { return propertyName; } /** * Gets the zero-based column number. */ public int getColumnNumber() { return column; } /** * Gets the one-based row number. */ public int getLineNumber() { return lineNumber; } /** * Gets the value of the cell as a string. No type conversion is performed, * this is just the string read in from the stream. */ public String getCellValue() { return value; } /** * Gets the text header used in the import file for this column. */ public String getColumnHeader() { return columnHeader; } } /** * Users of this class need to define a callback that will be handled for * each row. */ public interface ReaderImportRowHandler { /** * This is the callback that is called for each row. * @param columnIterator Iterator for a collection of CSVReaderImportCell for this row. */ void handleRow(Iterator columnIterator) throws ImportException; } /** * Create meta-information from the first line of the "file" (actually stream) * that contains the names of the columns. * @param columns */ protected ColumnHeader[] buildColumnDescriptionArray(String[] columns) { ColumnHeader[] columnDescriptionArray; columnDescriptionArray = new ColumnHeader[columns.length]; for (int i = 0; i < columns.length; i++) { columnDescriptionArray[i] = new ColumnHeader( columns[i], (String) columnHeaderMap.get(columns[i])); } return columnDescriptionArray; } /** * Remove leading/trailing quotes * @param columnsReadFromFile */ protected void trimLeadingTrailingQuotes(String[] columnsReadFromFile) { for (int i = 0; i < columnsReadFromFile.length; i++) { String regex2 = "(?:\")*([^\"]+)(?:\")*"; columnsReadFromFile[i] = columnsReadFromFile[i].trim().replaceAll(regex2, "$1"); } } /** * Users of this class must define a map where the keys are the column headers * that will appear in the first line of the CSV file (stream) and the values * are the associated property names that the callback will receive. * @param columnList */ public void setColumnHeaderToAtributeMapping(Map columnHeaderMap) { this.columnHeaderMap = columnHeaderMap; } /** * Split a line into a list of CSVReaderImportCell objects. * @param columnDescriptionArray * @param lineNumber * @param columns */ protected Iterator processLine( ColumnHeader[] columnDescriptionArray, int lineNumber, String[] columns) { List list = new ArrayList(); for (int i = 0; i < columns.length; i++) { if ( i >= columnDescriptionArray.length ) { continue; } else { list.add( new ReaderImportCell( lineNumber, i, columns[i], columnDescriptionArray[i].getColumnProperty(), columnDescriptionArray[i].getColumnHeader())); } } return list.iterator(); } /** * Utility routine to get a BufferedReader * @param stream */ protected BufferedReader getReader(InputStream stream) { InputStreamReader inStreamReader = new InputStreamReader(stream); BufferedReader bufferedReader = new BufferedReader(inStreamReader); return bufferedReader; } /** * Import a CSV file from a stream and callback on each row. * @param stream Stream of CSV (or other delimited data) * @param handler Callback for each row. */ abstract public void importStreamFromDelimitedFile( InputStream stream, ReaderImportRowHandler handler) throws ImportException; /** * Gets the mapping of text column header labels in the import file to * calendar event properties. */ public Map getColumnHeaderMap() { return columnHeaderMap; } /** * Each derived class must implement this filter to convert the properties as set by the * reader into a common set of properties that will be used to create calendar events. * Notably, this filter must create a ScheduleImporterService.ACTUAL_TIMERANGE property * that will define the actual start time/date of the event. * @param importStream * @param customFieldNames * @throws ImportException */ abstract public List filterEvents(List events, String[] customFieldNames) throws ImportException; /** * Derived classes must provide a default mapping of text column header labels in the import file to * calendar event properties. * @throws ImportException */ abstract public Map getDefaultColumnMap(); /** */ public TimeService getTimeService() { return timeService; } /** * @param service */ public void setTimeService(TimeService service) { timeService = service; } }