public void exportIntroductionPuzzle(IntroductionPuzzle puzzle, OutputStream os) throws TransformerException, ParserConfigurationException { Document xmlDoc; synchronized ( mDocumentBuilder) { // TODO: Figure out whether the DocumentBuilder is maybe synchronized // anyway xmlDoc = mDOM.createDocument(null, WebOfTrust.WOT_NAME, null); } // 1.0 does not support all Unicode characters which the String class supports. To prevent us // from having to filter all Strings, we use 1.1 xmlDoc.setXmlVersion("1.1"); Element rootElement = xmlDoc.getDocumentElement(); // We include the WoT version to have an easy way of handling bogus XML which might be created // by bugged versions. rootElement.setAttribute("Version", Long.toString(Version.getRealVersion())); Element puzzleElement = xmlDoc.createElement("IntroductionPuzzle"); puzzleElement.setAttribute( "Version", Integer.toString(INTRODUCTION_XML_FORMAT_VERSION)); /* Version of the XML format */ // This lock is actually not necessary because all values which are taken from the puzzle are // final. We leave it here just to make sure that it does // not get lost if it becomes necessary someday. synchronized (puzzle) { puzzleElement.setAttribute("ID", puzzle.getID()); puzzleElement.setAttribute("Type", puzzle.getType().toString()); puzzleElement.setAttribute("MimeType", puzzle.getMimeType()); synchronized (mDateFormat) { puzzleElement.setAttribute("ValidUntil", mDateFormat.format(puzzle.getValidUntilDate())); } Element dataElement = xmlDoc.createElement("Data"); dataElement.setAttribute("Value", Base64.encodeStandard(puzzle.getData())); puzzleElement.appendChild(dataElement); } rootElement.appendChild(puzzleElement); DOMSource domSource = new DOMSource(xmlDoc); StreamResult resultStream = new StreamResult(os); synchronized (mSerializer) { mSerializer.transform(domSource, resultStream); } }