Repo disclosed
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
package application.parsing;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import application.helpers.Utils;
|
||||
import application.helpers.wrappers.WrappedException;
|
||||
import application.res.Text;
|
||||
|
||||
/**
|
||||
* This class wraps a file together with its writer and readable name together,
|
||||
* so the writer can be written on repeatedly without having to be opened each
|
||||
* and every time.
|
||||
*
|
||||
* @author Bianca
|
||||
*
|
||||
*/
|
||||
|
||||
public class FileWrapper
|
||||
{
|
||||
/**
|
||||
* The file to be wrapped
|
||||
*/
|
||||
private File file;
|
||||
/**
|
||||
* The filename in a readable format so it can be displayed to the user.
|
||||
*/
|
||||
private String readableFileName;
|
||||
/**
|
||||
* A writer for the file
|
||||
*/
|
||||
private BufferedWriter bout;
|
||||
|
||||
/**
|
||||
* Creates a file in temp directory for this filename and creates the writer.
|
||||
*
|
||||
* @param filename Exact filename ending
|
||||
* @param readableFilename First part of the readable name
|
||||
* @param readableSubFilename Second part of the readable name
|
||||
* @throws WrappedException If there was an error creating the file or the
|
||||
* writer
|
||||
*/
|
||||
private FileWrapper(String filename, String readableFilename, String readableSubFilename) throws WrappedException
|
||||
{
|
||||
try
|
||||
{
|
||||
file = Files.createTempFile("health_data", "__" + filename).toFile();
|
||||
readableFileName = createReadableFileName(readableFilename, readableSubFilename);
|
||||
file.deleteOnExit();
|
||||
bout = new BufferedWriter(new FileWriter(file, true));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new WrappedException(null, Text.E_CREATE_TEMP_FILES);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a file in temp directory for this filename and creates the writer.
|
||||
*
|
||||
* @param filename Exact filename ending
|
||||
* @param readableFilename Readable name
|
||||
* @throws WrappedException If there was an error creating the file or the
|
||||
* writer
|
||||
*/
|
||||
public FileWrapper(String filename, String readableFilename) throws WrappedException
|
||||
{
|
||||
this(filename, readableFilename, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a file in temp directory for this filename and creates the writer.
|
||||
* The header will be written with the given header coloumns.
|
||||
*
|
||||
* @param filename Exact filename ending
|
||||
* @param readableFilename First part of the readable name
|
||||
* @param readableSubFilename Second part of the readable name
|
||||
* @param headerColoums The header coloumn names
|
||||
* @throws WrappedException If there was an error creating the file or the
|
||||
* writer
|
||||
*/
|
||||
public FileWrapper(String filename, String readableFilename, String readableSubFilename, String[] headerColoums)
|
||||
throws WrappedException
|
||||
{
|
||||
this(filename, readableFilename, readableSubFilename);
|
||||
try
|
||||
{
|
||||
writeHeaderColumn(headerColoums, true);
|
||||
bout.newLine();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new WrappedException(null, Text.E_CREATE_TEMP_FILES);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines the two parts of the readable filename into on.
|
||||
*
|
||||
* @param partOne The first (main) part of the filename.
|
||||
* @param partTwo The second (additional) part of the filename.
|
||||
* @return The described value.
|
||||
*/
|
||||
public static String createReadableFileName(String partOne, String partTwo)
|
||||
{
|
||||
if (partTwo == null)
|
||||
{
|
||||
return String.format(Text.F_FILE_DESC, partOne, "");
|
||||
}
|
||||
return String.format(Text.F_FILE_DESC, partOne, partTwo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a readable filename.
|
||||
*
|
||||
* @param name The intended filename.
|
||||
* @return The described value.
|
||||
*/
|
||||
public static String createReadableFileName(String name)
|
||||
{
|
||||
return createReadableFileName(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the header column in the files (names of attributes and sub attributes
|
||||
* (in lists))
|
||||
*
|
||||
* @param attributes names of the attributes
|
||||
* @param top attributes can be nested. If this is {@code True}, then
|
||||
* this is the top level attribute. If this is {@code False}
|
||||
* than it's a sub attribute.
|
||||
* @throws IOException if there was an error writing
|
||||
*/
|
||||
private void writeHeaderColumn(String[] attributes, boolean top) throws IOException
|
||||
{
|
||||
for (int i = 0; i < attributes.length; i++)
|
||||
{
|
||||
// write attributeName
|
||||
bout.write(attributes[i]);
|
||||
// in case of sub attributes write sested elements
|
||||
if (attributes[i].equalsIgnoreCase(Text.TAG_NAME_META_DATA_ENTRY))
|
||||
{
|
||||
bout.write("[[");
|
||||
writeHeaderColumn(Utils.META_DATA_ATTR, false);
|
||||
bout.write("]*]");
|
||||
}
|
||||
if (attributes[i].equalsIgnoreCase(Text.TAG_NAME_WORKOUT_EVENT))
|
||||
{
|
||||
bout.write("[[");
|
||||
writeHeaderColumn(Utils.WORKOUT_EVENT_ATTR, false);
|
||||
bout.write("]*]");
|
||||
}
|
||||
if (attributes[i].equalsIgnoreCase(Text.TAG_NAME_WORKOUT_ROUTE))
|
||||
{
|
||||
bout.write("[[");
|
||||
writeHeaderColumn(Utils.WORKOUT_ROUTE_ATTR, false);
|
||||
bout.write("]*]");
|
||||
}
|
||||
if (attributes[i].equalsIgnoreCase(Text.TAG_NAME_HR_LIST))
|
||||
{
|
||||
bout.write("[[");
|
||||
writeHeaderColumn(Utils.HR_LIST_ATTR, false);
|
||||
bout.write("]*]");
|
||||
}
|
||||
if (attributes[i].equalsIgnoreCase(Text.TAG_NAME_IB_PER_MINUTES))
|
||||
{
|
||||
bout.write("[[");
|
||||
writeHeaderColumn(Utils.IB_PER_MINUTES_ATTR, false);
|
||||
bout.write("]*]");
|
||||
}
|
||||
//Elements are separated with ';' on top level and with ',' on all other levels
|
||||
if (i < attributes.length - 1)
|
||||
{
|
||||
if (top)
|
||||
{
|
||||
bout.write(";");
|
||||
}
|
||||
else
|
||||
{
|
||||
bout.write(",");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the writer for the file.
|
||||
* @return the described value.
|
||||
*/
|
||||
public BufferedWriter getBufferedWriter()
|
||||
{
|
||||
return bout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file as an object.
|
||||
* @return The described value.
|
||||
*/
|
||||
public File getFile()
|
||||
{
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the readable filename.
|
||||
* @return The described value.
|
||||
*/
|
||||
public String getReadableFilename()
|
||||
{
|
||||
return readableFileName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package application.parsing;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
import application.helpers.wrappers.Occupation;
|
||||
import application.helpers.wrappers.WrappedException;
|
||||
import application.helpers.wrappers.WriteSelection;
|
||||
import application.res.Text;
|
||||
|
||||
/**
|
||||
* This class coordinates the work with the parser (Reading and Writing).
|
||||
* @author Bianca
|
||||
*
|
||||
*/
|
||||
public class ParsingWrapper
|
||||
{
|
||||
/** The {@link ReadHandler} who will give an overview of the health data given**/
|
||||
private ReadHandler read;
|
||||
/** factory needed for the parser**/
|
||||
private SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
|
||||
/** the parser**/
|
||||
private SAXParser saxParser;
|
||||
/** The health data file**/
|
||||
private File srcFile;
|
||||
|
||||
/**
|
||||
* Constructor tries to get access to the health data file
|
||||
*
|
||||
* @param file file object of the data
|
||||
* @throws Exception in case there was an error while getting access
|
||||
*/
|
||||
public ParsingWrapper(File file) throws Exception
|
||||
{
|
||||
srcFile=file;
|
||||
saxParser = saxParserFactory.newSAXParser();
|
||||
read = new ReadHandler();
|
||||
saxParser.parse(srcFile, read);
|
||||
if(read.getExportDate()==null) //wrong file / error reading
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives access to the read data
|
||||
* @return
|
||||
*/
|
||||
public ReadHandler getRead()
|
||||
{
|
||||
return read;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the chosen data to the temp-directory
|
||||
* @param selection The users selection on what data to use
|
||||
* @param job The given job of the user
|
||||
* @return the created files. Keys are the readable filenames
|
||||
* @throws WrappedException If there was an error with the writing to files
|
||||
*/
|
||||
public HashMap<String,File> writeSelectedDataToFiles(WriteSelection selection, Occupation job) throws WrappedException
|
||||
{
|
||||
try
|
||||
{
|
||||
WriteHandler write = new WriteHandler(selection, job);
|
||||
saxParser.parse(srcFile, write);
|
||||
if(write.getErrorMessages()!=null)
|
||||
{
|
||||
throw new WrappedException(null, write.getErrorMessages());
|
||||
}
|
||||
return write.getAllFiles();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw new WrappedException(e, Text.E_WRITE_TO_TEMP_FILES);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the files from the temp directory into a zip file and places it in the given directory.
|
||||
* @param files The files to wrap up
|
||||
* @param targetDir The directory on where to save them
|
||||
* @return The created zip file or {@code null} if writing / creating didn't work
|
||||
*/
|
||||
public File writeToZipFile(HashMap<String,File> files, File targetDir)
|
||||
{
|
||||
File target = new File(targetDir, "Export.zip");
|
||||
int c=0;
|
||||
//file with the same name could already exist
|
||||
while(target.exists())
|
||||
{
|
||||
c++;
|
||||
target = new File(targetDir, "Export("+c+").zip");
|
||||
}
|
||||
boolean created=false;
|
||||
try
|
||||
{
|
||||
created=target.createNewFile();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
//file couldn't be created due to exception
|
||||
}
|
||||
if(!created)
|
||||
{ //file couldn't be created, so writing impossible
|
||||
return null;
|
||||
}
|
||||
try(FileOutputStream fos = new FileOutputStream(target);
|
||||
ZipOutputStream zipOut = new ZipOutputStream(fos))
|
||||
{
|
||||
for (String key : files.keySet())
|
||||
{
|
||||
File srcFile=files.get(key);
|
||||
if(srcFile!=null)
|
||||
{
|
||||
try(FileInputStream fis = new FileInputStream(srcFile))
|
||||
{
|
||||
String filename= srcFile.getName();
|
||||
filename=filename.substring(filename.indexOf("__")+2);
|
||||
ZipEntry zipEntry = new ZipEntry(filename);
|
||||
zipOut.putNextEntry(zipEntry);
|
||||
byte[] bytes = new byte[1024];
|
||||
int length;
|
||||
while((length = fis.read(bytes)) >= 0)
|
||||
{
|
||||
zipOut.write(bytes, 0, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
//Problem with the file streams, Nothing a user could change so:
|
||||
return null;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
package application.parsing;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import application.enums.BiologicalSex;
|
||||
import application.enums.BloodType;
|
||||
import application.enums.EntryType;
|
||||
import application.enums.SkinType;
|
||||
import application.helpers.Utils;
|
||||
import application.res.Text;
|
||||
|
||||
/**
|
||||
* This class is in charge of reading in the data of the file and getting an overview of the data.
|
||||
* @author Bianca
|
||||
*
|
||||
*/
|
||||
public class ReadHandler extends DefaultHandler
|
||||
{
|
||||
/** The date the health data was exported**/
|
||||
private String exportDate;
|
||||
/** the biological sex given in the health data **/
|
||||
private BiologicalSex bSex;
|
||||
/** the blood type given in the health data **/
|
||||
private BloodType bloodType;
|
||||
/** the skin type given in the health data **/
|
||||
private SkinType skinType;
|
||||
/** the region code given in the health data **/
|
||||
private String regionCode;
|
||||
/** the date of birth as a string given in the health data**/
|
||||
private String dateOfBirthString;
|
||||
/** the date of birth saved in a calendar**/
|
||||
private Calendar dateOfBirth;
|
||||
/** contains as a key the name of tags (e.g EntryTypes) and as value the number of occurrences**/
|
||||
private HashMap<String, Integer> names=new HashMap<>();
|
||||
/** contains as a key the name of the sub workout and as value the number of occurrences **/
|
||||
private HashMap<String, Integer> subWorkouts=new HashMap<>();
|
||||
/** contains as a key the name of the sub records and as value the number of occurrences **/
|
||||
private HashMap<String, Integer> subRecords=new HashMap<>();
|
||||
/** keeps track of the tag layer. With every new element we increase the layer by one**/
|
||||
private int overallLayer=0;
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
|
||||
{
|
||||
//increase layer
|
||||
if(overallLayer>0)
|
||||
{
|
||||
overallLayer++;
|
||||
}
|
||||
|
||||
if (qName.equalsIgnoreCase(Text.TAG_NAME_HEALTH_DATA))
|
||||
{ //outermost tag (overallLayer==0)
|
||||
overallLayer++;
|
||||
regionCode=attributes.getValue(Text.TAG_ATTR_REGION_CODE);
|
||||
}
|
||||
else if (qName.equalsIgnoreCase(EntryType.EXPORT_DATE.getValue()))
|
||||
{
|
||||
exportDate=attributes.getValue(Text.TAG_ATTR_EXPORT_DATE);
|
||||
}
|
||||
else if (qName.equalsIgnoreCase(Text.TAG_NAME_ME_INFO))
|
||||
{
|
||||
bSex = BiologicalSex.getValue(attributes.getValue(Text.TAG_ATTR_BIOLOGICAL_SEX));
|
||||
dateOfBirthString = attributes.getValue(Text.TAG_ATTR_DATE_OF_BIRTH);
|
||||
bloodType = BloodType.getValue(attributes.getValue(Text.TAG_ATTR_BLOOD_TYPE));
|
||||
skinType = SkinType.getValue(attributes.getValue(Text.TAG_ATTR_SKIN_TYPE));
|
||||
if(dateOfBirthString!=null&&!dateOfBirthString.equals(""))
|
||||
{
|
||||
try
|
||||
{
|
||||
dateOfBirth=new GregorianCalendar();
|
||||
dateOfBirth.setTime(Utils.formatDateOfBirth.parse(dateOfBirthString));
|
||||
} catch (ParseException e)
|
||||
{
|
||||
dateOfBirth=null;
|
||||
e.printStackTrace();
|
||||
//do nth if parsing error
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (qName.equalsIgnoreCase(EntryType.RECORD.getValue()))
|
||||
{
|
||||
String subRecord=attributes.getValue(Text.TAG_ATTR_RECORD_TYPE);
|
||||
Integer j = subRecords.get(subRecord);
|
||||
if (j == null)
|
||||
{
|
||||
j = 0;
|
||||
}
|
||||
subRecords.put(subRecord, ++j);
|
||||
}
|
||||
else if (qName.equalsIgnoreCase(EntryType.WORKOUT.getValue()))
|
||||
{
|
||||
String subWorkout=attributes.getValue(Text.TAG_ATTR_WORKOUT_TYPE);
|
||||
Integer j = subWorkouts.get(subWorkout);
|
||||
if (j == null)
|
||||
{
|
||||
j = 0;
|
||||
}
|
||||
subWorkouts.put(subWorkout, ++j);
|
||||
}
|
||||
|
||||
if(overallLayer==2) //layer 2 means direct descendants of the document root (HealthData-tag)
|
||||
{
|
||||
Integer v=names.get(qName);
|
||||
if (v==null)
|
||||
{
|
||||
v=0;
|
||||
}
|
||||
|
||||
names.put(qName, ++v);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName) throws SAXException
|
||||
{
|
||||
//decrease layer
|
||||
if(overallLayer>0)
|
||||
{
|
||||
overallLayer--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the selected value from ME or ExportDate.
|
||||
*
|
||||
* @param type Value to find the info for.
|
||||
* @return Found value if it was a valid entry of ME or the export Date,
|
||||
* {@code null} otherwise
|
||||
*/
|
||||
public String getMeInfo(EntryType type)
|
||||
{
|
||||
if (type.equals(EntryType.BIOLOGICAL_SEX))
|
||||
{
|
||||
return bSex.getReadableValue();
|
||||
} else if (type.equals(EntryType.DATE_OF_BIRTH))
|
||||
{
|
||||
return getDateOfBirth();
|
||||
}
|
||||
if (type.equals(EntryType.BLOOD_TYPE))
|
||||
{
|
||||
return bloodType.getReadableValue();
|
||||
}
|
||||
if (type.equals(EntryType.SKIN_TYPE))
|
||||
{
|
||||
return skinType.getReadableValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the day the health data was exported
|
||||
* @return the described value.
|
||||
*/
|
||||
public String getExportDate()
|
||||
{
|
||||
return exportDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the region code given in the file.
|
||||
* @return the described value.
|
||||
*/
|
||||
public String getRegionCode()
|
||||
{
|
||||
return regionCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds out how many Entries of the given EntryTypes can be found in the
|
||||
* document
|
||||
*
|
||||
* @param type EntryType to find the count to
|
||||
* @return 0 if there are none, otherwise the correct number of entries
|
||||
*/
|
||||
public int getTypeNumber(EntryType type)
|
||||
{
|
||||
if (names.get(type.getValue()) == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return names.get(type.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the year of birth if the data was given in the file. Otherwise returns -1.
|
||||
* @return the described value.
|
||||
*/
|
||||
public int getDateOfBirthYear()
|
||||
{
|
||||
if(dateOfBirth!=null)
|
||||
{
|
||||
return dateOfBirth.get(Calendar.YEAR);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the month of birth if the data was given in the file. Otherwise returns -1.
|
||||
* @return the described value.
|
||||
*/
|
||||
public int getDateOfBirthMonth()
|
||||
{
|
||||
if(dateOfBirth!=null)
|
||||
{
|
||||
return dateOfBirth.get(Calendar.MONTH)+1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the day of birth if the data was given in the file. Otherwise returns -1.
|
||||
* @return the described value.
|
||||
*/
|
||||
public int getDateOfBirthDay()
|
||||
{
|
||||
if(dateOfBirth!=null)
|
||||
{
|
||||
return dateOfBirth.get(Calendar.DAY_OF_MONTH);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SubWorkouts with their respective occurrences
|
||||
* @return The described value
|
||||
*/
|
||||
public HashMap<String, Integer> getSubWorkouts()
|
||||
{
|
||||
return subWorkouts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SubRecords with their respective occurrences
|
||||
* @return The described value
|
||||
*/
|
||||
public HashMap<String, Integer> getSubRecords()
|
||||
{
|
||||
return subRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date of birth as the String read in the file
|
||||
* @return The described value.
|
||||
*/
|
||||
public String getDateOfBirth()
|
||||
{
|
||||
return dateOfBirthString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date of birth split into 3 parts (day, month, year)
|
||||
* @return the described value
|
||||
*/
|
||||
public HashMap<String, Integer> getSplitDateOfBirth()
|
||||
{
|
||||
HashMap<String, Integer> res= new HashMap<>();
|
||||
if(getDateOfBirthDay()>0)
|
||||
{
|
||||
res.put(Text.DAY, getDateOfBirthDay());
|
||||
}
|
||||
if(getDateOfBirthMonth()>0)
|
||||
{
|
||||
res.put(Text.MONTH, getDateOfBirthMonth());
|
||||
}
|
||||
if(getDateOfBirthYear()>0)
|
||||
{
|
||||
res.put(Text.YEAR, getDateOfBirthYear());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the biological sex as given in the file
|
||||
* @return the described value
|
||||
*/
|
||||
public BiologicalSex getBSex()
|
||||
{
|
||||
return bSex;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,632 @@
|
||||
package application.parsing;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.text.ParseException;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import application.enums.BiologicalSex;
|
||||
import application.enums.BloodType;
|
||||
import application.enums.EntryType;
|
||||
import application.enums.SkinType;
|
||||
import application.helpers.Utils;
|
||||
import application.helpers.wrappers.AttributeDataInfoTuple;
|
||||
import application.helpers.wrappers.GeneralSaveInfo;
|
||||
import application.helpers.wrappers.MeSaveInfo;
|
||||
import application.helpers.wrappers.Occupation;
|
||||
import application.helpers.wrappers.WrappedException;
|
||||
import application.helpers.wrappers.WriteSelection;
|
||||
import application.res.Text;
|
||||
|
||||
public class WriteHandler extends DefaultHandler
|
||||
{
|
||||
/**
|
||||
* Contains the StringBuilders for the nested attributes which need to be added
|
||||
* to the complete Row. Key is the tag name of the nested attribute
|
||||
*/
|
||||
private HashMap<String, AttributeDataInfoTuple> nestedAttributes;
|
||||
/** The text to be written as one row into the files **/
|
||||
private StringBuilder completeRow;
|
||||
/** the selection of the user **/
|
||||
private WriteSelection selection;
|
||||
/** all files which will be written. Key is the readable name **/
|
||||
private HashMap<String, FileWrapper> allFiles;
|
||||
/**
|
||||
* In case of records and workouts there will be sub elements. The name will be
|
||||
* saved here.
|
||||
**/
|
||||
private String subElementName = null;
|
||||
/**
|
||||
* All error messages will be appended here as {@link DefaultHandler} does not
|
||||
* permit other exceptions in the startElement and endElement methods
|
||||
**/
|
||||
private StringBuilder errorMessages;
|
||||
|
||||
/**
|
||||
* Initializes the variables and creates all files needed for the selected data
|
||||
*
|
||||
* @param selection The selection of the user
|
||||
* @param job The job given by the user
|
||||
*/
|
||||
public WriteHandler(WriteSelection selection, Occupation job)
|
||||
{
|
||||
this.selection = selection;
|
||||
this.errorMessages = new StringBuilder();
|
||||
resetSubAttributes();
|
||||
// figure out what is selected
|
||||
// create files for the selected
|
||||
allFiles = new HashMap<>();
|
||||
try
|
||||
{
|
||||
boolean me = false;
|
||||
for (EntryType meElem : EntryType.ALL_ME_ONES)
|
||||
{
|
||||
if (this.selection.entrySelected(meElem))
|
||||
{
|
||||
me = true;
|
||||
}
|
||||
}
|
||||
if (!job.equals(Text.NOT_SET))
|
||||
{ // job given
|
||||
me = true;
|
||||
}
|
||||
if (me)
|
||||
{
|
||||
FileWrapper fw = new FileWrapper("me_info.txt", "MainInfo");
|
||||
allFiles.put(fw.getReadableFilename(), fw);
|
||||
if (!job.getLevelOne().equals(Text.NOT_SET))
|
||||
{
|
||||
writeToMeFile(new MeSaveInfo(EntryType.JOB, Text.OCCUPATION_LEVEL_ONE, job.getLevelOne()));
|
||||
if (!job.getLevelTwo().equals(Text.NOT_SET))
|
||||
{
|
||||
writeToMeFile(new MeSaveInfo(EntryType.JOB, Text.OCCUPATION_LEVEL_TWO, job.getLevelTwo()));
|
||||
if (!job.getLevelThree().equals(Text.NOT_SET))
|
||||
{
|
||||
writeToMeFile(new MeSaveInfo(EntryType.JOB, Text.OCCUPATION_LEVEL_THREE, job.getLevelThree()));
|
||||
if (!job.getLevelFour().equals(Text.NOT_SET))
|
||||
{
|
||||
writeToMeFile(new MeSaveInfo(EntryType.JOB, Text.OCCUPATION_LEVEL_FOUR, job.getLevelFour()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.selection.entrySelected(EntryType.ACTIVITY_SUMMARY))
|
||||
{
|
||||
FileWrapper fw = new FileWrapper("activity_summary.csv", EntryType.ACTIVITY_SUMMARY.getValue(), null,
|
||||
Utils.ACTIV_SUMM_ATTR);
|
||||
allFiles.put(fw.getReadableFilename(), fw);
|
||||
}
|
||||
if (this.selection.entrySelected(EntryType.WORKOUT))
|
||||
{
|
||||
for (String selectedType : selection.getWorkouts())
|
||||
{
|
||||
FileWrapper fw = new FileWrapper("workout_" + selectedType + ".csv", EntryType.WORKOUT.getValue(),
|
||||
Utils.shortenHKStrings(selectedType), Utils.workoutAttributes);
|
||||
allFiles.put(fw.getReadableFilename(), fw);
|
||||
}
|
||||
}
|
||||
if (this.selection.entrySelected(EntryType.RECORD))
|
||||
{
|
||||
for (String selectedType : selection.getRecords())
|
||||
{
|
||||
FileWrapper fw = new FileWrapper("record_" + selectedType + ".csv", EntryType.RECORD.getValue(),
|
||||
Utils.shortenHKStrings(selectedType), Utils.recordAttributes);
|
||||
allFiles.put(fw.getReadableFilename(), fw);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (WrappedException e)
|
||||
{
|
||||
errorMessages.append(e.getReason());
|
||||
errorMessages.append("\n");
|
||||
e.getException().printStackTrace();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
errorMessages.append(Text.E_CREATE_TEMP_FILES);
|
||||
errorMessages.append("\n");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
|
||||
{
|
||||
try
|
||||
{
|
||||
// ME Entries not of the me tag
|
||||
if (selection.entrySelected(EntryType.REGION_CODE) && qName.equalsIgnoreCase(Text.TAG_NAME_HEALTH_DATA))
|
||||
{
|
||||
writeToMeFile(new MeSaveInfo(EntryType.REGION_CODE, attributes.getValue(Text.TAG_ATTR_REGION_CODE)));
|
||||
}
|
||||
else if (selection.entrySelected(EntryType.EXPORT_DATE)
|
||||
&& qName.equalsIgnoreCase(EntryType.EXPORT_DATE.getValue()))
|
||||
{
|
||||
writeToMeFile(new MeSaveInfo(EntryType.EXPORT_DATE, attributes.getValue(Text.TAG_ATTR_EXPORT_DATE)));
|
||||
}
|
||||
// ME Tag
|
||||
else if (qName.equalsIgnoreCase(Text.TAG_NAME_ME_INFO))
|
||||
{
|
||||
for (EntryType me : EntryType.ALL_ORIGINAL_ME_ONES)
|
||||
{
|
||||
if (selection.entrySelected(me))
|
||||
{
|
||||
String dateOfBirthString = attributes.getValue(Text.TAG_ATTR_DATE_OF_BIRTH);
|
||||
// first the simple ones
|
||||
if (me != EntryType.DATE_OF_BIRTH)
|
||||
{
|
||||
String value = "";
|
||||
if (me == EntryType.BIOLOGICAL_SEX)
|
||||
{
|
||||
value = BiologicalSex.getValue(attributes.getValue(Text.TAG_ATTR_BIOLOGICAL_SEX))
|
||||
.getReadableValue();
|
||||
}
|
||||
else if (me == EntryType.BLOOD_TYPE)
|
||||
{
|
||||
value = BloodType.getValue(attributes.getValue(Text.TAG_ATTR_BLOOD_TYPE))
|
||||
.getReadableValue();
|
||||
}
|
||||
else if (me == EntryType.SKIN_TYPE)
|
||||
{
|
||||
value = SkinType.getValue(attributes.getValue(Text.TAG_ATTR_SKIN_TYPE))
|
||||
.getReadableValue();
|
||||
}
|
||||
writeToMeFile(new MeSaveInfo(me, value));
|
||||
}
|
||||
else if (dateOfBirthString != null && !dateOfBirthString.equals(""))
|
||||
{// now the date of birth with individually selected parts
|
||||
try
|
||||
{
|
||||
Calendar dateOfBirth = new GregorianCalendar();
|
||||
dateOfBirth.setTime(Utils.formatDateOfBirth.parse(dateOfBirthString));
|
||||
|
||||
if (selection.birthPartSelected(Text.YEAR))
|
||||
{
|
||||
writeToMeFile(new MeSaveInfo(EntryType.DATE_OF_BIRTH, Text.YEAR,
|
||||
dateOfBirth.get(Calendar.YEAR) + ""));
|
||||
}
|
||||
if (selection.birthPartSelected(Text.MONTH))
|
||||
{
|
||||
writeToMeFile(new MeSaveInfo(EntryType.DATE_OF_BIRTH, Text.MONTH,
|
||||
"" + (dateOfBirth.get(Calendar.MONTH) + 1)));
|
||||
}
|
||||
if (selection.birthPartSelected(Text.DAY))
|
||||
{
|
||||
writeToMeFile(new MeSaveInfo(EntryType.DATE_OF_BIRTH, Text.DAY,
|
||||
dateOfBirth.get(Calendar.DAY_OF_MONTH) + ""));
|
||||
}
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
// bad luck. Do nothing if parsing error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// activity summaries: only one file and no special cases
|
||||
else if (selection.entrySelected(EntryType.ACTIVITY_SUMMARY)
|
||||
&& qName.equalsIgnoreCase(EntryType.ACTIVITY_SUMMARY.getValue()))
|
||||
{
|
||||
writeToFile(new GeneralSaveInfo(getValuesToAttributes(Utils.ACTIV_SUMM_ATTR, attributes),
|
||||
EntryType.ACTIVITY_SUMMARY));
|
||||
}
|
||||
// The following ones might need completion in the endElement-method
|
||||
else if (qName.equalsIgnoreCase(EntryType.WORKOUT.getValue()) && selection.workoutSelected(attributes))
|
||||
{
|
||||
subElementName = Utils.shortenHKStrings(attributes.getValue(Text.TAG_ATTR_WORKOUT_TYPE));
|
||||
completeRow.append(getNonNestedAttributeValues(
|
||||
getValuesToAttributes(Utils.workoutAttributes, attributes), Utils.workoutAttributes, true));
|
||||
}
|
||||
else if (qName.equalsIgnoreCase(EntryType.RECORD.getValue()) && selection.recordSelected(attributes))
|
||||
{
|
||||
subElementName = Utils.shortenHKStrings(attributes.getValue(Text.TAG_ATTR_RECORD_TYPE));
|
||||
completeRow.append(getNonNestedAttributeValues(
|
||||
getValuesToAttributes(Utils.recordAttributes, attributes), Utils.recordAttributes, true));
|
||||
}
|
||||
// These are now nested elements with nested attributes
|
||||
else if (subElementName != null && isNestedAttribute(qName))
|
||||
{
|
||||
for (String tagName : nestedAttributes.keySet())
|
||||
{
|
||||
if (qName.equals(tagName))
|
||||
{ // all entries in attributes
|
||||
AttributeDataInfoTuple tuple = nestedAttributes.get(tagName);
|
||||
if (tagName.equals(Text.TAG_NAME_HR_LIST))
|
||||
{ // this one is completely nested
|
||||
tuple.getBuilder().append("[");
|
||||
}
|
||||
else
|
||||
{
|
||||
tuple.getBuilder()
|
||||
.append(getNonNestedAttributeValues(
|
||||
getValuesToAttributes(tuple.getSubAttributes(), attributes),
|
||||
tuple.getSubAttributes(), false));
|
||||
if (!tagName.equals(Text.TAG_NAME_WORKOUT_ROUTE))
|
||||
{ // workout route is nested again and isn't complete yet
|
||||
tuple.getBuilder().append(",");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (WrappedException e)
|
||||
{
|
||||
errorMessages.append(e.getReason());
|
||||
errorMessages.append("\n");
|
||||
// TODO: alle prints entfernen
|
||||
e.getException().printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes all attributes of an element up to the first nested attribute
|
||||
*
|
||||
* @param values attribute values to be written
|
||||
* @param names attribute names to check for nesting
|
||||
* @param top indicates whether this is already a nested attribute
|
||||
* ({@code False}) or whether we are at top level ({@code True}
|
||||
* @return The complete string for the element if there are no nested values,
|
||||
* otherwise the incomplete beginning which needs to be finished with
|
||||
* {@code addAllNestedAttributes}
|
||||
*/
|
||||
private String getNonNestedAttributeValues(String[] values, String[] names, boolean top)
|
||||
{
|
||||
StringBuilder res = new StringBuilder();
|
||||
// Start element with a bracket
|
||||
res.append("[");
|
||||
for (int i = 0; i < names.length; i++)
|
||||
{
|
||||
if (isNestedAttribute(names[i]))
|
||||
{ // stop if attribute is nested, then we need to finish at another point
|
||||
// here is no bracket at the end!
|
||||
return res.toString();
|
||||
}
|
||||
res.append(values[i]);
|
||||
if (top)
|
||||
{
|
||||
res.append(";");
|
||||
}
|
||||
else
|
||||
{
|
||||
res.append(",");
|
||||
}
|
||||
}
|
||||
// replace last char (, or ;) with bracket
|
||||
res = res.replace(res.length() - 1, res.length(), "]");
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines for an attribute name whether it is a nested attribute
|
||||
*
|
||||
* @param attr the name to check
|
||||
* @return {@code True} if it is a nested attribute, {@code False} otherwise.
|
||||
*/
|
||||
private boolean isNestedAttribute(String attr)
|
||||
{
|
||||
for (String nestedAttribute : nestedAttributes.keySet())
|
||||
{
|
||||
if (attr.equals(nestedAttribute))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName) throws SAXException
|
||||
{
|
||||
if (subElementName != null)
|
||||
{ // we have a selected value which is nested / has nested attributes
|
||||
if (isNestedAttribute(qName))
|
||||
{ // nested case: either hr_list or workout_route
|
||||
|
||||
if (qName.equals(Text.TAG_NAME_HR_LIST))
|
||||
{ // all entries in IBperMinutes
|
||||
appendSubEntry(Text.TAG_NAME_HR_LIST, Text.TAG_NAME_IB_PER_MINUTES);
|
||||
nestedAttributes.put(Text.TAG_NAME_IB_PER_MINUTES,
|
||||
new AttributeDataInfoTuple(Utils.IB_PER_MINUTES_ATTR));
|
||||
nestedAttributes.get(Text.TAG_NAME_HR_LIST).getBuilder().append("],");
|
||||
}
|
||||
if (qName.equals(Text.TAG_NAME_WORKOUT_ROUTE))
|
||||
{ // last entry not in attributes! (MetaDataEntry)
|
||||
appendSubEntry(Text.TAG_NAME_WORKOUT_ROUTE, Text.TAG_NAME_META_DATA_ENTRY);
|
||||
nestedAttributes.put(Text.TAG_NAME_META_DATA_ENTRY,
|
||||
new AttributeDataInfoTuple(Utils.META_DATA_ATTR));
|
||||
nestedAttributes.get(Text.TAG_NAME_WORKOUT_ROUTE).getBuilder().append("],");
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // this can only be a record or workout
|
||||
// non nested ones were written in the start method, so only add the nested ones
|
||||
// now
|
||||
if (qName.equalsIgnoreCase(EntryType.WORKOUT.getValue()))
|
||||
{
|
||||
addAllNestedAttributes(completeRow, Utils.workoutAttributes);
|
||||
}
|
||||
else
|
||||
{
|
||||
addAllNestedAttributes(completeRow, Utils.recordAttributes);
|
||||
}
|
||||
|
||||
completeRow = removeOuterBrackets(completeRow);
|
||||
FileWrapper fw = allFiles.get(FileWrapper.createReadableFileName(qName, subElementName));
|
||||
if (fw != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
fw.getBufferedWriter().append(completeRow);
|
||||
fw.getBufferedWriter().newLine();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
errorMessages.append(Text.E_WRITE_TO_TEMP_FILES);
|
||||
errorMessages.append("\n");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
resetSubAttributes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for removing the outer Brackets in a StringBuilder, but in truth just
|
||||
* removes the first and last char of it.... So be careful, it doesn't check for
|
||||
* brackets!
|
||||
*
|
||||
* @param sb The StringBuilder to be shortened
|
||||
* @return The shortened StringBuilder
|
||||
*/
|
||||
private StringBuilder removeOuterBrackets(StringBuilder sb)
|
||||
{
|
||||
sb = sb.replace(0, 1, "");
|
||||
return sb.replace(sb.length() - 1, sb.length(), "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Nested Attributes (which are ALLWAYS at the end of attribute lists) are here
|
||||
* appended at the end of the current row
|
||||
*
|
||||
* @param toAppend Contains the current row which should be appended
|
||||
* @param attributes The whole attribute list of the current row. But only the
|
||||
* nested ones will be appended thus the non nested ones need
|
||||
* to already be in the StringBuilder
|
||||
*/
|
||||
private void addAllNestedAttributes(StringBuilder toAppend, String[] attributes)
|
||||
{
|
||||
for (int i = 0; i < attributes.length; i++)
|
||||
{
|
||||
for (String tagName : nestedAttributes.keySet())
|
||||
{
|
||||
if (attributes[i].equals(tagName))
|
||||
{
|
||||
appendSubEntry(toAppend, tagName);
|
||||
toAppend.append(";");
|
||||
}
|
||||
}
|
||||
}
|
||||
toAppend = toAppend.replace(toAppend.length() - 1, toAppend.length(), "]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the text of a sub entry to its containing row. All sub entries (even
|
||||
* if they are empty) will be surrounded by brackets [].
|
||||
*
|
||||
* @param toAppendTo The containing row which should be appended
|
||||
* @param nestedInfo The name of the attribute containing the sub entry
|
||||
* information
|
||||
*/
|
||||
private void appendSubEntry(StringBuilder toAppendTo, String nestedInfo)
|
||||
{
|
||||
toAppendTo.append("[");
|
||||
StringBuilder toAppendWith = nestedAttributes.get(nestedInfo).getBuilder();
|
||||
if (toAppendWith.length() > 0) // there is an element here, so there is also a ',' too much
|
||||
{
|
||||
toAppendTo.append(toAppendWith.substring(0, toAppendWith.length() - 1));
|
||||
}
|
||||
toAppendTo.append("]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the text of a sub entry to its containing row. All sub entries (even
|
||||
* if they are empty) will be surrounded by brackets [].
|
||||
*
|
||||
* @param topLevelInfo The name of the attribute which should be appended with a
|
||||
* sub attribute
|
||||
* @param nestedInfo The name of the attribute containing the sub entry
|
||||
* information
|
||||
*/
|
||||
private void appendSubEntry(String topLevelInfo, String nestedInfo)
|
||||
{
|
||||
appendSubEntry(nestedAttributes.get(topLevelInfo).getBuilder(), nestedInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* /** Writes one line of information to a file (but not the ME File)
|
||||
*
|
||||
* @param info The information about what to write.
|
||||
* @throws WrappedException if the file could not be written
|
||||
*/
|
||||
private void writeToFile(GeneralSaveInfo info) throws WrappedException
|
||||
{
|
||||
FileWrapper fw = allFiles.get(info.getReadableFilename());
|
||||
if (fw != null)
|
||||
{
|
||||
BufferedWriter bout = fw.getBufferedWriter();
|
||||
try
|
||||
{
|
||||
writeNormalRow(bout, info.getValues(), true);
|
||||
bout.newLine();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw new WrappedException(e, Text.E_WRITE_TO_TEMP_FILES);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes one line of information to the me file
|
||||
*
|
||||
* @param info The information about what to write.
|
||||
* @throws WrappedException if the file could not be written
|
||||
*/
|
||||
private void writeToMeFile(MeSaveInfo info) throws WrappedException
|
||||
{
|
||||
FileWrapper fw = allFiles.get(FileWrapper.createReadableFileName(Text.ME_FILE_DESC));
|
||||
if (fw != null)
|
||||
{
|
||||
BufferedWriter bout = fw.getBufferedWriter();
|
||||
try
|
||||
{
|
||||
bout.write(String.format(Text.F_ME_SAVE, info.getSaveKey(), info.getSaveValue()));
|
||||
bout.newLine();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
throw new WrappedException(e, Text.E_WRITE_TO_TEMP_FILES);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the HashMap containing the nested attributes info, as well as the
|
||||
* completeRow and sets the subElementname to {@code null}
|
||||
*/
|
||||
private void resetSubAttributes()
|
||||
{
|
||||
nestedAttributes = new HashMap<>();
|
||||
nestedAttributes.put(Text.TAG_NAME_META_DATA_ENTRY, new AttributeDataInfoTuple(Utils.META_DATA_ATTR));
|
||||
nestedAttributes.put(Text.TAG_NAME_WORKOUT_EVENT, new AttributeDataInfoTuple(Utils.WORKOUT_EVENT_ATTR));
|
||||
nestedAttributes.put(Text.TAG_NAME_WORKOUT_ROUTE, new AttributeDataInfoTuple(Utils.WORKOUT_ROUTE_ATTR));
|
||||
nestedAttributes.put(Text.TAG_NAME_HR_LIST, new AttributeDataInfoTuple(Utils.HR_LIST_ATTR));
|
||||
nestedAttributes.put(Text.TAG_NAME_IB_PER_MINUTES, new AttributeDataInfoTuple(Utils.IB_PER_MINUTES_ATTR));
|
||||
|
||||
completeRow = new StringBuilder();
|
||||
subElementName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the values for the given attributes and returns them in an array where
|
||||
* the values are saved at the index corresponding to their keys.
|
||||
*
|
||||
* @param attributeName Keys / names of the attributes.
|
||||
* @param values The object containing the values
|
||||
* @return The described array
|
||||
*/
|
||||
private String[] getValuesToAttributes(String[] attributeName, Attributes values)
|
||||
{
|
||||
String[] res = new String[attributeName.length];
|
||||
for (int i = 0; i < res.length; i++)
|
||||
{
|
||||
String v = values.getValue(attributeName[i]);
|
||||
if(attributeName[i].equals("device")&&v!=null)
|
||||
{
|
||||
//Entry left out due to privacy
|
||||
String device="<HKDevice:";
|
||||
String actualDeviceSubstring=v.substring(v.indexOf(device),v.indexOf(">")+1);
|
||||
v=v.replace(actualDeviceSubstring, "device_anonymized");
|
||||
}
|
||||
if (v == null)
|
||||
{
|
||||
res[i] = "";
|
||||
}
|
||||
else if (v.contains(",") || v.contains(";"))
|
||||
{
|
||||
res[i] = "\"" + v + "\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
res[i] = v;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a non nested row into a file
|
||||
*
|
||||
* @param bout The writer of the file
|
||||
* @param values the values in correct order needed to fit with the header row
|
||||
* which should be written
|
||||
* @param top shows whether this is a "nested row" / nested attribute entry
|
||||
* @throws IOException if there was an error writing
|
||||
*/
|
||||
private void writeNormalRow(Writer bout, String[] values, boolean top) throws IOException
|
||||
{
|
||||
for (int i = 0; i < values.length; i++) // for every attribute value
|
||||
{
|
||||
bout.write(values[i]);
|
||||
if (i < values.length - 1)
|
||||
{
|
||||
if (top)
|
||||
{
|
||||
bout.write(";");
|
||||
}
|
||||
else
|
||||
{
|
||||
bout.write(",");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all files written in temp directory with the readable name as key and
|
||||
* the {@link File} as value. It also closes the writers and thus can only be
|
||||
* used after the end of writing.
|
||||
*
|
||||
* @return The described value.
|
||||
*/
|
||||
public HashMap<String, File> getAllFiles()
|
||||
{
|
||||
HashMap<String, File> res = new HashMap<>();
|
||||
for (String key : allFiles.keySet())
|
||||
{
|
||||
FileWrapper fw = allFiles.get(key);
|
||||
try
|
||||
{
|
||||
fw.getBufferedWriter().close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// Stream couldn't be closed. Bad luck.
|
||||
}
|
||||
res.put(key, fw.getFile());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all accumulated error messages.
|
||||
*
|
||||
* @return The described value or {@code null} if there is no error message.
|
||||
*/
|
||||
public String getErrorMessages()
|
||||
{
|
||||
if (errorMessages.length()==0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return errorMessages.toString();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user