/*
* Copyright 2012 Shared Learning Collaborative, LLC
*
* Licensed 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.slc.sli.sample.transform;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import org.slc.sli.sample.entities.Address;
import org.slc.sli.sample.entities.AddressType;
import org.slc.sli.sample.entities.BirthData;
import org.slc.sli.sample.entities.GenerationCodeSuffixType;
import org.slc.sli.sample.entities.InterchangeStudentParent;
import org.slc.sli.sample.entities.LanguageItemType;
import org.slc.sli.sample.entities.LanguagesType;
import org.slc.sli.sample.entities.Name;
import org.slc.sli.sample.entities.Parent;
import org.slc.sli.sample.entities.ParentIdentityType;
import org.slc.sli.sample.entities.ParentReferenceType;
import org.slc.sli.sample.entities.PersonalInformationVerificationType;
import org.slc.sli.sample.entities.PersonalTitlePrefixType;
import org.slc.sli.sample.entities.RaceItemType;
import org.slc.sli.sample.entities.RaceType;
import org.slc.sli.sample.entities.RelationType;
import org.slc.sli.sample.entities.SexType;
import org.slc.sli.sample.entities.StateAbbreviationType;
import org.slc.sli.sample.entities.Student;
import org.slc.sli.sample.entities.StudentIdentityType;
import org.slc.sli.sample.entities.StudentParentAssociation;
import org.slc.sli.sample.entities.StudentReferenceType;
/**
*
* This class converts CSV files into an Ed-Fi xml file.
* In this sample we have the following assumption for csv files:
* 1. The records in Student.csv, StudentAddress.csv and StudentLanguage.csv
* are sorted by StudentUSI in ascending order.
* 2. The references (e.g. StudentUSI and ParentUSI) in StudentParentAssociation.csv
* are correct and both exit in Student.csv and Parent.csv. This sample code does
* not check reference integrity check across csv files.
*
*/
public class CSV2XMLTransformer {
// CSV readers for student related files
private CSVReader studentReader;
private CSVReader studentAddressReader;
private CSVReader studentLanguageReader;
// CSV reader for parent related files
private CSVReader parentReader;
// CSV reader for studentParentAssociation files
private CSVReader studentParentAssociationReader;
// input csv files
private static final String studentFile = "data/Student.csv";
private static final String studentAddressFile = "data/StudentAddress.csv";
private static final String studentLanguagesFile = "data/StudentLanguage.csv";
private static final String parentFile = "data/Parent.csv";
private static final String studentParentAssociationFile = "data/StudentParentAssociation.csv";
// output Ed-Fi xml file
private static final String interchangeStudentParentFile = "data/InterchangeStudentParent.xml";
private static final String outputPath = "data/";
/**
* main method
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
CSV2XMLTransformer transformer = new CSV2XMLTransformer();
transformer.loadData();
PrintStream ps = new PrintStream(new File(interchangeStudentParentFile));
transformer.printInterchangeStudentParent(ps);
SchemaValidator.check(outputPath);
}
/**
* open csv files and create CSV reader for each file
* and load the first record for each reader
*
* @throws IOException
*/
private void loadData() throws IOException {
// load student data
studentReader = new CSVReader(studentFile);
studentAddressReader = new CSVReader(studentAddressFile);
studentLanguageReader = new CSVReader(studentLanguagesFile);
// load parent data
parentReader = new CSVReader(parentFile);
// load studentParentAssociation data
studentParentAssociationReader = new CSVReader(studentParentAssociationFile);
}
/**
* Iterate through Student, Parent, and studentParentAssociation records in the CSV files,
* converts them into JAXB java objects, and then marshals them into SLI-EdFi xml file.
*
* @param ps
* @throws JAXBException
*/
private void printInterchangeStudentParent(PrintStream ps) throws JAXBException {
int studentCounter = 0;
int parentCounter = 0;
int studentParentAssociationCounter = 0;
Marshaller marshaller = getMarshaller();
InterchangeStudentParent interchangeStudentParent = new InterchangeStudentParent();
List<Object> list = interchangeStudentParent.getStudentOrParentOrStudentParentAssociation();
// process student
while (studentReader.getCurrentRecord() != null) {
list.add(this.getStudent());
studentReader.getNextRecord();
studentCounter++;
}
// process parent
while (parentReader.getCurrentRecord() != null) {
list.add(this.getParent());
parentReader.getNextRecord();
parentCounter++;
}
// process studentParentAssociation
while (studentParentAssociationReader.getCurrentRecord() != null) {
list.add(this.getStudentParentAssociation());
studentParentAssociationReader.getNextRecord();
studentParentAssociationCounter++;
}
marshaller.marshal(interchangeStudentParent, ps);
System.out.println("Total " + studentCounter + " students are exported.");
System.out.println("Total " + parentCounter + " parents are exported.");
System.out.println("Total " + studentParentAssociationCounter
+ " student-parent-associations are exported.");
System.out.println("Total " + ( studentCounter + parentCounter + studentParentAssociationCounter)
+ " entities are exported.");
}
private Marshaller getMarshaller() throws JAXBException, PropertyException {
JAXBContext context = JAXBContext.newInstance(InterchangeStudentParent.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty("jaxb.formatted.output", Boolean.TRUE);
return marshaller;
}
/**
* generate student jaxb object from csv records
*
* @return one jaxb student object
*/
private Student getStudent() {
Map<String, String> studentRecord = studentReader.getCurrentRecord();
Student student = new Student();
// set id
String studentId = studentRecord.get("StudentUSI");
student.setStudentUniqueStateId(studentId);
student.setId("STUD_" + studentId);
// set name
student.setName(this.getName(studentRecord));
// set sex
student.setSex(SexType.fromValue(studentRecord.get("Sex")));
// set birthData
BirthData birthData = new BirthData();
birthData.setBirthDate(CSVReader.getDate(studentRecord.get("BirthDate")));
student.setBirthData(birthData);
// set ProfileThumbnail
String profile = studentRecord.get("ProfileThumbnail");
if (!profile.isEmpty()) {
student.setProfileThumbnail(profile);
}
// set HispanicLatinoEthnicity
student.setHispanicLatinoEthnicity(studentRecord.get("HispanicLatinoEthnicity") == "1" ? true : false);
// set raceType
String racial = studentRecord.get("RacialCategory");
if (!racial.isEmpty()) {
RaceType raceType = new RaceType();
raceType.getRacialCategory().add(RaceItemType.fromValue(racial));
student.setRace(raceType);
}
// set addresses
addStudentAddresses(student);
// set languages
addStudentLanguages(student);
return student;
}
/**
* Iterate through studentAddress csv file to add all addresses for a specific student
*
* @param student
*/
private void addStudentAddresses(Student student) {
String studentId = student.getStudentUniqueStateId();
while (studentAddressReader.getCurrentRecord() != null) {
Map<String, String> studentAddressRecord = studentAddressReader.getCurrentRecord();
String id = studentAddressRecord.get("StudentUSI");
if (id.compareTo(studentId) > 0) {
// if the studentUSI of the address record is larger than studentUSI of the student
// which means the current address record belongs to next student, not the current one.
break;
} else if (id.equals(studentId)) {
student.getAddress().add(this.getAddress(studentAddressRecord));
}
studentAddressReader.getNextRecord();
}
}
/**
* Iterate through studentLanguage csv file to add all languages for a specific student
*
* @param student
*/
private void addStudentLanguages(Student student) {
String studentId = student.getStudentUniqueStateId();
LanguagesType languages = new LanguagesType();
while (studentLanguageReader.getCurrentRecord() != null) {
Map<String, String> studentLanguageRecord = studentLanguageReader.getCurrentRecord();
String id = studentLanguageRecord.get("StudentUSI");
if (id.compareTo(studentId) > 0) {
// if the studentUSI of the language record is larger than studentUSI of the student
// which means the current language record belongs to next student, not the current one.
break;
} else if (id.equals(studentId)) {
String ls = studentLanguageRecord.get("Language");
if (!ls.isEmpty()) {
LanguageItemType language = LanguageItemType.fromValue(ls);
languages.getLanguage().add(language);
}
}
studentLanguageReader.getNextRecord();
}
if (languages.getLanguage().size() > 0) {
student.setLanguages(languages);
}
}
/**
* generate jaxb parent object from csv record
*
* @return jaxb parent object
*/
private Parent getParent() {
Map<String, String> parentRecord = parentReader.getCurrentRecord();
Parent parent = new Parent();
// set Id
String parentId = parentRecord.get("ParentUSI");
parent.setParentUniqueStateId(parentId);
parent.setId("PRNT_" + parentId);
// set name
parent.setName(this.getName(parentRecord));
// set sex
parent.setSex(SexType.fromValue(parentRecord.get("Sex")));
return parent;
}
/**
* generate StudentParentAssociation jaxb object from csv record
*
* @return a studentParentAssociation jaxb object
*/
private StudentParentAssociation getStudentParentAssociation() {
Map<String, String> studentParentAssociationRecord = studentParentAssociationReader.getCurrentRecord();
StudentParentAssociation studentParentAssociation = new StudentParentAssociation();
// set student reference
StudentIdentityType sit = new StudentIdentityType();
sit.setStudentUniqueStateId(studentParentAssociationRecord.get("StudentUSI"));
StudentReferenceType srt = new StudentReferenceType();
srt.setStudentIdentity(sit);
studentParentAssociation.setStudentReference(srt);
// set parent reference
ParentIdentityType pit = new ParentIdentityType();
pit.setParentUniqueStateId(studentParentAssociationRecord.get("ParentUSI"));
ParentReferenceType prt = new ParentReferenceType();
prt.setParentIdentity(pit);
studentParentAssociation.setParentReference(prt);
// set relation
if (!studentParentAssociationRecord.get("Relation").isEmpty()) {
studentParentAssociation
.setRelation(RelationType.fromValue(studentParentAssociationRecord.get("Relation")));
}
// set primary contact status
String primaryContact = studentParentAssociationRecord.get("PrimaryContactStatus");
if (!primaryContact.isEmpty()) {
studentParentAssociation.setPrimaryContactStatus(primaryContact.equals("1") ? true : false);
}
// set lives with
String livesWith = studentParentAssociationRecord.get("LivesWith");
if (!livesWith.isEmpty()) {
studentParentAssociation.setLivesWith(livesWith.equals("1") ? true : false);
}
// set emergency contact status
String emergencyContact = studentParentAssociationRecord.get("EmergencyContactStatus");
if (!emergencyContact.isEmpty()) {
studentParentAssociation.setEmergencyContactStatus(emergencyContact.equals("1") ? true : false);
}
return studentParentAssociation;
}
/**
* generate address jaxb object from csv record
*
* @param addressRecord
* @return an Address jaxb object
*/
private Address getAddress(Map<String, String> addressRecord) {
Address address = new Address();
String addressType = addressRecord.get("AddressType");
if (!addressType.isEmpty()) {
address.setAddressType(AddressType.fromValue(addressType));
}
address.setStreetNumberName(addressRecord.get("StreetNumberName"));
address.setCity(addressRecord.get("City"));
String state = addressRecord.get("StateAbbreviation");
if (!state.isEmpty()) {
address.setStateAbbreviation(StateAbbreviationType.fromValue(state));
}
address.setPostalCode(addressRecord.get("PostalCode"));
address.setNameOfCounty(addressRecord.get("NameOfCounty"));
return address;
}
/**
* generate name jaxb object from csv record
*
* @param nameRecord
* @return a name jaxb object
*/
private Name getName(Map<String, String> nameRecord) {
Name name = new Name();
String verification = nameRecord.get("Verification");
if (!verification.isEmpty()) {
name.setVerification(PersonalInformationVerificationType.fromValue(verification));
}
String prefix = nameRecord.get("PersonalTitlePrefix");
if (!prefix.isEmpty()) {
name.setPersonalTitlePrefix(PersonalTitlePrefixType.fromValue(prefix));
}
name.setFirstName(nameRecord.get("FirstName"));
String middleName = nameRecord.get("MiddleName");
if (!middleName.isEmpty()) {
name.setMiddleName(middleName);
}
name.setLastSurname(nameRecord.get("LastSurname"));
String generation = nameRecord.get("GenerationCodeSuffix");
if (!generation.isEmpty()) {
name.setGenerationCodeSuffix(GenerationCodeSuffixType.fromValue(generation));
}
return name;
}
}