package edu.vserver.exercises.math.essentials.level; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.util.Arrays; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.CDATASection; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import fi.utu.ville.exercises.helpers.GsonPersistenceHandler; import fi.utu.ville.exercises.model.ExerciseData; import fi.utu.ville.exercises.model.ExerciseException; import fi.utu.ville.exercises.model.PersistenceHandler; import fi.utu.ville.exercises.model.SubmissionInfo; import fi.utu.ville.standardutils.TempFilesManager; import fi.utu.ville.standardutils.XMLHelper; /** * A persistencehandler wrapper to use with exercises that use LevelMathDataWrapper. Internally it uses a GsonPersistenceHandler to convert the difficulty * levels to Json, which are combined into one XML file. * * @param <E> * ExerciseData to manage * @param <S> * SubmissionInfo to manage */ public class LevelMathPersistenceWrapper<E extends ExerciseData, S extends SubmissionInfo> implements PersistenceHandler<LevelMathDataWrapper<E>, S> { /** * */ private static final long serialVersionUID = 2629452801442738865L; private final GsonPersistenceHandler<E, S> handler; public LevelMathPersistenceWrapper(Class<E> exerDataClass, Class<S> submInfoClass) { this.handler = new GsonPersistenceHandler<>(exerDataClass, submInfoClass); } @Override public byte[] saveExerData( LevelMathDataWrapper<E> etd, TempFilesManager tempManager, fi.utu.ville.exercises.model.PersistenceHandler.ByRefSaver matHandler) throws ExerciseException { PersistenceHandler<E, S> persistenceHandler = getPersistenceHandler(); E easy = etd.getForLevel(DiffLevel.EASY); E normal = etd.getForLevel(DiffLevel.NORMAL); E hard = etd.getForLevel(DiffLevel.HARD); byte[] easyBuf = persistenceHandler.saveExerData(easy, tempManager, matHandler); byte[] normalBuf = persistenceHandler.saveExerData(normal, tempManager, matHandler); byte[] hardBuf = persistenceHandler.saveExerData(hard, tempManager, matHandler); try { DocumentBuilderFactory docFactory = DocumentBuilderFactory .newInstance(); DocumentBuilder docBuilder; docBuilder = docFactory.newDocumentBuilder(); Document doc = docBuilder.newDocument(); Element rootElement = doc.createElement("levels"); CDATASection easyData = doc.createCDATASection(Arrays .toString(easyBuf)); CDATASection normalData = doc.createCDATASection(Arrays .toString(normalBuf)); CDATASection hardData = doc.createCDATASection(Arrays .toString(hardBuf)); Element easyElement = doc.createElement("easy"); easyElement.appendChild(easyData); Element normalElement = doc.createElement("normal"); normalElement.appendChild(normalData); Element hardElement = doc.createElement("hard"); hardElement.appendChild(hardData); rootElement.appendChild(easyElement); rootElement.appendChild(normalElement); rootElement.appendChild(hardElement); doc.appendChild(rootElement); return XMLHelper.xmlToBytes(doc); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (TransformerConfigurationException e) { e.printStackTrace(); } catch (TransformerException e) { e.printStackTrace(); } catch (TransformerFactoryConfigurationError e) { e.printStackTrace(); } return new byte[] {}; } @Override public LevelMathDataWrapper<E> loadExerData( byte[] dataPres, TempFilesManager tempManager, fi.utu.ville.exercises.model.PersistenceHandler.ByRefLoader matHandler) throws ExerciseException { E easy = null; E normal = null; E hard = null; Document doc = null; PersistenceHandler<E, S> persistenceHandler = getPersistenceHandler(); try { doc = XMLHelper.parseFromBytes(dataPres); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } Element levelsElement = doc.getDocumentElement(); NodeList listOfLevels = levelsElement.getChildNodes(); for (int i = 0; i < listOfLevels.getLength(); i++) { Node levelElement = listOfLevels.item(i); String name = levelElement.getNodeName(); String levelData = levelElement.getChildNodes().item(0) .getNodeValue(); byte[] levelBuf = stringToByteArray(levelData); switch (name) { case "easy": easy = persistenceHandler.loadExerData(levelBuf, tempManager, matHandler); break; case "normal": normal = persistenceHandler.loadExerData(levelBuf, tempManager, matHandler); break; case "hard": hard = persistenceHandler.loadExerData(levelBuf, tempManager, matHandler); break; } } return new LevelMathDataWrapper<E>(easy, normal, hard); } @Override public byte[] saveSubmission(S subm, TempFilesManager tempManager) throws ExerciseException { PersistenceHandler<E, S> handler = getPersistenceHandler(); return handler.saveSubmission(subm, tempManager); } @Override public S loadSubmission(byte[] dataPres, boolean forStatGiver, TempFilesManager tempManager) throws ExerciseException { PersistenceHandler<E, S> handler = getPersistenceHandler(); return handler.loadSubmission(dataPres, forStatGiver, tempManager); } public GsonPersistenceHandler<E, S> getPersistenceHandler() { return handler; } private byte[] stringToByteArray(String value) { String[] byteValues = value.substring(1, value.length() - 1).split(","); byte[] bytes = new byte[byteValues.length]; for (int i = 0, len = bytes.length; i < len; i++) { bytes[i] = Byte.valueOf(byteValues[i].trim()); } return bytes; } public static void printDocument(Document doc, OutputStream out) throws IOException, TransformerException { TransformerFactory tf = TransformerFactory.newInstance(); Transformer transformer = tf.newTransformer(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); transformer.setOutputProperty( "{http://xml.apache.org/xslt}indent-amount", "4"); transformer.transform(new DOMSource(doc), new StreamResult( new OutputStreamWriter(out, "UTF-8"))); } }