diff --git a/.gitignore b/.gitignore
index 7839e66..094e0eb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,13 @@
/build/
/.idea/
/logs/
+out/
document-service.jar
+**/.DS_Store
+.classpath
+.project
+.settings/
+bin/
# Ignore Gradle GUI config
gradle-app.setting
@@ -11,4 +17,4 @@ gradle-app.setting
!gradle-wrapper.jar
# Cache of project
-.gradletasknamecache
\ No newline at end of file
+.gradletasknamecache
diff --git a/build.gradle b/build.gradle
index 2a4ec7f..95dc8f2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,3 +1,7 @@
+plugins {
+ id "com.github.hierynomus.license" version "0.15.0"
+}
+
apply plugin: 'groovy'
apply plugin: 'java'
@@ -5,6 +9,7 @@ version = '1.0'
sourceCompatibility = 1.8
targetCompatibility = 1.8
+
allprojects {
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
diff --git a/client/cmd/bin/dsclient b/client/cmd/bin/dsclient
old mode 100644
new mode 100755
diff --git a/client/cmd/bin/dsclient.mac b/client/cmd/bin/dsclient.mac
old mode 100644
new mode 100755
diff --git a/conf.json b/conf.json
new file mode 100644
index 0000000..c669a8e
--- /dev/null
+++ b/conf.json
@@ -0,0 +1,24 @@
+{
+ "protocol":"http",
+ "host":"0.0.0.0",
+ "port":2115,
+ "tmpFolder":"docsCache",/** cache during a request, it will be deleted when the request is finished **/
+ "min": 10,/** min workers **/
+ "max": 100,/** max workers **/
+ "timeout":"30s",/** timeout duration **/
+ "logConfig":{
+ "level":"TRACE", /** OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL **/
+ "level_console":"DEBUG", /** OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL **/
+ "maxFileSize": "5MB",
+ "maxBackupIndex": 5,
+ "pattern": "%d{dd.MM.yyyy HH:mm:ss} %-5p %c{1}:%L - %m%n",
+ "filePath":"./logs/document-service.log"
+ },
+ "libreConfig":{
+ "librepath":"/Applications/LibreOffice.app/Contents/MacOS/soffice", /** the libreoffice executable folder path **/
+ "min" : 10, /** default 8 | min executables ready to be ready. An executable is mainly needed to convert to PDF. It is recommended to use one exe for a request at the time.**/
+ "max" : 100, /** default 40 | max capacity of executable running. The next request will be on hold until one is freed or until request timeout..**/
+ "highLoad": 55 /** highLoad defines the percentage of executables in use, when it is reached prepare new ones to be ready for high availability and fast response.**/
+ /** Please note! LibreOffice likes to fail sometimes, to have a stable failover, you might want to keep the highLoad value around 50% or even lower.**/
+ }
+}
\ No newline at end of file
diff --git a/doc/dependency_decisions.yml b/doc/dependency_decisions.yml
new file mode 100644
index 0000000..202f516
--- /dev/null
+++ b/doc/dependency_decisions.yml
@@ -0,0 +1,61 @@
+---
+- - :permit
+ - BSD
+ - :who:
+ :why:
+ :versions: []
+ :when: 2019-12-20 09:24:59.598985000 Z
+- - :permit
+ - MIT
+ - :who:
+ :why:
+ :versions: []
+ :when: 2019-12-20 09:25:04.086031000 Z
+- - :permit
+ - Apache 2.0
+ - :who:
+ :why:
+ :versions: []
+ :when: 2019-12-20 09:25:50.159396000 Z
+- - :permit
+ - Apache 2.0, Eclipse Public License - Version 1.0
+ - :who:
+ :why:
+ :versions: []
+ :when: 2019-12-20 09:26:16.280768000 Z
+- - :approve
+ - juh
+ - :who:
+ :why: LibreOffice MPL 2.0
+ :versions: []
+ :when: 2019-12-20 13:55:54.070224000 Z
+- - :approve
+ - jurt
+ - :who:
+ :why: LibreOffice MPL 2.0
+ :versions: []
+ :when: 2019-12-20 13:55:58.446785000 Z
+- - :approve
+ - ridl
+ - :who:
+ :why: LibreOffice MPL 2.0
+ :versions: []
+ :when: 2019-12-20 13:56:05.186925000 Z
+- - :approve
+ - unoil
+ - :who:
+ :why: LibreOffice MPL 2.0
+ :versions: []
+ :when: 2019-12-20 13:56:10.946673000 Z
+- - :approve
+ - javax.servlet-api
+ - :who:
+ :why: GPLv2 with CPE
+ :versions: []
+ :when: 2019-12-20 13:56:57.264730000 Z
+- - :approve
+ - jaxb-api
+ - :who:
+ :why: GPLv2 with CPE
+ :versions: []
+ :when: 2019-12-20 14:04:55.702653000 Z
diff --git a/gradlew b/gradlew
old mode 100644
new mode 100755
diff --git a/output.pdf b/output.pdf
new file mode 100644
index 0000000..ad4ee2f
Binary files /dev/null and b/output.pdf differ
diff --git a/src/main/java/com/proxeus/document/odt/ODTCompiler.java b/src/main/java/com/proxeus/document/odt/ODTCompiler.java
index 84212b9..badcb06 100644
--- a/src/main/java/com/proxeus/document/odt/ODTCompiler.java
+++ b/src/main/java/com/proxeus/document/odt/ODTCompiler.java
@@ -120,7 +120,8 @@ private FileResult compile(Template template, VarParser varParser) throws Except
return result;
} catch (Exception e) {
cfc.waitForImageTasksToFinish();
- throw new UnavailableException("LibreOffice error during convert to " + cfc.template.format + " please try again.");
+ e.printStackTrace();
+ throw new UnavailableException("LibreOffice error during convert to " + cfc.template.format + ": " + e.getMessage());
}
}
return null;
diff --git a/src/main/java/com/proxeus/office/libre/LibreConfig.java b/src/main/java/com/proxeus/office/libre/LibreConfig.java
index 8819887..6ded697 100644
--- a/src/main/java/com/proxeus/office/libre/LibreConfig.java
+++ b/src/main/java/com/proxeus/office/libre/LibreConfig.java
@@ -7,6 +7,7 @@
public class LibreConfig {
/**
* "/opt/libreoffice5.4/program" "C:/Program Files/LibreOffice 5/program" "/usr/lib/libreoffice/program"
+ * "/Applications/LibreOffice.app/Contents/MacOS/soffice"
**/
public String librepath = "/usr/lib/libreoffice/program";
/**
@@ -20,4 +21,4 @@ public class LibreConfig {
/** highLoad defines the percentage of executables in use, when it is reached prepare new ones to be ready for high availability and fast response.**/
public int highLoad = 60;
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/proxeus/office/libre/LibreOfficeAssistant.java b/src/main/java/com/proxeus/office/libre/LibreOfficeAssistant.java
index 397a329..521c918 100644
--- a/src/main/java/com/proxeus/office/libre/LibreOfficeAssistant.java
+++ b/src/main/java/com/proxeus/office/libre/LibreOfficeAssistant.java
@@ -51,13 +51,26 @@ public String Convert(File src, File dst, String format) throws Exception {
* @return contentType
*/
public String Convert(File src, File dst, String format, boolean newFontsInstalled) throws Exception {
+ LibreOffice lo = null;
+ try{
+ lo = libreOfficePool.take(newFontsInstalled);
+ newFontsInstalled = false;
+ }catch(Exception e){
+ throw new UnavailableException("Please try again later.", e);
+ }finally {
+ libreOfficePool.release();
+ }
+
+ if (lo == null){
+ throw new UnavailableException("Cannot initialize LibreOffice instance. Please try again later.");
+ }
+
int count = 0;
do{
try{
- LibreOffice lo = libreOfficePool.take(newFontsInstalled);
- newFontsInstalled = false;
return lo.Convert(src, dst, format);
}catch(ExceptionInInitializerError wiie){
+ wiie.printStackTrace();
++count;
}catch(Exception e){
throw new UnavailableException("Please try again later.", e);
@@ -65,7 +78,7 @@ public String Convert(File src, File dst, String format, boolean newFontsInstall
libreOfficePool.release();
}
}while(count < 10);
- throw new UnavailableException("Please try again later.");
+ throw new UnavailableException("Cannot initialize LibreOffice instance. Please try again later.");
}
/**
diff --git a/src/main/java/com/proxeus/office/libre/exe/LibreOffice.java b/src/main/java/com/proxeus/office/libre/exe/LibreOffice.java
index a4f1826..4ffc853 100644
--- a/src/main/java/com/proxeus/office/libre/exe/LibreOffice.java
+++ b/src/main/java/com/proxeus/office/libre/exe/LibreOffice.java
@@ -99,6 +99,7 @@ private void exportDocument(File src, File dst, LibreOfficeFormat outputFormat)
//InputStream input = new FileInputStream(src);
//OOInputStream ooInputStream = new OOInputStream(input);
String sUrl = src.toURI().toString();
+ System.out.println("DEBUG SURL: " + sUrl);
XComponent oDocToStore = null;
try {
oDocToStore = con.getCompLoader().loadComponentFromURL(sUrl, "_blank", 0, createProps(
@@ -111,10 +112,10 @@ private void exportDocument(File src, File dst, LibreOfficeFormat outputFormat)
));
if (oDocToStore == null) {
lastReconnect = -1;//force reconnect
- throw new ExceptionInInitializerError("Please try again later.");
+ throw new ExceptionInInitializerError("No doc to store. No Please try again later.");
}
} catch (NullPointerException eee) {
- throw new ExceptionInInitializerError("Please try again later.");
+ throw new ExceptionInInitializerError("Internal error. Please try again later.");
}
try {
diff --git a/src/main/java/com/proxeus/office/libre/exe/LibreOfficePool.java b/src/main/java/com/proxeus/office/libre/exe/LibreOfficePool.java
index 5a5349e..a18fea9 100644
--- a/src/main/java/com/proxeus/office/libre/exe/LibreOfficePool.java
+++ b/src/main/java/com/proxeus/office/libre/exe/LibreOfficePool.java
@@ -273,7 +273,7 @@ public LibreOffice take(boolean reconnect) throws Exception {
//looks like the service is under heavy load, lets throw and exceptions saying try again later
//holding the request longer doesn't make sense as it takes more resources
if (lo == null) {
- throw new UnavailableException("Please try again later.");
+ throw new UnavailableException("All LibreOffice instances busy. Please try again later.");
}
} else {
//try poll
@@ -282,7 +282,7 @@ public LibreOffice take(boolean reconnect) throws Exception {
offerNew();
lo = executables.poll(8, TimeUnit.SECONDS);
if (lo == null) {
- throw new UnavailableException("Please try again later.");
+ throw new UnavailableException("Cannot get LibreOffice instance. Please try again later.");
}
}
}
diff --git a/src/main/java/com/proxeus/xml/jtwig/ExtractorState.java b/src/main/java/com/proxeus/xml/jtwig/ExtractorState.java
new file mode 100644
index 0000000..18f4046
--- /dev/null
+++ b/src/main/java/com/proxeus/xml/jtwig/ExtractorState.java
@@ -0,0 +1,10 @@
+package com.proxeus.xml.jtwig;
+
+public enum ExtractorState {
+ XML,
+ MAYBE_BEGIN_ISLAND,
+ ISLAND,
+ SINGLE_QUOTE_STRING,
+ DOUBLE_QUOTE_STRING,
+ MAYBE_END_ISLAND,
+}
diff --git a/src/main/java/com/proxeus/xml/jtwig/ExtractorXMLEvent.java b/src/main/java/com/proxeus/xml/jtwig/ExtractorXMLEvent.java
new file mode 100644
index 0000000..ad18fac
--- /dev/null
+++ b/src/main/java/com/proxeus/xml/jtwig/ExtractorXMLEvent.java
@@ -0,0 +1,117 @@
+package com.proxeus.xml.jtwig;
+
+import sun.nio.cs.ext.ISCII91;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.Characters;
+import javax.xml.stream.events.EndElement;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+import java.io.Writer;
+
+public class ExtractorXMLEvent implements XMLEvent {
+
+ private XMLEvent event;
+ private ExtractorState state;
+ private IslandType islandType;
+
+ public ExtractorXMLEvent(XMLEvent event, ExtractorState state, IslandType islandType) {
+ this.event = event;
+ this.state = state;
+ this.islandType = islandType;
+ }
+
+ public XMLEvent getEvent() {
+ return event;
+ }
+
+ public ExtractorState getState() {
+ return state;
+ }
+
+ @Override
+ public int getEventType() {
+ return event.getEventType();
+ }
+
+ @Override
+ public Location getLocation() {
+ return event.getLocation();
+ }
+
+ @Override
+ public boolean isStartElement() {
+ return event.isStartElement();
+ }
+
+ @Override
+ public boolean isAttribute() {
+ return event.isAttribute();
+ }
+
+ @Override
+ public boolean isNamespace() {
+ return event.isNamespace();
+ }
+
+ @Override
+ public boolean isEndElement() {
+ return event.isEndElement();
+ }
+
+ @Override
+ public boolean isEntityReference() {
+ return event.isEntityReference();
+ }
+
+ @Override
+ public boolean isProcessingInstruction() {
+ return event.isProcessingInstruction();
+ }
+
+ @Override
+ public boolean isCharacters() {
+ return event.isCharacters();
+ }
+
+ @Override
+ public boolean isStartDocument() {
+ return event.isStartDocument();
+ }
+
+ @Override
+ public boolean isEndDocument() {
+ return event.isEndDocument();
+ }
+
+ @Override
+ public StartElement asStartElement() {
+ return event.asStartElement();
+ }
+
+ @Override
+ public EndElement asEndElement() {
+ return event.asEndElement();
+ }
+
+ @Override
+ public Characters asCharacters() {
+ return event.asCharacters();
+ }
+
+ @Override
+ public QName getSchemaType() {
+ return event.getSchemaType();
+ }
+
+ @Override
+ public void writeAsEncodedUnicode(Writer writer) throws XMLStreamException {
+ event.writeAsEncodedUnicode(writer);
+ }
+
+ public String toString() {
+ return event.toString();
+ }
+}
diff --git a/src/main/java/com/proxeus/xml/jtwig/IslandType.java b/src/main/java/com/proxeus/xml/jtwig/IslandType.java
new file mode 100644
index 0000000..dc2cd5f
--- /dev/null
+++ b/src/main/java/com/proxeus/xml/jtwig/IslandType.java
@@ -0,0 +1,7 @@
+package com.proxeus.xml.jtwig;
+
+public enum IslandType {
+ CODE,
+ OUTPUT,
+ COMMENT
+}
diff --git a/src/main/java/com/proxeus/xml/jtwig/XMLJTwigExtractor.java b/src/main/java/com/proxeus/xml/jtwig/XMLJTwigExtractor.java
new file mode 100644
index 0000000..ac5d432
--- /dev/null
+++ b/src/main/java/com/proxeus/xml/jtwig/XMLJTwigExtractor.java
@@ -0,0 +1,384 @@
+package com.proxeus.xml.jtwig;
+
+import java.io.OutputStream;
+
+import javax.xml.stream.*;
+import javax.xml.stream.events.*;
+
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+import static com.proxeus.xml.jtwig.ExtractorState.*;
+import static com.proxeus.xml.jtwig.IslandType.*;
+
+/**
+ * This class extract JTwig template code island (http://jtwig.org/documentation/reference/syntax/code-islands)
+ * located in the XML text nodes and transform the XML document to a JTwig template.
+ *
+ *
+ * First, we need to ensure that code islands do not contain any XML tags:
+ * * XML elements entirely inside a code island are deleted,
+ * * XML tags opening inside an island are push after the end of the code island,
+ * * XML tags closing inside code island are pull forward before the code island.
+ *
+ *
{@Code
+ * {%...........................%} {% ......%}
+ * ...
+ * .......... .......
+ * ... ..................
+ *
+ * will result in :
+ *
+ * {% ..........................%} {% ......%}
+ * ...
+ * ... ....
+ * ....
+ * }
+ *
+ *
+ * {@Code
+ * If an element span several code islands, we need to split them:
+ *
+ * {%..........%} {%..........%} {%.........%}
+ * ......................................................................
+ *
+ *
+ * will results in:
+ *
+ * {%..........%} {%..........%} {%.........%}
+ * ... ... ... ...
+ * }
+ *
+ * {@Code
+ * If an element span an output or a comment island, we do not need to split it:
+ *
+ * {{..........}} {%..........%} {#.........#}
+ * ......................................................................
+ *
+ * will results in:
+ *
+ * {{..........}} {%..........%} {#.........#}
+ * ......................... ........................
+ * }
+ */
+public class XMLJTwigExtractor {
+
+ private ExtractorState state;
+ private IslandType islandType;
+
+ private StringBuffer nextCharacters;
+ private StringBuffer whiteSpaces;
+ private StringBuffer nextIsland;
+ private LinkedList afterIsland;
+ private LinkedList beforeIsland;
+ private LinkedList waitQueue;
+ private LinkedList resultQueue;
+
+ private XMLEventFactory eventFactory;
+
+ // DEBUG
+ private StringBuffer allString;
+
+ public XMLJTwigExtractor() {
+ this.state = XML;
+ this.nextCharacters = new StringBuffer();
+ this.whiteSpaces = new StringBuffer();
+ this.nextIsland = new StringBuffer();
+
+ this.afterIsland = new LinkedList<>();
+ this.beforeIsland = new LinkedList<>();
+ this.waitQueue = new LinkedList<>();
+ this.resultQueue = new LinkedList<>();
+ this.eventFactory = XMLEventFactory.newInstance();
+
+ // DEBUG
+ this.allString = new StringBuffer();
+ }
+
+ @SuppressWarnings({"unchecked", "null"})
+ public void extract(XMLEventReader eventReader, OutputStream output) throws XMLStreamException, IllegalStateException {
+ while (eventReader.hasNext()) {
+ processEvent(eventReader.nextEvent());
+ }
+
+ System.out.println(allString.toString());
+
+ System.out.println();
+
+ XMLEventWriter ew = XMLOutputFactory.newInstance().createXMLEventWriter(output);
+ resultQueue.forEach(event -> {
+ try {
+ ew.add(event.getEvent());
+ } catch (XMLStreamException e) {
+
+ }
+ });
+ }
+
+ private void processEvent(XMLEvent event) throws XMLStreamException {
+ System.out.printf("<%s> <%s> <%s> ", state, islandType, eventType(event));
+
+ switch (event.getEventType()) {
+ case XMLEvent.START_DOCUMENT:
+ System.out.println();
+ resultQueue.add(new ExtractorXMLEvent(event, state, islandType));
+ resultQueue.add(new ExtractorXMLEvent(eventFactory.createCharacters("\n"), state, islandType));
+ break;
+
+ case XMLEvent.END_DOCUMENT:
+ System.out.println();
+ if (this.state != XML) {
+ throw new IllegalStateException("Template code island not terminated");
+ }
+ resultQueue.add(new ExtractorXMLEvent(event, state, islandType));
+ break;
+ case XMLEvent.START_ELEMENT:
+ StartElement start = event.asStartElement();
+ System.out.println("\t" + start.getName());
+ switch (state) {
+ case XML:
+ resultQueue.add(new ExtractorXMLEvent(event, state, islandType));
+ break;
+ case MAYBE_BEGIN_ISLAND:
+ System.out.printf("PUSH ************************* START_ELEMENT TO WAIT QUEUE %s\n", start.getName());
+ waitQueue.add(new ExtractorXMLEvent(event, state, islandType));
+ break;
+ case ISLAND:
+ System.out.printf("PUSH ************************* START_ELEMENT TO AFTER QUEUE %s\n", start.getName());
+ afterIsland.add(new ExtractorXMLEvent(event, state, islandType));
+ }
+ break;
+ case XMLEvent.END_ELEMENT:
+ EndElement end = event.asEndElement();
+ System.out.println("\t" + end.getName());
+ switch (state) {
+ case XML:
+ resultQueue.add(new ExtractorXMLEvent(event, state, islandType));
+ break;
+ case MAYBE_BEGIN_ISLAND:
+ System.out.printf("PUSH ************************* END_ELEMENT TO WAIT QUEUE %s\n", end.getName());
+ waitQueue.add(new ExtractorXMLEvent(event, state, islandType));
+ break;
+ case ISLAND:
+ System.out.printf("BEGIN ************************* END_ELEMENT IN ISLAND %s\n", end.getName());
+ ListIterator it = afterIsland.listIterator(0);
+ boolean ignore = false;
+ while (it.hasNext()) {
+ ExtractorXMLEvent e = it.next();
+ System.out.printf("In stack %s %d\n", e.toString(), e.getEventType());
+ if (!e.isStartElement()) {
+ continue;
+ }
+ StartElement s = e.asStartElement();
+ System.out.printf("start tag >%s< >%s<\n", s.getName(), end.getName());
+ if (s.getName().equals(end.getName())) {
+ System.out.printf("Match start tag %s\n", e.toString());
+ it.remove();
+ ignore = true;
+ break;
+ }
+ System.out.printf("Wrong start tag %s != %s\n", s.getName(), end.getName());
+ // A well formed XML file should not reach this line as the end element shoudl match
+ // the start element.
+ }
+ System.out.printf("END ************************* END_ELEMENT IN ISLAND %s\n", end.getName());
+ if (!ignore) {
+ System.out.printf("PUSH ************************* END_ELEMENT TO RESULT QUEUE %s\n", end.getName());
+ resultQueue.add(new ExtractorXMLEvent(event, state, islandType));
+ }
+ }
+
+ break;
+ case XMLEvent.CHARACTERS:
+ Characters c = event.asCharacters();
+ if (c.isIgnorableWhiteSpace()) {
+ resultQueue.add(new ExtractorXMLEvent(event, state, islandType));
+ break;
+ }
+ if (c.isCData()) {
+ resultQueue.add(new ExtractorXMLEvent(event, state, islandType));
+ break;
+ }
+ System.out.println();
+ System.out.println("-->" + c.getData() + "<--");
+
+ CharacterIterator it = new StringCharacterIterator(c.getData());
+ while (it.current() != CharacterIterator.DONE) {
+ switch (this.state) {
+ case XML:
+ switch (it.current()) {
+ case '{':
+ this.state = MAYBE_BEGIN_ISLAND;
+ nextIsland.append(it.current());
+ break;
+ default:
+ nextCharacters.append(it.current());
+ }
+ break;
+ case MAYBE_BEGIN_ISLAND:
+ /*if (Character.isWhitespace(it.current())) {
+ whiteSpaces.append(it.current());
+ break;
+ }
+ */
+
+ switch (it.current()) {
+ case '%':
+ this.state = ISLAND;
+ this.islandType = CODE;
+ processWaitQueue();
+ nextIsland.append(it.current());
+ // whiteSpaces.delete(0, whiteSpaces.length());
+ break;
+ case '{':
+ this.state = ISLAND;
+ this.islandType = OUTPUT;
+ processWaitQueue();
+ nextIsland.append(it.current());
+ // whiteSpaces.delete(0, whiteSpaces.length());
+ break;
+ case '#':
+ this.state = ISLAND;
+ this.islandType = COMMENT;
+ processWaitQueue();
+ nextIsland.append(it.current());
+ // whiteSpaces.delete(0, whiteSpaces.length());
+ break;
+ default:
+ this.state = XML;
+ // push nextIsland to result and reset island
+ // push any tags and reset stack
+ // deal with spaces
+ // current to next characters
+ nextCharacters.append(nextIsland);
+ nextIsland.delete(0, nextIsland.length());
+
+ if (afterIsland.size() > 0) {
+ resultQueue.add(new ExtractorXMLEvent(eventFactory.createCharacters(nextCharacters.toString()), state, islandType));
+ nextCharacters.delete(0, nextCharacters.length());
+ System.out.printf("PUSH ************************* BEFORE QUEUE TO RESULT QUEUE %s\n", afterIsland.toString());
+ resultQueue.addAll(waitQueue);
+ System.out.printf("RESULT QUEUE %s\n", resultQueue.toString());
+ waitQueue.clear();
+ }
+ // nextCharacters.append(whiteSpaces);
+ nextCharacters.append(it.current());
+
+ // whiteSpaces.delete(0, whiteSpaces.length());
+ }
+ break;
+ case ISLAND:
+ if (Character.isWhitespace(it.current())) {
+ if (!Character.isWhitespace(nextIsland.charAt(nextIsland.length() - 1))) {
+ nextIsland.append(' ');
+ }
+ } else {
+ nextIsland.append(it.current());
+ }
+ switch (it.current()) {
+ case '%':
+ if (this.islandType == CODE) {
+ this.state = MAYBE_END_ISLAND;
+ }
+ break;
+ case '}':
+ if (this.islandType == OUTPUT) {
+ this.state = MAYBE_END_ISLAND;
+ }
+ break;
+ case '#':
+ if (this.islandType == COMMENT) {
+ this.state = MAYBE_END_ISLAND;
+ }
+ break;
+ case '"':
+ this.state = DOUBLE_QUOTE_STRING;
+ break;
+ case '\'':
+ this.state = SINGLE_QUOTE_STRING;
+ }
+ break;
+ case DOUBLE_QUOTE_STRING:
+ nextIsland.append(it.current());
+ switch (it.current()) {
+ case '"':
+ this.state = ISLAND;
+ }
+ break;
+ case SINGLE_QUOTE_STRING:
+ nextIsland.append(it.current());
+ switch (it.current()) {
+ case '\'':
+ this.state = ISLAND;
+ }
+ break;
+ case MAYBE_END_ISLAND:
+ /* if (Character.isWhitespace(it.current())) {
+ whiteSpaces.append(it.current());
+ break;
+ }
+ */
+
+ switch (it.current()) {
+ case '}':
+ this.state = XML;
+ //whiteSpaces.delete(0, whiteSpaces.length());
+ nextIsland.append(it.current());
+ nextCharacters.append(nextIsland);
+ nextIsland.delete(0, nextIsland.length());
+
+ if (afterIsland.size() > 0) {
+ resultQueue.add(new ExtractorXMLEvent(eventFactory.createCharacters(nextCharacters.toString()), state, islandType));
+ nextCharacters.delete(0, nextCharacters.length());
+ System.out.printf("PUSH ************************* AFTER QUEUE TO RESULT QUEUE %s\n", afterIsland.toString());
+ resultQueue.addAll(afterIsland);
+ System.out.printf("RESULT QUEUE %s\n", resultQueue.toString());
+ afterIsland.clear();
+ }
+
+ break;
+ default:
+ this.state = ISLAND;
+ //nextIsland.append(whiteSpaces);
+ //whiteSpaces.delete(0, whiteSpaces.length());
+ nextIsland.append(it.current());
+ }
+ }
+ it.next();
+ }
+ if (nextCharacters.length() > 0) {
+ resultQueue.add(new ExtractorXMLEvent(eventFactory.createCharacters(nextCharacters.toString()), state, islandType));
+ nextCharacters.delete(0, nextCharacters.length());
+ }
+ default:
+ }
+ }
+
+ private void processWaitQueue() throws XMLStreamException {
+ System.out.printf("BEGIN ************************* ************************* PROCESSING WAIT QUEUE %s before %s after: %s\n", waitQueue.toString(), beforeIsland.toString(), afterIsland.toString());
+ for (ExtractorXMLEvent e : waitQueue) {
+ processEvent(e.getEvent());
+ }
+ System.out.printf("END ************************* ************************* PROCESSING WAIT QUEUE %s\n", resultQueue.toString());
+ waitQueue.clear();
+ }
+
+ private String eventType(XMLEvent event) {
+ switch (event.getEventType()) {
+ case XMLEvent.START_DOCUMENT:
+ return "START DOCUMENT";
+ case XMLEvent.END_DOCUMENT:
+ return "END DOCUMENT";
+ case XMLEvent.START_ELEMENT:
+ return "START ELEMENT";
+ case XMLEvent.END_ELEMENT:
+ return "END ELEMENT";
+ case XMLEvent.CHARACTERS:
+ return "CHARACTERS";
+ default:
+ return "UNKNOWN";
+ }
+ }
+}
diff --git a/src/main/resources/conf.json b/src/main/resources/conf.json
index 14b1333..c5be5e9 100644
--- a/src/main/resources/conf.json
+++ b/src/main/resources/conf.json
@@ -7,7 +7,7 @@
"max": 100,/** max workers **/
"timeout":"30s",/** timeout duration **/
"logConfig":{
- "level":"INFO", /** OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL **/
+ "level":"TRACE", /** OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL **/
"level_console":"DEBUG", /** OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL **/
"maxFileSize": "5MB",
"maxBackupIndex": 5,
diff --git a/src/test/java/com/proxeus/document/TemplateCompilerTest.java b/src/test/java/com/proxeus/document/TemplateCompilerTest.java
new file mode 100644
index 0000000..59a1132
--- /dev/null
+++ b/src/test/java/com/proxeus/document/TemplateCompilerTest.java
@@ -0,0 +1,155 @@
+package com.proxeus.document;
+
+import com.proxeus.document.FileResult;
+import com.proxeus.document.Template;
+import com.proxeus.document.TemplateCompiler;
+import com.proxeus.compiler.jtwig.MyJTwigCompiler;
+import com.proxeus.document.odt.ODTCompiler;
+import com.proxeus.office.libre.LibreConfig;
+import com.proxeus.office.libre.LibreOfficeAssistant;
+import com.proxeus.Application;
+import com.proxeus.Config;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/*
+ *
+ *
+
+ public class LibreConfig {
+ * "/opt/libreoffice5.4/program" "C:/Program Files/LibreOffice 5/program" "/usr/lib/libreoffice/program"
+ public String librepath = "/usr/lib/libreoffice/program";
+ * min executables ready to be ready. An executable is mainly needed to convert to PDF. It is recommended to use one exe for a request at the time.
+ public int min = 8;
+ * max capacity of executable running. The next request will be on hold until one is freed or until request timeout.
+ public int max = 40;
+
+ public int highLoad = 60;
+}
+ *
+ * package com.proxeus.document;
+
+import com.proxeus.compiler.jtwig.MyJTwigCompiler;
+import com.proxeus.document.docx.DOCXCompiler;
+import com.proxeus.document.odt.ODTCompiler;
+import com.proxeus.error.BadRequestException;
+import com.proxeus.office.libre.LibreOfficeAssistant;
+import com.proxeus.office.microsoft.MicrosoftOfficeAssistant;
+import com.proxeus.util.Json;
+import com.proxeus.util.zip.EntryFilter;
+import com.proxeus.util.zip.Zip;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+
+import static com.proxeus.document.TemplateType.DOCX;
+import static com.proxeus.document.TemplateType.ODT;
+
+
+public class TemplateCompiler {
+ private ODTCompiler odtCompiler;
+ private DOCXCompiler docxCompiler;
+ private MyJTwigCompiler compiler;
+
+ public TemplateCompiler(String cacheFolder, LibreOfficeAssistant libreOfficeAssistant) throws Exception{
+ compiler = new MyJTwigCompiler();
+ odtCompiler = new ODTCompiler(cacheFolder, compiler, libreOfficeAssistant);
+ docxCompiler = new DOCXCompiler(cacheFolder, compiler, new MicrosoftOfficeAssistant());
+ }
+
+ public FileResult compile(InputStream zipStream, String format, boolean embedError) throws Exception{
+ Template template = provideTemplateFromZIP(zipStream, format);
+ template.embedError = embedError;
+ return getCompiler(template).Compile(template);
+ }
+
+
+ post("/compile", (request, response) -> {
+ try {
+ StopWatch sw = StopWatch.createStarted();
+ FileResult result = templateCompiler.compile(request.raw().getInputStream(), request.queryParams("format"), request.queryMap().hasKey("error"));
+ response.header("Content-Type", result.contentType);
+ response.header("Content-Length", "" + result.target.length());
+ try {
+ streamAndClose(new FileInputStream(result.target), response.raw().getOutputStream());
+ } finally {
+ result.release();
+ }
+ System.out.println("request took: " + sw.getTime(TimeUnit.MILLISECONDS));
+ } catch(EofException | MultipartStream.MalformedStreamException eof){
+ try{
+ response.raw().getOutputStream().close();
+ }catch (Exception idc){}
+ } catch (CompilationException e) {
+ error(422, response, e);
+ } catch (BadRequestException e) {
+ error(HttpURLConnection.HTTP_BAD_REQUEST, response, e);
+ } catch (NotImplementedException e) {
+ error(HttpURLConnection.HTTP_NOT_IMPLEMENTED, response, e);
+ } catch (UnavailableException e) {
+ error(HttpURLConnection.HTTP_UNAVAILABLE, response, e);
+ } catch (Exception e) {
+ error(HttpURLConnection.HTTP_INTERNAL_ERROR, response, e);
+ }
+ return 0;
+ });
+
+*/
+
+public class TemplateCompilerTest {
+ private LibreOfficeAssistant libreOfficeAssistant;
+ private TemplateCompiler templateCompiler;
+
+ @Test
+ public void testCompile() throws Exception {
+
+ Config config = Application.init();
+ libreOfficeAssistant = new LibreOfficeAssistant(Config.by(LibreConfig.class));
+ templateCompiler = new TemplateCompiler(config.getTmpFolder(), libreOfficeAssistant);
+
+ InputStream inputStream = new ByteArrayInputStream(createZip());
+
+ FileResult result = templateCompiler.compile(inputStream, "pdf", true);
+ System.out.println(result.target.getAbsolutePath());
+ }
+
+ private byte[] createZip() throws Exception {
+ List srcFiles = Arrays.asList("simple.odt", "simple.json");
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ ZipOutputStream zipOut = new ZipOutputStream(os);
+ for (String srcFile : srcFiles) {
+ System.out.println(srcFile);
+ InputStream fis = getClass().getClassLoader().getResourceAsStream(srcFile);
+ ZipEntry zipEntry = new ZipEntry(srcFile);
+ zipOut.putNextEntry(zipEntry);
+
+ byte[] bytes = new byte[1024];
+ int length;
+ while((length = fis.read(bytes)) >= 0) {
+ zipOut.write(bytes, 0, length);
+ }
+ fis.close();
+ }
+ zipOut.close();
+
+ return os.toByteArray();
+ }
+}
diff --git a/src/test/java/com/proxeus/document/odt/ODTCompilerTest.java b/src/test/java/com/proxeus/document/odt/ODTCompilerTest.java
new file mode 100644
index 0000000..789cb5a
--- /dev/null
+++ b/src/test/java/com/proxeus/document/odt/ODTCompilerTest.java
@@ -0,0 +1,97 @@
+package com.proxeus.document.odt;
+
+import com.proxeus.document.FileResult;
+import com.proxeus.document.Template;
+import com.proxeus.document.TemplateCompiler;
+import com.proxeus.compiler.jtwig.MyJTwigCompiler;
+import com.proxeus.document.odt.ODTCompiler;
+import com.proxeus.office.libre.LibreConfig;
+import com.proxeus.office.libre.LibreOfficeAssistant;
+
+import com.proxeus.Config;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.List;
+
+/*
+ *
+ *
+
+ public class LibreConfig {
+ * "/opt/libreoffice5.4/program" "C:/Program Files/LibreOffice 5/program" "/usr/lib/libreoffice/program"
+ public String librepath = "/usr/lib/libreoffice/program";
+ * min executables ready to be ready. An executable is mainly needed to convert to PDF. It is recommended to use one exe for a request at the time.
+ public int min = 8;
+ * max capacity of executable running. The next request will be on hold until one is freed or until request timeout.
+ public int max = 40;
+
+ public int highLoad = 60;
+}
+ *
+ * package com.proxeus.document;
+
+import com.proxeus.compiler.jtwig.MyJTwigCompiler;
+import com.proxeus.document.docx.DOCXCompiler;
+import com.proxeus.document.odt.ODTCompiler;
+import com.proxeus.error.BadRequestException;
+import com.proxeus.office.libre.LibreOfficeAssistant;
+import com.proxeus.office.microsoft.MicrosoftOfficeAssistant;
+import com.proxeus.util.Json;
+import com.proxeus.util.zip.EntryFilter;
+import com.proxeus.util.zip.Zip;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+
+import static com.proxeus.document.TemplateType.DOCX;
+import static com.proxeus.document.TemplateType.ODT;
+
+
+public class TemplateCompiler {
+ private ODTCompiler odtCompiler;
+ private DOCXCompiler docxCompiler;
+ private MyJTwigCompiler compiler;
+
+ public TemplateCompiler(String cacheFolder, LibreOfficeAssistant libreOfficeAssistant) throws Exception{
+ compiler = new MyJTwigCompiler();
+ odtCompiler = new ODTCompiler(cacheFolder, compiler, libreOfficeAssistant);
+ docxCompiler = new DOCXCompiler(cacheFolder, compiler, new MicrosoftOfficeAssistant());
+ }
+
+ public FileResult compile(InputStream zipStream, String format, boolean embedError) throws Exception{
+ Template template = provideTemplateFromZIP(zipStream, format);
+ template.embedError = embedError;
+ return getCompiler(template).Compile(template);
+ }
+
+*/
+
+public class ODTCompilerTest {
+/*
+ private ODTCompiler odtCompiler;
+
+ @Test
+ public void testCompile() throws Exception {
+ MyJTwigCompiler compiler = new MyJTwigCompiler();
+
+ LibreConfig config = new LibreConfig();
+ config.librepath = "/Applications/LibreOffice.app/Contents/MacOS/soffice";
+ LibreOfficeAssistant libreOfficeAssistant = new LibreOfficeAssistant(Config.by(LibreConfig.class));
+
+ odtCompiler = new ODTCompiler("/tmp", compiler, libreOfficeAssistant);
+ Template template = provideTemplateFromZIP(zipStream, format);
+
+ FileResult result = odtCompiler.Compile(template);
+
+ }
+ */
+}
diff --git a/src/test/java/com/proxeus/xml/XmlTemplateHandlerTest.java b/src/test/java/com/proxeus/xml/XmlTemplateHandlerTest.java
index 5f4e1b7..10ad604 100644
--- a/src/test/java/com/proxeus/xml/XmlTemplateHandlerTest.java
+++ b/src/test/java/com/proxeus/xml/XmlTemplateHandlerTest.java
@@ -8,10 +8,46 @@
import java.util.List;
public class XmlTemplateHandlerTest {
+ //@Test
+ public void parseODTXml() throws Exception{
+ XmlTemplateHandler expected = getXmlTemplateFixer2("odt_content_fixed.xml");
+ XmlTemplateHandler mxf = getXmlTemplateFixer2("odt_content.xml");
+ String fixed_template_with_code = expected.toString();
+ mxf.fixCodeStructures();
+ String fixed = mxf.toString();
+ System.out.println(fixed);
+ Assert.assertEquals(fixed_template_with_code, fixed);
+
+ }
+
+ //@Test
+ public void parseODTBodyXml() throws Exception{
+ XmlTemplateHandler expected = getXmlTemplateFixer2("odt_body_fixed.xml");
+ XmlTemplateHandler mxf = getXmlTemplateFixer2("odt_body.xml");
+ String fixed_template_with_code = expected.toString();
+ mxf.fixCodeStructures();
+ String fixed = mxf.toString();
+ System.out.println(fixed);
+ Assert.assertEquals(fixed_template_with_code, fixed);
+
+ }
+
+ @Test
+ public void parseIfStatementXml() throws Exception{
+ XmlTemplateHandler expected = getXmlTemplateFixer2("if_statement_fixed.xml");
+ XmlTemplateHandler mxf = getXmlTemplateFixer2("if_statement.xml");
+ String fixed_template_with_code = expected.toString();
+ mxf.fixCodeStructures();
+ String fixed = mxf.toString();
+ System.out.println(fixed);
+ Assert.assertEquals(fixed_template_with_code, fixed);
+
+ }
+
@Test
public void fixCodeStructures() throws Exception {
- XmlTemplateHandler expected = getXmlTemplateFixer2("fixed_template_with_code.xml");
- XmlTemplateHandler mxf = getXmlTemplateFixer2("malformed_template_with_code.xml");
+ XmlTemplateHandler expected = getXmlTemplateFixer2("template_with_code_fixed.xml");
+ XmlTemplateHandler mxf = getXmlTemplateFixer2("template_with_code.xml");
String fixed_template_with_code = expected.toString();
List imgEles = mxf.findElementsByName("imgele");
imgEles.get(0).attr("name:var", "img123");
@@ -20,6 +56,17 @@ public void fixCodeStructures() throws Exception {
Assert.assertEquals(fixed_template_with_code, fixed);
}
+ @Test
+ public void fixCodeStructures2() throws Exception {
+ XmlTemplateHandler expected = getXmlTemplateFixer2("template_with_code2_fixed.xml");
+ XmlTemplateHandler mxf = getXmlTemplateFixer2("template_with_code2.xml");
+ String fixed_template_with_code = expected.toString();
+ mxf.fixCodeStructures();
+ String fixed = mxf.toString();
+ System.out.println(fixed);
+ Assert.assertEquals(fixed_template_with_code, fixed);
+ }
+
@Test
public void findElementsByNameFromRoot() throws Exception {
XmlTemplateHandler mxf = getXmlTemplateFixer();
@@ -93,7 +140,8 @@ private XmlTemplateHandler getXmlTemplateFixer2(String filename) throws Exceptio
Config configTryToPlaceCodeMoreSuitable = new Config();
configTryToPlaceCodeMoreSuitable.FixCodeByFindingTheNextCommonParent = true;
configTryToPlaceCodeMoreSuitable.AddTryToWrapXMLTagWithCode("for", "table:table-row");
- configTryToPlaceCodeMoreSuitable.Fix_XMLTags = false;
+ configTryToPlaceCodeMoreSuitable.Fix_XMLTags = true;
+ configTryToPlaceCodeMoreSuitable.Fix_RemoveXMLStartTagsWithoutEndTags=true;
return new XmlTemplateHandler(configTryToPlaceCodeMoreSuitable, TemplateCompiler.class.getClassLoader().getResourceAsStream(filename));
}
diff --git a/src/test/java/com/proxeus/xml/jtwig/XmlJTwigExtractorTest.java b/src/test/java/com/proxeus/xml/jtwig/XmlJTwigExtractorTest.java
new file mode 100644
index 0000000..b293eb8
--- /dev/null
+++ b/src/test/java/com/proxeus/xml/jtwig/XmlJTwigExtractorTest.java
@@ -0,0 +1,70 @@
+package com.proxeus.xml.jtwig;
+
+import com.proxeus.document.TemplateCompiler;
+import com.proxeus.xml.Config;
+import com.proxeus.xml.Element;
+import com.proxeus.xml.Node;
+import com.proxeus.xml.XmlTemplateHandler;
+import org.apache.commons.io.IOUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import sun.jvm.hotspot.interpreter.BytecodeStream;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import java.io.*;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class XmlJTwigExtractorTest {
+
+ @Test
+ public void xmlTagsInIsland() {
+
+ List tests = Arrays.asList(
+ //"xml_tags_in_island",
+ //"template_with_code2",
+ "template_with_code"
+ );
+
+ for (String test : tests) {
+ XMLJTwigExtractor extractor = new XMLJTwigExtractor();
+
+ InputStream input = XMLJTwigExtractor.class.getClassLoader().getResourceAsStream(test + ".xml");
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+
+ // First, create a new XMLInputFactory
+ XMLInputFactory inputFactory = XMLInputFactory.newInstance();
+ // Setup a new eventReader
+
+ try {
+ XMLEventReader eventReader = inputFactory.createXMLEventReader(input);
+ extractor.extract(eventReader, output);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ System.out.println(output.toString());
+
+ try {
+ InputStream expected = XMLJTwigExtractor.class.getClassLoader().getResourceAsStream(test + "_fixed.xml");
+ Assert.assertEquals(convert(expected, Charset.defaultCharset()), output.toString());
+ } catch (IOException e) {
+
+ }
+
+ }
+
+
+ }
+
+ private String convert(InputStream inputStream, Charset charset) throws IOException {
+
+ try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, charset))) {
+ return br.lines().collect(Collectors.joining(System.lineSeparator()));
+ }
+ }
+}
diff --git a/src/test/resources/.~lock.simple.odt# b/src/test/resources/.~lock.simple.odt#
new file mode 100644
index 0000000..72383f1
--- /dev/null
+++ b/src/test/resources/.~lock.simple.odt#
@@ -0,0 +1 @@
+,emeka,Emekas-MacBook-Pro.local,11.02.2020 10:50,file:///Users/emeka/Library/Application%20Support/LibreOffice/4;
\ No newline at end of file
diff --git a/src/test/resources/conf.json b/src/test/resources/conf.json
new file mode 100644
index 0000000..fdecafb
--- /dev/null
+++ b/src/test/resources/conf.json
@@ -0,0 +1,24 @@
+{
+ "protocol":"http",
+ "host":"0.0.0.0",
+ "port":2115,
+ "tmpFolder":"docsCache",/** cache during a request, it will be deleted when the request is finished **/
+ "min": 10,/** min workers **/
+ "max": 100,/** max workers **/
+ "timeout":"30s",/** timeout duration **/
+ "logConfig":{
+ "level":"INFO", /** OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL **/
+ "level_console":"DEBUG", /** OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL **/
+ "maxFileSize": "5MB",
+ "maxBackupIndex": 5,
+ "pattern": "%d{dd.MM.yyyy HH:mm:ss} %-5p %c{1}:%L - %m%n",
+ "filePath":"./logs/document-service.log"
+ },
+ "libreConfig":{
+ "librepath":"/Applications/LibreOffice.app/Contents/MacOS/soffice", /** the libreoffice executable folder path **/
+ "min" : 10, /** default 8 | min executables ready to be ready. An executable is mainly needed to convert to PDF. It is recommended to use one exe for a request at the time.**/
+ "max" : 100, /** default 40 | max capacity of executable running. The next request will be on hold until one is freed or until request timeout..**/
+ "highLoad": 55 /** highLoad defines the percentage of executables in use, when it is reached prepare new ones to be ready for high availability and fast response.**/
+ /** Please note! LibreOffice likes to fail sometimes, to have a stable failover, you might want to keep the highLoad value around 50% or even lower.**/
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/if_statement.xml b/src/test/resources/if_statement.xml
new file mode 100644
index 0000000..c5818f5
--- /dev/null
+++ b/src/test/resources/if_statement.xml
@@ -0,0 +1,31 @@
+
+
+
+
+ {
+
+ %
+ if input.PurposeDETemplate == 'Other %}'
+ %}
+
+ {{
+
+ input.PurposeDE
+
+ }} {
+
+ %
+ else
+ %}
+
+ {{
+
+ input.PurposeDETemplate
+
+ }} {
+
+ %
+ endif
+ %}
+
+
diff --git a/src/test/resources/if_statement_fixed.xml b/src/test/resources/if_statement_fixed.xml
new file mode 100644
index 0000000..da919e4
--- /dev/null
+++ b/src/test/resources/if_statement_fixed.xml
@@ -0,0 +1,31 @@
+
+
+
+
+ {
+
+ %
+ if input.PurposeDETemplate == ‘Other‘
+ %}
+
+ {{
+
+ input.PurposeDE
+
+ }} {
+
+ %
+ else
+ %}
+
+ {{
+
+ input.PurposeDETemplate
+
+ }} {
+
+ %
+ endif
+ %}
+
+
diff --git a/src/test/resources/input1.xml b/src/test/resources/input1.xml
new file mode 100644
index 0000000..767f284
--- /dev/null
+++ b/src/test/resources/input1.xml
@@ -0,0 +1,30 @@
+
+
+
+ {
+
+ %
+ if input.PurposeDETemplate == ‘Other‘
+ %}
+
+ {{
+
+ input.PurposeDE
+
+ }} {
+
+ %
+ else
+ %}
+
+ {{
+
+ input.PurposeDETemplate
+
+ }} {
+
+ %
+ endif
+ %}
+
+
\ No newline at end of file
diff --git a/src/test/resources/input1_fixed.xml b/src/test/resources/input1_fixed.xml
new file mode 100644
index 0000000..518c711
--- /dev/null
+++ b/src/test/resources/input1_fixed.xml
@@ -0,0 +1,17 @@
+
+
+ {% if input.PurposeDETemplate == ‘Other‘ %}
+
+
+ {{ input.PurposeDE }}
+
+
+ { % else %}
+
+
+ {{ input.PurposeDETemplate }}
+
+
+ {% endif %}
+
+
diff --git a/src/test/resources/odt_body.xml b/src/test/resources/odt_body.xml
new file mode 100644
index 0000000..f2f3079
--- /dev/null
+++ b/src/test/resources/odt_body.xml
@@ -0,0 +1,197 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Anmeldung an das Handelsregisteramt
+
+
+
+
+
+ Zur Eintragung in das Handelsregister wird folgende Neueintragung angemeldet:
+
+
+
+
+
+
+
+
+
+
+ Firma
+
+
+
+
+
+ {{
+
+ input.FirmaGerman
+
+ }}
+
+
+
+
+
+
+ AG
+
+
+
+
+
+
+
+ Übersetzungen der Firma
+
+
+
+
+ {{
+
+ input.FirmaGerman
+
+ }} SA
+
+
+
+
+
+
+ {{
+
+ input.FirmaGerman
+
+ }} Ltd
+
+
+
+
+
+
+
+ Sitz
+
+
+
+
+ {{
+
+ input.HeadquarterRegisteredOffice
+
+ }} / {{
+
+ input.HeadquarterCanton
+
+ }}
+
+
+
+
+
+
+
+ Domizil
+
+
+
+
+ {{
+
+ input.HeadquarterZIP
+
+ }} {{
+
+ input.HeadquarterCity
+
+ }}, {{
+
+ input.HeadquarterStreet
+
+ }} {{
+
+ input.HeadquarterStreetNumber
+
+ }} (eigenes Rechtsdomizil)
+
+
+
+
+
+
+
+ Rechtsform
+
+
+ Aktiengesellschaft
+
+
+
+
+
+ Statutendatum
+
+
+
+
+ {{
+
+ input.DateOfStatutes
+
+ }}
+
+
+
+
+
+
+
+ Zweck
+
+
+
+
+ {
+
+ %
+ if input.PurposeDETemplate == ‘Other‘
+ %}
+
+ {{
+
+ input.PurposeDE
+
+ }} {
+
+ %
+ else
+ %}
+
+ {{
+
+ input.PurposeDETemplate
+
+ }} {
+
+ %
+ endif
+ %}
+
+
+
+
+
+
+
+
+
diff --git a/src/test/resources/odt_body_fixed.xml b/src/test/resources/odt_body_fixed.xml
new file mode 100644
index 0000000..99cc5e3
--- /dev/null
+++ b/src/test/resources/odt_body_fixed.xml
@@ -0,0 +1,197 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Anmeldung an das Handelsregisteramt
+
+
+
+
+
+ Zur Eintragung in das Handelsregister wird folgende Neueintragung angemeldet:
+
+
+
+
+
+
+
+
+
+
+ Firma
+
+
+
+
+
+ {{
+
+ input.FirmaGerman
+
+ }}
+
+
+
+
+
+
+ AG
+
+
+
+
+
+
+
+ Übersetzungen der Firma
+
+
+
+
+ {{
+
+ input.FirmaGerman
+
+ }} SA
+
+
+
+
+
+
+ {{
+
+ input.FirmaGerman
+
+ }} Ltd
+
+
+
+
+
+
+
+ Sitz
+
+
+
+
+ {{
+
+ input.HeadquarterRegisteredOffice
+
+ }} / {{
+
+ input.HeadquarterCanton
+
+ }}
+
+
+
+
+
+
+
+ Domizil
+
+
+
+
+ {{
+
+ input.HeadquarterZIP
+
+ }} {{
+
+ input.HeadquarterCity
+
+ }}, {{
+
+ input.HeadquarterStreet
+
+ }} {{
+
+ input.HeadquarterStreetNumber
+
+ }} (eigenes Rechtsdomizil)
+
+
+
+
+
+
+
+ Rechtsform
+
+
+ Aktiengesellschaft
+
+
+
+
+
+ Statutendatum
+
+
+
+
+ {{
+
+ input.DateOfStatutes
+
+ }}
+
+
+
+
+
+
+
+ Zweck
+
+
+
+
+ {
+
+ %
+ if input.PurposeDETemplate == ‘Other‘
+ %}
+
+ {{
+
+ input.PurposeDE
+
+ }} {
+
+ %
+ else
+ %}
+
+ {{
+
+ input.PurposeDETemplate
+
+ }} {
+
+ %
+ endif
+ %}
+
+
+
+
+
+
+
+
+
diff --git a/src/test/resources/odt_content.xml b/src/test/resources/odt_content.xml
new file mode 100644
index 0000000..f86b549
--- /dev/null
+++ b/src/test/resources/odt_content.xml
@@ -0,0 +1,765 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Anmeldung an das Handelsregisteramt
+
+
+
+
+
+ Zur Eintragung in das Handelsregister wird folgende Neueintragung angemeldet:
+
+
+
+
+
+
+
+
+
+
+ Firma
+
+
+
+
+
+ {{
+
+ input.FirmaGerman
+
+ }}
+
+
+
+
+
+
+ AG
+
+
+
+
+
+
+
+ Übersetzungen der Firma
+
+
+
+
+ {{
+
+ input.FirmaGerman
+
+ }} SA
+
+
+
+
+
+
+ {{
+
+ input.FirmaGerman
+
+ }} Ltd
+
+
+
+
+
+
+
+ Sitz
+
+
+
+
+ {{
+
+ input.HeadquarterRegisteredOffice
+
+ }} / {{
+
+ input.HeadquarterCanton
+
+ }}
+
+
+
+
+
+
+
+ Domizil
+
+
+
+
+ {{
+
+ input.HeadquarterZIP
+
+ }} {{
+
+ input.HeadquarterCity
+
+ }}, {{
+
+ input.HeadquarterStreet
+
+ }} {{
+
+ input.HeadquarterStreetNumber
+
+ }} (eigenes Rechtsdomizil)
+
+
+
+
+
+
+
+ Rechtsform
+
+
+ Aktiengesellschaft
+
+
+
+
+
+ Statutendatum
+
+
+
+
+ {{
+
+ input.DateOfStatutes
+
+ }}
+
+
+
+
+
+
+
+ Zweck
+
+
+
+
+ {
+
+ %
+ if input.PurposeDETemplate == ‘Other‘
+ %}
+
+ {{
+
+ input.PurposeDE
+
+ }} {
+
+ %
+ else
+ %}
+
+ {{
+
+ input.PurposeDETemplate
+
+ }} {
+
+ %
+ endif
+ %}
+
+
+
+
+
+
+
+
+
diff --git a/src/test/resources/odt_content_fixed.xml b/src/test/resources/odt_content_fixed.xml
new file mode 100644
index 0000000..c7a08d4
--- /dev/null
+++ b/src/test/resources/odt_content_fixed.xml
@@ -0,0 +1,765 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Anmeldung an das Handelsregisteramt
+
+
+
+
+
+ Zur Eintragung in das Handelsregister wird folgende Neueintragung angemeldet:
+
+
+
+
+
+
+
+
+
+
+ Firma
+
+
+
+
+
+ {{
+
+ input.FirmaGerman
+
+ }}
+
+
+
+
+
+
+ AG
+
+
+
+
+
+
+
+ Übersetzungen der Firma
+
+
+
+
+ {{
+
+ input.FirmaGerman
+
+ }} SA
+
+
+
+
+
+
+ {{
+
+ input.FirmaGerman
+
+ }} Ltd
+
+
+
+
+
+
+
+ Sitz
+
+
+
+
+ {{
+
+ input.HeadquarterRegisteredOffice
+
+ }} / {{
+
+ input.HeadquarterCanton
+
+ }}
+
+
+
+
+
+
+
+ Domizil
+
+
+
+
+ {{
+
+ input.HeadquarterZIP
+
+ }} {{
+
+ input.HeadquarterCity
+
+ }}, {{
+
+ input.HeadquarterStreet
+
+ }} {{
+
+ input.HeadquarterStreetNumber
+
+ }} (eigenes Rechtsdomizil)
+
+
+
+
+
+
+
+ Rechtsform
+
+
+ Aktiengesellschaft
+
+
+
+
+
+ Statutendatum
+
+
+
+
+ {{
+
+ input.DateOfStatutes
+
+ }}
+
+
+
+
+
+
+
+ Zweck
+
+
+
+
+ {
+
+ %
+ if input.PurposeDETemplate == ‘Other‘
+ %}
+
+ {{
+
+ input.PurposeDE
+
+ }} {
+
+ %
+ else
+ %}
+
+ {{
+
+ input.PurposeDETemplate
+
+ }} {
+
+ %
+ endif
+ %}
+
+
+
+
+
+
+
+
+
diff --git a/src/test/resources/simple.json b/src/test/resources/simple.json
new file mode 100644
index 0000000..dacfe6d
--- /dev/null
+++ b/src/test/resources/simple.json
@@ -0,0 +1,14 @@
+{
+ "input":{
+ "FirmaGerman":"testfirma",
+ "HeadquarterRegisteredOffice":"testoffice",
+ "HeadquarterCanton":"testcanton",
+ "HeadquarterZip":"testzip",
+ "HeadquarterCity":"testcity",
+ "HeadquarterStreet":"teststreet",
+ "HeadquarterStreetNumber":"testnumber",
+ "DateOfStatues":"testdos",
+ "PurposeDETemplate":"Other",
+ "PurposeDE":"testpurposede"
+ }
+}
diff --git a/src/test/resources/simple.odt b/src/test/resources/simple.odt
new file mode 100644
index 0000000..84ba08f
Binary files /dev/null and b/src/test/resources/simple.odt differ
diff --git a/src/test/resources/malformed_template_with_code.xml b/src/test/resources/template_with_code.xml
similarity index 61%
rename from src/test/resources/malformed_template_with_code.xml
rename to src/test/resources/template_with_code.xml
index 2a8adab..8f3b79b 100644
--- a/src/test/resources/malformed_template_with_code.xml
+++ b/src/test/resources/template_with_code.xml
@@ -1,31 +1,31 @@
-
+
àààääää
{% set abc = "% } {{}}" %}
{% set abc2 = [] %}
-
+ -
{%if (true)%}
before if{%if (false)%} after if
-
-
+
+ -
before elseif{%elseif (false) %} after elseif
-
-
+
+ -
before else{%else%} after else
{%if input.IntendedDeliveryDate == ‘Specific Date‘ %}
{{input.SpecificDate}}{%else%}
{{input.DeliveryWeek}}
{%endif%}
-
-
-
-
-
+
+ -
+
+
-
+
+
{%endif%}
-
-
+
+
diff --git a/src/test/resources/template_with_code2.xml b/src/test/resources/template_with_code2.xml
new file mode 100644
index 0000000..8919c4c
--- /dev/null
+++ b/src/test/resources/template_with_code2.xml
@@ -0,0 +1,6 @@
+
+
+ {% set abc="% } {{}}" %}
+ {% if abc=="% } {{}}" %}
+
+
diff --git a/src/test/resources/template_with_code2_fixed.xml b/src/test/resources/template_with_code2_fixed.xml
new file mode 100644
index 0000000..8bbb801
--- /dev/null
+++ b/src/test/resources/template_with_code2_fixed.xml
@@ -0,0 +1,5 @@
+
+
+ {% set abc="% } {{}}" %}
+ {% if abc=="% } {{}}" %}
+
diff --git a/src/test/resources/fixed_template_with_code.xml b/src/test/resources/template_with_code_fixed.xml
similarity index 54%
rename from src/test/resources/fixed_template_with_code.xml
rename to src/test/resources/template_with_code_fixed.xml
index ae1a3c6..69f9e09 100644
--- a/src/test/resources/fixed_template_with_code.xml
+++ b/src/test/resources/template_with_code_fixed.xml
@@ -1,30 +1,30 @@
-
+
àààääää
{% set abc = "% } {{}}" %}
{% set abc2 = [] %}
-
+ -
{%if (true)%}
before if{%if (false)%} after if
-
-
+
+ -
before elseif{%elseif (false) %} after elseif
-
-
+
+ -
before else{%else%} after else
{%if input.IntendedDeliveryDate == 'Specific Date' %}
{{input.SpecificDate}}
{%else%}{{input.DeliveryWeek}}
{%endif%}
-
-
-
-
-
- lala{%endif%} omfg
-
-
+
+ -
+
+ {%endif%}
{%endif%}
-
-
+
+
diff --git a/src/test/resources/xml_tags_in_island.xml b/src/test/resources/xml_tags_in_island.xml
new file mode 100644
index 0000000..3e2975c
--- /dev/null
+++ b/src/test/resources/xml_tags_in_island.xml
@@ -0,0 +1,15 @@
+
+
+ first line
+
+ second line
+
+
+ third line
+ {% if
+
+
+ foobar barfoo %}
+ fourth line
+ fifth line {% endif %}
+
\ No newline at end of file
diff --git a/src/test/resources/xml_tags_in_island_fixed.xml b/src/test/resources/xml_tags_in_island_fixed.xml
new file mode 100644
index 0000000..8dea3c1
--- /dev/null
+++ b/src/test/resources/xml_tags_in_island_fixed.xml
@@ -0,0 +1,12 @@
+
+
+ first line
+
+ second line
+
+
+ third line
+ {% if foobar barfoo %}
+ fourth line
+ fifth line {% endif %}
+
\ No newline at end of file
diff --git a/test.odt b/test.odt
new file mode 100644
index 0000000..49a7acd
Binary files /dev/null and b/test.odt differ