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%}

    - - - - - +
  • +
  • + +
      +
    • lala{%endif%} omfg - - +
    • +
    {%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 - - +
  • +
  • + +
      +
    • + lala
    {%endif%}
    • omfg +
    • +
    {%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