package fi.utu.ville.exercises.stub;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import org.apache.commons.codec.binary.Base64;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import fi.utu.ville.exercises.model.ExerciseException;
import fi.utu.ville.exercises.model.PersistenceHandler;
import fi.utu.ville.exercises.model.StatisticalSubmissionInfo;
import fi.utu.ville.exercises.model.SubmissionInfo;
import fi.utu.ville.standardutils.BinaryStringConversionHelper;
import fi.utu.ville.standardutils.TempFilesManager;
import fi.utu.ville.standardutils.XMLHelper;
/**
* A class for storing persistently {@link StatisticalSubmissionInfo}-objects to XML and loading them from the persistent representation.
*
* @author Riku Haavisto
*
*/
public class StatisticalSubmInfoSerializer implements Serializable {
/**
*
*/
private static final long serialVersionUID = 3630050290963327288L;
private static final Logger logger = Logger
.getLogger(StatisticalSubmInfoSerializer.class.getName());
public static final StatisticalSubmInfoSerializer INSTANCE = new StatisticalSubmInfoSerializer();
// used element and attribute names
private static final String rootName = "statistical-subm-info";
private static final String timeOnTaskAttr = "time-on-task";
private static final String evaluationAttr = "evaluation";
private static final String doneTimeAttr = "done-time";
private static final String actSubmElName = "submission-info";
private StatisticalSubmInfoSerializer() {
}
/**
* Parses a byte array produced by {@link #save(StatisticalSubmissionInfo, PersistenceHandler, TempFilesManager) save()} to a
* {@link StatisticalSubmissionInfo}-object.
*
* @param dataPres
* saved bytes
* @param forStatGiver
* whether info will be loaded for stat-giver
* @param persistenceHandler
* exercise-type specific {@link PersistenceHandler}
* @param tempManager
* {@link TempFilesManager}
* @return {@link StatisticalSubmissionInfo} loaded from parameters
*/
public <S extends SubmissionInfo> StatisticalSubmissionInfo<S> load(
byte[] dataPres, boolean forStatGiver,
PersistenceHandler<?, S> persistenceHandler,
TempFilesManager tempManager) {
StatisticalSubmissionInfo<S> res = null;
ByteArrayInputStream binput = null;
try {
Document doc = XMLHelper.parseFromBytes(dataPres);
Element rootEl = (Element) doc.getElementsByTagName(rootName).item(
0);
int timeOnTask = Integer.parseInt(rootEl
.getAttribute(timeOnTaskAttr));
double evaluation = Double.parseDouble(rootEl
.getAttribute(evaluationAttr));
long doneTime = Long.parseLong(rootEl.getAttribute(doneTimeAttr));
Element submInfoEl = (Element) rootEl.getElementsByTagName(
actSubmElName).item(0);
String submInfoAscii = submInfoEl.getTextContent();
byte[] submBytes = Base64.decodeBase64(submInfoAscii);
S submInfo = null;
submInfo = persistenceHandler.loadSubmission(submBytes,
forStatGiver, tempManager);
res = new StatisticalSubmissionInfo<S>(timeOnTask, evaluation,
doneTime, submInfo);
logger.info("Loaded: " + res);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ExerciseException e) {
e.printStackTrace();
} finally {
if (binput != null) {
try {
binput.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return res;
}
/**
* Saves a given {@link StatisticalSubmissionInfo} object to persistence (XML) byte-form.
*
* @param toWrite
* {@link StatisticalSubmissionInfo} to save
* @param serializerHandler
* exercise-type specific {@link PersistenceHandler} for saving the {@link SubmissionInfo}-object
* @param tempManager
* {@link TempFilesManager}
* @return bytes of the persistent representation of {@link StatisticalSubmissionInfo}-object
*/
public <S extends SubmissionInfo> byte[] save(
StatisticalSubmissionInfo<S> toWrite,
PersistenceHandler<?, S> serializerHandler,
TempFilesManager tempManager) {
byte[] res = null;
try {
logger.info("About to save: " + toWrite);
Document doc = XMLHelper.createEmptyDocument();
Element topEl = doc.createElement(rootName);
topEl.setAttribute(doneTimeAttr, toWrite.getDoneTime() + "");
topEl.setAttribute(evaluationAttr, toWrite.getEvalution() + "");
topEl.setAttribute(timeOnTaskAttr, toWrite.getTimeOnTask() + "");
Element submInfoEl = doc.createElement(actSubmElName);
byte[] submBytes = serializerHandler.saveSubmission(
toWrite.getSubmissionData(), tempManager);
submInfoEl.setTextContent(BinaryStringConversionHelper
.bytesToString(submBytes));
topEl.appendChild(submInfoEl);
doc.appendChild(topEl);
res = XMLHelper.xmlToBytes(doc);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (TransformerException e) {
e.printStackTrace();
} catch (TransformerFactoryConfigurationError e) {
e.printStackTrace();
} catch (DOMException e) {
e.printStackTrace();
} catch (ExerciseException e) {
e.printStackTrace();
}
return res;
}
/**
* <p>
* Loads the bytes of {@link SubmissionInfo} contained in a byte-representation of a {@link StatisticalSubmissionInfo}.
* </p>
*
* <p>
* This method is mainly useful for loading the byte-representation to inspection so that the developer of an exercise type can easily see does the
* persistent representation of a {@link SubmissionInfo} be what it should be.
* </p>
*
* @param dataPres
* bytes of persisted {@link SubmissionInfo}
* @return the bytes of persisted {@link SubmissionInfo}
*/
public byte[] loadOnlySubmDataForInspecting(byte[] dataPres) {
byte[] res = null;
try {
Document doc = XMLHelper.parseFromBytes(dataPres);
Element rootEl = (Element) doc.getElementsByTagName(rootName).item(
0);
Element submInfoEl = (Element) rootEl.getElementsByTagName(
actSubmElName).item(0);
String submInfoAscii = submInfoEl.getTextContent();
res = Base64.decodeBase64(submInfoAscii);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return res;
}
}