1 package sk.stuba.fiit.foo07.genex.export;
2
3 import java.io.BufferedReader;
4 import java.io.BufferedWriter;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7 import java.io.InputStreamReader;
8 import java.io.OutputStreamWriter;
9 import java.io.StringReader;
10 import java.sql.Connection;
11 import java.util.ArrayList;
12
13 import net.iharder.base64.Base64;
14
15 import org.w3c.dom.Document;
16 import org.w3c.dom.Element;
17 import org.w3c.dom.Node;
18
19 import sk.stuba.fiit.foo07.genex.beans.Answer;
20 import sk.stuba.fiit.foo07.genex.beans.Picture;
21 import sk.stuba.fiit.foo07.genex.beans.Question;
22 import sk.stuba.fiit.foo07.genex.beans.QuestionType;
23 import sk.stuba.fiit.foo07.genex.common.ResourceHelper;
24 import sk.stuba.fiit.foo07.genex.common.SettingsHelper;
25 import sk.stuba.fiit.foo07.genex.dao.AnswerDao;
26 import sk.stuba.fiit.foo07.genex.dao.AnswerDaoDerby;
27 import sk.stuba.fiit.foo07.genex.dao.PictureDao;
28 import sk.stuba.fiit.foo07.genex.dao.PictureDaoDerby;
29 import sk.stuba.fiit.foo07.genex.dao.QuestionDao;
30 import sk.stuba.fiit.foo07.genex.dao.QuestionDaoDerby;
31 import sk.stuba.fiit.foo07.genex.dao.QuestionTypeDao;
32 import sk.stuba.fiit.foo07.genex.dao.QuestionTypeDaoDerby;
33 import sk.stuba.fiit.foo07.genex.exceptions.ExportException;
34
35 import com.sun.org.apache.xerces.internal.dom.DocumentImpl;
36 import com.sun.org.apache.xml.internal.serialize.OutputFormat;
37 import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
38
39
40
41
42
43
44 public class ExportMoodle extends Export {
45
46
47
48
49
50
51
52
53 private class QuestionAnswers {
54 public QuestionAnswers(Question q, ArrayList<Answer> ans) {
55
56 this.question = new Question();
57 this.question.setCreated(q.getCreated());
58 this.question.setDerivedFromID(q.getDerivedFromID());
59 this.question.setDifficulty(q.getDifficulty());
60 this.question.setLastUpdate(q.getLastUpdate());
61 this.question.setQuestionID(q.getQuestionID());
62 this.question.setQuestionTypeID(q.getQuestionTypeID());
63 this.question.setText(q.getText());
64 this.question.setUserID(q.getUserID());
65
66 this.answers = new ArrayList<Answer>(ans.size());
67 for (Answer a : ans) {
68 Answer newAns = new Answer();
69 newAns.setAnswerID(a.getAnswerID());
70 newAns.setIsCorrect(a.getIsCorrect());
71 newAns.setQuestionID(a.getQuestionID());
72 newAns.setText(a.getText());
73 this.answers.add(newAns);
74 }
75 }
76
77 public Question question;
78 public ArrayList<Answer> answers;
79 }
80
81
82
83
84 private ArrayList<QuestionAnswers> questions;
85
86 private Connection con;
87
88 private BufferedWriter heveaInput;
89 private BufferedReader heveaOutput;
90 private BufferedReader heveaERR;
91 private Process heveaProc;
92
93 private static String nl = System.getProperty("line.separator");
94
95 private StringBuffer heveaOutputData;
96
97 public ExportMoodle() {
98 super();
99 setOutputFilename("export-moodle.xml");
100 }
101
102 @Override
103 public void exportQuestions(ArrayList<Question> questions, Connection con)
104 throws IOException, ExportException {
105 try {
106 this.con = con;
107
108 convertToHTML(questions);
109
110 Document xmldoc = new DocumentImpl();
111 Node root = xmldoc.createElement("quiz");
112
113 int num = 1;
114 for (QuestionAnswers q : this.questions) {
115 Element e = createQuestionXMLElement(q, xmldoc, num++);
116 root.appendChild(e);
117 }
118
119 xmldoc.appendChild(root);
120 OutputFormat of = new OutputFormat("XML", "UTF-8", true);
121 of.setIndent(1);
122 of.setIndenting(true);
123
124 XMLSerializer serializer = new XMLSerializer(new FileOutputStream(
125 getOutputFilename()), of);
126
127 serializer.asDOMSerializer();
128 serializer.serialize(xmldoc.getDocumentElement());
129
130 } catch (IOException e) {
131 System.err.println("Error running hevea/converting to HTML:" + e);
132 e.printStackTrace();
133 throw e;
134 }
135 }
136
137 @Override
138 public void exportTest(Integer testId, Connection con) throws IOException,
139 ExportException {
140
141 QuestionDao qDao = new QuestionDaoDerby(con);
142
143
144 try {
145 exportQuestions(qDao.getQuestionsByTestID(testId), con);
146 } catch (Exception e) {
147 }
148 }
149
150 @Override
151 public void exportTests(ArrayList<Integer> testIds, Connection con)
152 throws IOException, ExportException {
153 for (int tid : testIds)
154 exportTest(tid, con);
155 }
156
157
158
159
160
161
162
163
164
165
166
167
168 private void convertToHTML(ArrayList<Question> originalQ)
169 throws IOException {
170
171 heveaOutputData = new StringBuffer();
172 newHeveaProcess();
173 questions = new ArrayList<QuestionAnswers>(originalQ.size());
174
175 AnswerDao aDao = new AnswerDaoDerby(con);
176 int dataSize = 0;
177 for (int i = 0; i < originalQ.size(); i++) {
178 Question q = originalQ.get(i);
179 if (dataSize >= 10000) {
180 readHeveaOutput();
181 dataSize = 0;
182 newHeveaProcess();
183 }
184
185 heveaInput.write("=BEGINQ=");
186 heveaInput.write(nl);
187 heveaInput.write("=BEGINTEXT=");
188 heveaInput.write(nl);
189
190 heveaInput.write(q.getText().trim());
191 dataSize += q.getText().length();
192 heveaInput.write(nl);
193 heveaInput.write("=ENDTEXT=");
194 heveaInput.write(nl);
195
196
197 ArrayList<Answer> answers = null;
198 try {
199 answers = aDao.getAnswersByQuestionID(q.getQuestionID());
200 } catch (Exception e) {
201 }
202 questions.add(new QuestionAnswers(q, answers));
203
204 for (Answer a : answers) {
205 String text = a.getText();
206 heveaInput.write("=BEGINANS=");
207 heveaInput.write(nl);
208 heveaInput.write(text.trim());
209 dataSize += text.length();
210 heveaInput.write(nl);
211 heveaInput.write("=ENDANS=");
212 heveaInput.write(nl);
213
214 }
215
216 heveaInput.write("=ENDQ=");
217 heveaInput.write(nl);
218
219 heveaInput.flush();
220 }
221
222 readHeveaOutput();
223
224 parseHeveaOutput();
225 }
226
227
228
229
230
231
232 private void readHeveaOutput() throws IOException {
233 char c = 0;
234 heveaInput.close();
235 while (heveaERR.ready()) {
236 System.err.print((char) heveaERR.read());
237 }
238
239 while (heveaOutput.ready()) {
240 c = (char) heveaOutput.read();
241 heveaOutputData.append(c);
242 System.err.print(c);
243 }
244 heveaOutput.close();
245 heveaERR.close();
246 }
247
248
249
250
251
252
253 private void newHeveaProcess() throws IOException {
254 try {
255 heveaProc = Runtime.getRuntime().exec(
256 SettingsHelper.getSetting("hevea_path"));
257 heveaInput = new BufferedWriter(new OutputStreamWriter(heveaProc
258 .getOutputStream(),"UTF-8"));
259
260 heveaOutput = new BufferedReader(new InputStreamReader(heveaProc
261 .getInputStream()));
262
263 heveaERR = new BufferedReader(new InputStreamReader(heveaProc
264 .getErrorStream()));
265
266 ResourceHelper mh = new ResourceHelper();
267 String macros = mh.getMacros();
268
269 heveaInput.write(macros);
270 } catch (IOException e) {
271 System.err.println("HeVeA execution failed: " + e);
272 throw e;
273 }
274 }
275
276
277
278
279
280 private void parseHeveaOutput() throws IOException {
281 try {
282 BufferedReader dataSourceReader = new BufferedReader(
283 new StringReader(heveaOutputData.toString()));
284 String line = null;
285 int converted = 0;
286
287 while ((line = dataSourceReader.readLine()) != null) {
288 if ("=BEGINQ=".equals(line)) {
289
290 String tmpLine = dataSourceReader.readLine();
291 while (!"=BEGINTEXT=".equals(tmpLine)) {
292 tmpLine = dataSourceReader.readLine();
293 }
294
295 StringBuffer text = new StringBuffer();
296
297
298 while (!(tmpLine = dataSourceReader.readLine())
299 .contains("=ENDTEXT=")) {
300 text.append(tmpLine);
301 text.append(nl);
302 }
303
304 if (!tmpLine.equals("=ENDTEXT=")) {
305 text.append(tmpLine.replace("=ENDTEXT=", ""));
306 }
307
308 QuestionAnswers qa = questions.get(converted);
309 String tmp = text.toString();
310 if (tmp.contains("DIV CLASS=\"lstlisting\"")) {
311 tmp = tmp
312 .replace(
313 "DIV CLASS=\"lstlisting\"",
314 "DIV STYLE=\"font-family:monospace;white-space:pre;margin-right:auto;margin-left:0pt;text-align:left\"");
315 tmp = tmp.replace("/B> <B>", "/B> <B>");
316
317 }
318 qa.question.setText(tmp);
319 text = null;
320 int aNum = 0;
321
322 while (!(tmpLine = dataSourceReader.readLine())
323 .contains("=ENDQ=")) {
324
325 while (!"=BEGINANS=".equals(tmpLine)) {
326 tmpLine = dataSourceReader.readLine();
327 }
328 text = new StringBuffer();
329 while (!(tmpLine = dataSourceReader.readLine())
330 .contains("=ENDANS=")) {
331 text.append(tmpLine);
332 text.append(nl);
333 }
334 if (!tmpLine.equals("=ENDANS=")) {
335 text.append(tmpLine.replace("=ENDANS=", ""));
336 }
337 tmp = text.toString();
338 if (tmp.contains("DIV CLASS=\"lstlisting\"")) {
339 tmp = tmp
340 .replace(
341 "DIV CLASS=\"lstlisting\"",
342 "DIV STYLE=\"font-family:monospace;white-space:pre;margin-right:auto;margin-left:0pt;text-align:left\"");
343 tmp = tmp.replace("/B> <B>", "/B> <B>");
344 }
345
346 qa.answers.get(aNum++).setText(tmp);
347 text = null;
348 }
349
350 converted++;
351 }
352 }
353 } catch (IOException e) {
354 e.printStackTrace();
355 throw new IOException("Error parsing hevea output:" + e);
356 }
357
358 }
359
360
361
362
363
364
365
366
367
368
369
370 private Element createQuestionXMLElement(QuestionAnswers qa,
371 Document xmldoc, int num) throws ExportException {
372 PictureDao pDao = new PictureDaoDerby(con);
373
374 QuestionTypeDao qtDao = new QuestionTypeDaoDerby(con);
375 QuestionType qt = null;
376
377 try {
378 qt = qtDao.getQuestionTypeByQuestionID(qa.question.getQuestionID());
379 } catch (Exception e) {
380 }
381 String strQType = null;
382 if ("single choice".equalsIgnoreCase(qt.getName())
383 || "multi choice".equalsIgnoreCase(qt.getName())) {
384 strQType = new String("multichoice");
385 } else if ("true/false".equalsIgnoreCase(qt.getName())) {
386 strQType = new String("truefalse");
387 } else if ("fill in".equalsIgnoreCase(qt.getName())) {
388 strQType = new String("shortanswer");
389 } else if ("essay".equalsIgnoreCase(qt.getName())) {
390 strQType = new String("essay");
391 } else {
392 throw new ExportException("Unknown question type " + qt.getName()
393 + " for moodle export");
394 }
395 Element qElement = xmldoc.createElementNS(null, "question");
396 qElement.setAttribute("type", strQType);
397 Element qNameElement = xmldoc.createElementNS(null, "name");
398 Element textElement = xmldoc.createElementNS(null, "text");
399 textElement.appendChild(xmldoc.createTextNode("Otázka č. " + num));
400 qNameElement.appendChild(textElement);
401 qElement.appendChild(qNameElement);
402
403 Element qTextElement = xmldoc.createElementNS(null, "questiontext");
404 textElement = xmldoc.createElementNS(null, "text");
405 Node textNode = xmldoc.createTextNode(qa.question.getText());
406
407 textElement.appendChild(textNode);
408 qTextElement.appendChild(textElement);
409 qElement.appendChild(qTextElement);
410
411 int correct = 0;
412 for (Answer a : qa.answers) {
413 if (a.getIsCorrect()) {
414 correct++;
415 }
416 }
417
418 for (Answer a : qa.answers) {
419 Element aElement = xmldoc.createElementNS(null, "answer");
420 aElement.setAttribute("fraction", a.getIsCorrect() == true ? String
421 .valueOf(100 / correct) : "0");
422
423 textElement = xmldoc.createElementNS(null, "text");
424 textNode = xmldoc.createTextNode(a.getText());
425 textElement.appendChild(textNode);
426 aElement.appendChild(textElement);
427 qElement.appendChild(aElement);
428 }
429
430 ArrayList<Picture> pics = null;
431
432
433 try {
434 pics = pDao.getPicturesByQuestionID(qa.question.getQuestionID());
435 } catch (Exception e) {
436 }
437
438 for (Picture pic : pics) {
439 Element imageElement = xmldoc.createElementNS(null, "image");
440 textNode = xmldoc.createTextNode("genex-import/" + pic.getName());
441 imageElement.appendChild(textNode);
442 qElement.appendChild(imageElement);
443
444 Element imgDataElement = xmldoc.createElementNS(null,
445 "image_base64");
446 imgDataElement.appendChild(xmldoc.createTextNode(Base64
447 .encodeBytes(pic.getContent())));
448
449 qElement.appendChild(imgDataElement);
450 }
451
452 if ("multichoice".equalsIgnoreCase(strQType)) {
453 Element singleElement = xmldoc.createElementNS(null, "single");
454 if ("single choice".equalsIgnoreCase(qt.getName())) {
455 textNode = xmldoc.createTextNode("true");
456 } else {
457 textNode = xmldoc.createTextNode("false");
458 }
459 singleElement.appendChild(textNode);
460 qElement.appendChild(singleElement);
461 }
462
463 return qElement;
464 }
465 }