package no.ntnu.fp.storage;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;
import java.util.StringTokenizer;
import no.ntnu.fp.model.Project;
import no.ntnu.fp.model.Person;
import no.ntnu.fp.model.XmlSerializer;
import no.ntnu.fp.swingutil.FPFileFilter;
import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.ParsingException;
import nu.xom.Serializer;
/**
* This class handles all file operations concering storing and loading files.
* More in detail, this constitutes I/O for flat data files and XML files.
*
* @author Thomas Østerlie
* @author Rune Molden
* @version $Revision: 1.3 $ - $Date: 2005/02/20 21:32:17 $
*/
public class FileStorage implements Storage {
private XmlSerializer serializer = new XmlSerializer();
private static String XML_FILE_EXTENSION = "xml";
private static String DATA_FILE_EXTENSION = "data";
/**
* Default constructor.
*/
public FileStorage() {
}
/**
* Loads a file from the system and returns an instanciated {@link Project}
* object if the operation was successfully executed. This method handles both
* flat data file types (<code>*.data</code>) and XML files (<code>*.xml</code>).
*
* @param aFile The file to load
* @return A project found in the loaded file
* @throws IOException If the file could not loaded properly.
* @throws ParseException If the content of the file could not be properly
* parsed.
*/
public Project load(File aFile) throws IllegalArgumentException, IOException, ParseException {
String extension = FPFileFilter.getExtension(aFile);
if (extension != null && extension.toLowerCase().equals(XML_FILE_EXTENSION)) {
return loadXOMFile(aFile);
} else if (extension != null && extension.toLowerCase().equals(DATA_FILE_EXTENSION)) {
return loadFlatFile(aFile);
} else {
throw new IllegalArgumentException("Invalid filetype! The extension (" +
extension + ") is not supported.");
}
}
/**
* Transforms an {@link URL} to a {@link File} object if it originally
* represents a file.
*
* @param url the URL to transform
* @return A File object representing the URL
* @throws IllegalArgumentException If the protocol of the URL is not "file".
*/
protected File getURLFile(URL url) throws IllegalArgumentException {
if (! url.getProtocol().equals("file")) {
throw new IllegalArgumentException("FileStorage only support the file protocol, not " + url);
}
return new File(url.getPath());
}
/**
* Loads a file from a network resource and returns an instanciated
* {@link Project} object if the operation performed successful.
*
* @see #load(File)
*/
public Project load(URL url) throws IOException, ParseException {
return load(getURLFile(url));
}
/**
* Here, a date, represented as a String is parsed into a Date object.
* The date format is {@link DateFormat#MEDIUM} and the locale is set
* to {@link Locale#US}.
*
* @param date The date, represented as a String, to parse
* @return An instanciated Date object
* @throws ParseException If the parse operation fails
*/
protected Date parseDate(String date) throws ParseException {
DateFormat format = DateFormat.getDateInstance(DateFormat.MEDIUM, java.util.Locale.US);
return format.parse(date);
}
protected String parseDateToString(Date date) {
DateFormat format = DateFormat.getDateInstance(DateFormat.MEDIUM, java.util.Locale.US);
return format.format(date);
// StringTokenizer tokenizer = new StringTokenizer(dateFormatted);
}
/**
* A {@link Project} is stored to a proper file format based on it's
* storage representation. If the extension indicates it is to be stored as
* (<code>*.xml</code>), the representation will be in XML. Otherwise, the
* {@link Project} is stored in a flat file format (<code>*.data</code>).
*
* @param aProject The project to save.
* @param aFile The file to save the project to.
* @throws IOException If file I/O in some way fails
*/
public void save(Project aProject, File aFile) throws IOException {
String extension = FPFileFilter.getExtension(aFile);
if (extension != null && extension.equals("data")) {
saveFlatFile(aProject, aFile);
}
else if (extension != null && extension.equals("xml")) {
saveXmlFile(aProject, aFile);
}
else {
throw new IllegalArgumentException("The file type ("
+ extension + ") is not supported as a storage format!");
}
}
/**
*
* @param aProject The project to save.
* @param aFile The file to store the project to.
* @throws IOException If some file I/O fails.
*/
private void saveXmlFile(Project aProject, File aFile) throws IOException {
Serializer serial =
new Serializer(new FileOutputStream(aFile), "iso-8859-1");
serial.setIndent(5);
serial.write(serializer.toXml(aProject));
}
/**
*
* @param url the url to save to.
* @param aProject The project to save.
* @throws IOException
* @throws ParseException
*/
public void save(URL url, Project aProject) throws IOException {
save(aProject, getURLFile(url));
}
private void saveFlatFile(Project aProject, File aFile) throws IOException {
FileWriter aFileWriter = new FileWriter(aFile);
BufferedWriter aWriter = new BufferedWriter(aFileWriter);
PrintWriter printWriter = new PrintWriter(aWriter);
for (int i = 0; i < aProject.getPersonCount(); i++) {
printWriter.println(aProject.getPerson(i).getName() + ";" +
aProject.getPerson(i).getEmail() + ";" +
parseDateToString(aProject.getPerson(i).getDateOfBirth()));
}
printWriter.close();
}
/**
*
* @param aFile
* @return
* @throws IOException
* @throws ParseException
*/
private Project loadFlatFile(File aFile) throws java.io.IOException, ParseException {
Project aProject = new Project();
FileReader aFileReader = new FileReader(aFile);
BufferedReader aReader = new BufferedReader(aFileReader);
String line = aReader.readLine();
while (line != null) {
aProject.addPerson(assemblePerson(line));
line = aReader.readLine();
}
aReader.close();
return aProject;
}
private Project loadXOMFile(File aFile) throws java.io.IOException, ParseException {
Document doc = null;
try {
doc = new Builder().build(aFile);
} catch (ParsingException pe) {
throw new ParseException("Exception when building from " + aFile, -1);
}
return serializer.toProject(doc);
}
private Person assemblePerson(String line) throws ParseException {
StringTokenizer tokenizer = new StringTokenizer(line, ";");
String name = tokenizer.nextToken();
String email = tokenizer.nextToken();
Date date = parseDate(tokenizer.nextToken());
return new Person(name, email, date);
}
}