From 594ae5a2259db832e984f5c9d6bd23689f2ec89e Mon Sep 17 00:00:00 2001 From: arolfes Date: Wed, 25 Oct 2023 21:54:23 +0200 Subject: [PATCH] very dirty hack to make the taskana-routing-rest module work again as long as a newer release of dmn-xlsx-converter is missing, we need to care that the underlying docx4j version is using jakarta instead of javax So all classes are copied from this PR https://github.com/camunda-community-hub/camunda-dmn-xlsx/pull/53 --- pom.xml | 9 +- routing/dmn-xlsx-converter/LEGAL_NOTICE.md | 16 ++ routing/dmn-xlsx-converter/LICENSE | 202 ++++++++++++++++ routing/dmn-xlsx-converter/README.md | 16 ++ routing/dmn-xlsx-converter/pom.xml | 118 +++++++++ .../dmn/xlsx/AdvancedSpreadsheetAdapter.java | 101 ++++++++ .../org/camunda/bpm/dmn/xlsx/BaseAdapter.java | 32 +++ .../bpm/dmn/xlsx/CellContentHandler.java | 30 +++ .../bpm/dmn/xlsx/DmnConversionContext.java | 50 ++++ .../bpm/dmn/xlsx/DmnValueNumberConverter.java | 33 +++ .../bpm/dmn/xlsx/DmnValueRangeConverter.java | 49 ++++ .../bpm/dmn/xlsx/DmnValueStringConverter.java | 34 +++ .../xlsx/FeelSimpleUnaryTestConverter.java | 40 +++ .../bpm/dmn/xlsx/InputOutputColumns.java | 47 ++++ .../SimpleInputOutputDetectionStrategy.java | 73 ++++++ .../StaticInputOutputDetectionStrategy.java | 77 ++++++ .../camunda/bpm/dmn/xlsx/XlsxConverter.java | 85 +++++++ .../bpm/dmn/xlsx/XlsxWorksheetContext.java | 81 +++++++ .../bpm/dmn/xlsx/XlsxWorksheetConverter.java | 228 ++++++++++++++++++ .../camunda/bpm/dmn/xlsx/api/Spreadsheet.java | 24 ++ .../bpm/dmn/xlsx/api/SpreadsheetAdapter.java | 45 ++++ .../bpm/dmn/xlsx/api/SpreadsheetCell.java | 27 +++ .../bpm/dmn/xlsx/api/SpreadsheetRow.java | 33 +++ .../bpm/dmn/xlsx/elements/CellHelper.java | 18 ++ .../xlsx/elements/HeaderValuesContainer.java | 77 ++++++ .../bpm/dmn/xlsx/elements/IndexedCell.java | 57 +++++ .../dmn/xlsx/elements/IndexedDmnColumns.java | 59 +++++ .../bpm/dmn/xlsx/elements/IndexedRow.java | 77 ++++++ .../dmn/xlsx/DmnValueRangeMatcherTest.java | 53 ++++ .../InputOutputDetectionStrategyTest.java | 45 ++++ .../org/camunda/bpm/dmn/xlsx/TestHelper.java | 46 ++++ .../bpm/dmn/xlsx/XslxToDmnConversionTest.java | 170 +++++++++++++ .../src/test/resources/log4j2-test.xml | 16 ++ .../src/test/resources/test1.xlsx | Bin 0 -> 8221 bytes .../src/test/resources/test2.xlsx | Bin 0 -> 8258 bytes .../src/test/resources/test3.xlsx | Bin 0 -> 8252 bytes .../src/test/resources/test4.xlsx | Bin 0 -> 4785 bytes .../src/test/resources/test5.xlsx | Bin 0 -> 8216 bytes .../src/test/resources/test6.xlsx | Bin 0 -> 9571 bytes routing/pom.xml | 1 + routing/taskana-routing-rest/pom.xml | 1 + 41 files changed, 2069 insertions(+), 1 deletion(-) create mode 100644 routing/dmn-xlsx-converter/LEGAL_NOTICE.md create mode 100644 routing/dmn-xlsx-converter/LICENSE create mode 100644 routing/dmn-xlsx-converter/README.md create mode 100644 routing/dmn-xlsx-converter/pom.xml create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/AdvancedSpreadsheetAdapter.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/BaseAdapter.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/CellContentHandler.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/DmnConversionContext.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/DmnValueNumberConverter.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/DmnValueRangeConverter.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/DmnValueStringConverter.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/FeelSimpleUnaryTestConverter.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/InputOutputColumns.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/SimpleInputOutputDetectionStrategy.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/StaticInputOutputDetectionStrategy.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/XlsxConverter.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/XlsxWorksheetContext.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/XlsxWorksheetConverter.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/api/Spreadsheet.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/api/SpreadsheetAdapter.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/api/SpreadsheetCell.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/api/SpreadsheetRow.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/CellHelper.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/HeaderValuesContainer.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/IndexedCell.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/IndexedDmnColumns.java create mode 100644 routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/IndexedRow.java create mode 100644 routing/dmn-xlsx-converter/src/test/java/org/camunda/bpm/dmn/xlsx/DmnValueRangeMatcherTest.java create mode 100644 routing/dmn-xlsx-converter/src/test/java/org/camunda/bpm/dmn/xlsx/InputOutputDetectionStrategyTest.java create mode 100644 routing/dmn-xlsx-converter/src/test/java/org/camunda/bpm/dmn/xlsx/TestHelper.java create mode 100644 routing/dmn-xlsx-converter/src/test/java/org/camunda/bpm/dmn/xlsx/XslxToDmnConversionTest.java create mode 100644 routing/dmn-xlsx-converter/src/test/resources/log4j2-test.xml create mode 100644 routing/dmn-xlsx-converter/src/test/resources/test1.xlsx create mode 100644 routing/dmn-xlsx-converter/src/test/resources/test2.xlsx create mode 100644 routing/dmn-xlsx-converter/src/test/resources/test3.xlsx create mode 100644 routing/dmn-xlsx-converter/src/test/resources/test4.xlsx create mode 100644 routing/dmn-xlsx-converter/src/test/resources/test5.xlsx create mode 100644 routing/dmn-xlsx-converter/src/test/resources/test6.xlsx diff --git a/pom.xml b/pom.xml index 055ee6d556..5f4e722675 100644 --- a/pom.xml +++ b/pom.xml @@ -96,7 +96,13 @@ 1.9.20.1 - 0.3.0 + + 0.4.0-taskana-patch + + 11.4.9 4.0.1 4.0.3 4.0.3 @@ -352,6 +358,7 @@ true warning true + **/org/camunda/bpm/dmn/**/* diff --git a/routing/dmn-xlsx-converter/LEGAL_NOTICE.md b/routing/dmn-xlsx-converter/LEGAL_NOTICE.md new file mode 100644 index 0000000000..85818394f9 --- /dev/null +++ b/routing/dmn-xlsx-converter/LEGAL_NOTICE.md @@ -0,0 +1,16 @@ +This Module is a clone of Projekt Module +[camunda-dmn-xlsx:xlsx-dmn-converter](https://github.com/camunda-community-hub/camunda-dmn-xlsx/tree/master/xlsx-dmn-converter) + +The original project is licensed under APACHE LICENSE Version 2. + +All changes to the code are included in this PR: https://github.com/camunda-community-hub/camunda-dmn-xlsx/pull/53 + +The changes were necessary so that there is a version compatible with jakarta-xml-bind and this version can be used with Camunda. + +The main changes were: + +* Upgrade of lib `org.docx4j:docx4j:6.0.1` to `org.docx4j:docx4j-JAXB-ReferenceImpl:11.4.9` +* In class `org.camunda.bpm.dmn.xlsx.XlsxConverter` and `org.camunda.bpm.dmn.xlsx.XlsxWorksheetConverter` a new parameter was introduced: `historyTimeToLive` + * because camunda-engine with version 7.20.X requires a timeToLive for history of decisions + * default timeToLive is 180 days + * the new parameter is set during execution of convert method to the created decisons diff --git a/routing/dmn-xlsx-converter/LICENSE b/routing/dmn-xlsx-converter/LICENSE new file mode 100644 index 0000000000..7a4a3ea242 --- /dev/null +++ b/routing/dmn-xlsx-converter/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/routing/dmn-xlsx-converter/README.md b/routing/dmn-xlsx-converter/README.md new file mode 100644 index 0000000000..2138fa8e16 --- /dev/null +++ b/routing/dmn-xlsx-converter/README.md @@ -0,0 +1,16 @@ +This Module is a clone of Projekt Module +[camunda-dmn-xlsx:xlsx-dmn-converter](https://github.com/camunda-community-hub/camunda-dmn-xlsx/tree/master/xlsx-dmn-converter) + +The original project is licensed under APACHE LICENSE Version 2. + +All changes to the code are included in this PR: https://github.com/camunda-community-hub/camunda-dmn-xlsx/pull/53 + +The changes were necessary so that there is a version compatible with jakarta-xml-bind and this version can be used with Camunda. + +The main changes were: + +* Upgrade of lib `org.docx4j:docx4j:6.0.1` to `org.docx4j:docx4j-JAXB-ReferenceImpl:11.4.9` +* In class `org.camunda.bpm.dmn.xlsx.XlsxConverter` and `org.camunda.bpm.dmn.xlsx.XlsxWorksheetConverter` a new parameter was introduced: `historyTimeToLive` + * because camunda-engine with version 7.20.X requires a timeToLive for history of decisions + * default timeToLive is 180 days + * the new parameter is set during execution of convert method to the created decisons diff --git a/routing/dmn-xlsx-converter/pom.xml b/routing/dmn-xlsx-converter/pom.xml new file mode 100644 index 0000000000..1afd1c1b75 --- /dev/null +++ b/routing/dmn-xlsx-converter/pom.xml @@ -0,0 +1,118 @@ + + + 4.0.0 + org.camunda.bpm.extension.dmn + dmn-xlsx-converter + ${version.dmn-xlsx-converter} + DMN-XLSX Converter + jar + + + pro.taskana + taskana-routing-parent + 8.0.0-SNAPSHOT + ../pom.xml + + + + + org.docx4j + docx4j-JAXB-ReferenceImpl + ${version.docx4j} + + + + org.camunda.bpm.model + camunda-dmn-model + ${version.camunda.dmn} + + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-params + test + + + + org.assertj + assertj-core + test + + + + org.apache.logging.log4j + log4j-api + test + + + org.apache.logging.log4j + log4j-core + test + + + org.apache.logging.log4j + log4j-slf4j2-impl + test + + + + + + + org.codehaus.mojo + aspectj-maven-plugin + + true + + + + org.apache.maven.plugins + maven-resources-plugin + ${version.maven.resources} + + + copy-license-to-classes-folder + process-test-classes + + copy-resources + + + + ${project.build.directory}/classes + + + + . + + LICENSE + + + + . + + LEGAL_NOTICE.md + + + + . + + README.md + + + + + + + + + + + diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/AdvancedSpreadsheetAdapter.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/AdvancedSpreadsheetAdapter.java new file mode 100644 index 0000000000..b91f910b2b --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/AdvancedSpreadsheetAdapter.java @@ -0,0 +1,101 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import org.camunda.bpm.dmn.xlsx.api.Spreadsheet; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetCell; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetRow; +import org.camunda.bpm.dmn.xlsx.elements.HeaderValuesContainer; +import org.camunda.bpm.model.dmn.HitPolicy; + +public class AdvancedSpreadsheetAdapter extends BaseAdapter { + + public InputOutputColumns determineInputOutputs(Spreadsheet context) { + Set inputColumns = new LinkedHashSet<>(); + Set outputColumns = new LinkedHashSet<>(); + + SpreadsheetRow headerRow = context.getRows().get(0); + + List cells = headerRow.getCells(); + + for (SpreadsheetCell indexedCell : cells) { + if("input".equalsIgnoreCase(context.resolveCellContent(indexedCell))) { + inputColumns.add(indexedCell.getColumn()); + } + if("output".equalsIgnoreCase(context.resolveCellContent(indexedCell))) { + outputColumns.add(indexedCell.getColumn()); + } + } + + InputOutputColumns columns = new InputOutputColumns(); + int idCounter = 0; + for (String column : inputColumns) { + idCounter++; + HeaderValuesContainer hvc = new HeaderValuesContainer(); + hvc.setId("input" + idCounter); + fillHvc(context, column, hvc); + columns.addInputHeader(hvc); + } + idCounter= 0; + for (String column : outputColumns) { + idCounter++; + HeaderValuesContainer hvc = new HeaderValuesContainer(); + hvc.setId("output" + idCounter); + fillHvc(context, column, hvc); + columns.addOutputHeader(hvc); + } + + return columns; + } + + public HitPolicy determineHitPolicy(Spreadsheet context) { + if (context.getRows().size() < 4) { + return null; + } + SpreadsheetRow row = context.getRows().get(4); + if (row.getCell("A") != null) { + final String hitPolicyString = context.resolveCellContent(row.getCell("A")).toUpperCase(); + return HitPolicy.valueOf(hitPolicyString); + } + else + { + return null; + } + } + + @Override + public List determineRuleRows(Spreadsheet context) { + List rows = context.getRows(); + return rows.subList(5, rows.size()); + } + + public int numberHeaderRows() { + return 5; + } + + private void fillHvc(Spreadsheet context, String column, HeaderValuesContainer hvc) { + SpreadsheetCell cell; + cell = context.getRows().get(1).getCell(column); + hvc.setLabel(context.resolveCellContent(cell)); + cell = context.getRows().get(2).getCell(column); + hvc.setExpressionLanguage(context.resolveCellContent(cell)); + cell = context.getRows().get(3).getCell(column); + hvc.setText(context.resolveCellContent(cell)); + cell = context.getRows().get(4).getCell(column); + hvc.setTypeRef(context.resolveCellContent(cell)); + hvc.setColumn(column); + } +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/BaseAdapter.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/BaseAdapter.java new file mode 100644 index 0000000000..ccb7053865 --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/BaseAdapter.java @@ -0,0 +1,32 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx; + +import java.util.List; +import org.camunda.bpm.dmn.xlsx.CellContentHandler; +import org.camunda.bpm.dmn.xlsx.api.Spreadsheet; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetAdapter; + +public abstract class BaseAdapter implements SpreadsheetAdapter { + + @Override + public String determineDecisionName(Spreadsheet context) { + return context.getName(); + } + + @Override + public List getCellContentHandlers( + Spreadsheet context) { + return CellContentHandler.DEFAULT_HANDLERS; + } +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/CellContentHandler.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/CellContentHandler.java new file mode 100644 index 0000000000..87fade6347 --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/CellContentHandler.java @@ -0,0 +1,30 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx; + +import java.util.ArrayList; +import java.util.List; +import org.camunda.bpm.dmn.xlsx.api.Spreadsheet; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetCell; + +/** + * @author Thorben Lindhauer + */ +public interface CellContentHandler { + + public static final List DEFAULT_HANDLERS = new ArrayList<>(); + + boolean canConvert(SpreadsheetCell cell, Spreadsheet spreadsheet); + + String convert(SpreadsheetCell cell, Spreadsheet spreadsheet); +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/DmnConversionContext.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/DmnConversionContext.java new file mode 100644 index 0000000000..af218a7ce5 --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/DmnConversionContext.java @@ -0,0 +1,50 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx; + +import java.util.List; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetCell; +import org.camunda.bpm.dmn.xlsx.elements.IndexedDmnColumns; + +/** + * @author Thorben Lindhauer + * + */ +public class DmnConversionContext { + + protected final List cellContentHandlers; + protected final org.camunda.bpm.dmn.xlsx.XlsxWorksheetContext worksheetContext; + + protected IndexedDmnColumns indexedDmnColumns = new IndexedDmnColumns(); + + public DmnConversionContext( + XlsxWorksheetContext worksheetContext, List cellContentHandlers) { + this.worksheetContext = worksheetContext; + this.cellContentHandlers = cellContentHandlers; + } + + public String resolveCellValue(SpreadsheetCell cell) { + for (CellContentHandler contentHandler : cellContentHandlers) { + if (contentHandler.canConvert(cell, worksheetContext)) { + return contentHandler.convert(cell, worksheetContext); + } + } + throw new RuntimeException("cannot parse cell content, unsupported format"); + + } + + public IndexedDmnColumns getIndexedDmnColumns() { + return indexedDmnColumns; + } + +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/DmnValueNumberConverter.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/DmnValueNumberConverter.java new file mode 100644 index 0000000000..c875f41758 --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/DmnValueNumberConverter.java @@ -0,0 +1,33 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx; + +import org.camunda.bpm.dmn.xlsx.api.Spreadsheet; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetCell; +import org.xlsx4j.sml.STCellType; + +/** + * @author Thorben Lindhauer + * + */ +public class DmnValueNumberConverter implements CellContentHandler { + + public boolean canConvert(SpreadsheetCell cell, Spreadsheet context) { + return STCellType.N.equals(cell.getRaw().getT()); + } + + public String convert(SpreadsheetCell cell, Spreadsheet context) { + return cell.getRaw().getV(); + } + +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/DmnValueRangeConverter.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/DmnValueRangeConverter.java new file mode 100644 index 0000000000..5c810660e6 --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/DmnValueRangeConverter.java @@ -0,0 +1,49 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx; + +import java.util.regex.Pattern; +import org.camunda.bpm.dmn.xlsx.api.Spreadsheet; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetCell; +import org.xlsx4j.sml.Cell; +import org.xlsx4j.sml.STCellType; + +/** + * @author Thorben Lindhauer + * + */ +public class DmnValueRangeConverter implements CellContentHandler { + + public static final Pattern RANGE_REGEX = Pattern.compile("[\\[\\]](?:[0-9.]+|(?:date and time\\(.+\\)))\\.\\.(?:[0-9.]+|(?:date and time\\(.+\\)))[\\[\\]]"); + + @Override + public boolean canConvert(SpreadsheetCell cell, Spreadsheet context) { + Cell rawCell = cell.getRaw(); + + if (STCellType.S.equals(rawCell.getT())) + { + String content = context.resolveCellContent(cell); + return RANGE_REGEX.matcher(content).matches(); + } + else + { + return false; + } + } + + @Override + public String convert(SpreadsheetCell cell, Spreadsheet context) { + return context.resolveCellContent(cell); + } + +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/DmnValueStringConverter.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/DmnValueStringConverter.java new file mode 100644 index 0000000000..8a9d797bbb --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/DmnValueStringConverter.java @@ -0,0 +1,34 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx; + +import org.camunda.bpm.dmn.xlsx.api.Spreadsheet; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetCell; +import org.xlsx4j.sml.STCellType; + +/** + * @author Thorben Lindhauer + */ +public class DmnValueStringConverter implements CellContentHandler { + + public static final DmnValueStringConverter INSTANCE = new DmnValueStringConverter(); + + public boolean canConvert(SpreadsheetCell cell, Spreadsheet context) { + return STCellType.S.equals(cell.getRaw().getT()); + } + + public String convert(SpreadsheetCell cell, Spreadsheet context) { + String content = context.resolveCellContent(cell); + return "\"" + content + "\""; + } +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/FeelSimpleUnaryTestConverter.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/FeelSimpleUnaryTestConverter.java new file mode 100644 index 0000000000..174a9a0ab1 --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/FeelSimpleUnaryTestConverter.java @@ -0,0 +1,40 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx; + +import org.camunda.bpm.dmn.xlsx.CellContentHandler; +import org.camunda.bpm.dmn.xlsx.api.Spreadsheet; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetCell; +import org.xlsx4j.sml.Cell; +import org.xlsx4j.sml.STCellType; + +/** + * @author Thorben Lindhauer + */ +public class FeelSimpleUnaryTestConverter implements CellContentHandler { + + public boolean canConvert(SpreadsheetCell cell, Spreadsheet context) { + Cell rawCell = cell.getRaw(); + + if (!STCellType.S.equals(rawCell.getT())) { + return false; + } + + String rawContent = context.resolveCellContent(cell); + return rawContent.startsWith(">") || rawContent.startsWith("<"); + } + + public String convert(SpreadsheetCell cell, Spreadsheet context) { + return context.resolveCellContent(cell); + } +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/InputOutputColumns.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/InputOutputColumns.java new file mode 100644 index 0000000000..541d969845 --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/InputOutputColumns.java @@ -0,0 +1,47 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx; + +import java.util.ArrayList; +import java.util.List; +import org.camunda.bpm.dmn.xlsx.elements.HeaderValuesContainer; + +/** + * @author Thorben Lindhauer + */ +public class InputOutputColumns { + + protected List inputHeaders; + protected List outputHeaders; + + public InputOutputColumns() { + this.inputHeaders = new ArrayList(); + this.outputHeaders = new ArrayList(); + } + + public void addOutputHeader(HeaderValuesContainer hvc) { + this.outputHeaders.add(hvc); + } + + public void addInputHeader(HeaderValuesContainer hvc) { + this.inputHeaders.add(hvc); + } + + public List getOutputHeaders() { + return outputHeaders; + } + + public List getInputHeaders() { + return inputHeaders; + } +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/SimpleInputOutputDetectionStrategy.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/SimpleInputOutputDetectionStrategy.java new file mode 100644 index 0000000000..0cb5cd6ee1 --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/SimpleInputOutputDetectionStrategy.java @@ -0,0 +1,73 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx; + +import java.util.List; +import org.camunda.bpm.dmn.xlsx.BaseAdapter; +import org.camunda.bpm.dmn.xlsx.InputOutputColumns; +import org.camunda.bpm.dmn.xlsx.api.Spreadsheet; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetCell; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetRow; +import org.camunda.bpm.dmn.xlsx.elements.HeaderValuesContainer; +import org.camunda.bpm.model.dmn.HitPolicy; + +/** + * @author Thorben Lindhauer + */ +public class SimpleInputOutputDetectionStrategy extends BaseAdapter { + + public org.camunda.bpm.dmn.xlsx.InputOutputColumns determineInputOutputs(Spreadsheet context) { + + SpreadsheetRow headerRow = context.getRows().get(0); + + if (!headerRow.hasCells()) { + throw new RuntimeException( + "A dmn table requires at least one output; the header row contains no entries"); + } + + org.camunda.bpm.dmn.xlsx.InputOutputColumns ioColumns = new InputOutputColumns(); + + List cells = headerRow.getCells(); + HeaderValuesContainer hvc = new HeaderValuesContainer(); + SpreadsheetCell outputCell = cells.get(cells.size() - 1); + fillHvc(outputCell, context, hvc); + hvc.setId("Output" + outputCell.getColumn()); + + ioColumns.addOutputHeader(hvc); + + for (SpreadsheetCell inputCell : cells.subList(0, cells.size() - 1)) { + hvc = new HeaderValuesContainer(); + fillHvc(inputCell, context, hvc); + hvc.setId("Input" + inputCell.getColumn()); + ioColumns.addInputHeader(hvc); + } + + return ioColumns; + } + + @Override + public HitPolicy determineHitPolicy(Spreadsheet context) { + return null; + } + + @Override + public List determineRuleRows(Spreadsheet context) { + List rows = context.getRows(); + return rows.subList(1, rows.size()); + } + + private void fillHvc(SpreadsheetCell cell, Spreadsheet context, HeaderValuesContainer hvc) { + hvc.setText(context.resolveCellContent(cell)); + hvc.setColumn(cell.getColumn()); + } +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/StaticInputOutputDetectionStrategy.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/StaticInputOutputDetectionStrategy.java new file mode 100644 index 0000000000..9337502ffa --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/StaticInputOutputDetectionStrategy.java @@ -0,0 +1,77 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx; + +import java.util.List; +import java.util.Set; +import org.camunda.bpm.dmn.xlsx.BaseAdapter; +import org.camunda.bpm.dmn.xlsx.InputOutputColumns; +import org.camunda.bpm.dmn.xlsx.api.Spreadsheet; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetCell; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetRow; +import org.camunda.bpm.dmn.xlsx.elements.HeaderValuesContainer; +import org.camunda.bpm.model.dmn.HitPolicy; + +/** + * @author Thorben Lindhauer + */ +public class StaticInputOutputDetectionStrategy extends BaseAdapter { + + protected Set inputColumns; + protected Set outputColumns; + + public StaticInputOutputDetectionStrategy(Set inputColumns, Set outputColumns) { + this.inputColumns = inputColumns; + this.outputColumns = outputColumns; + } + + public InputOutputColumns determineInputOutputs(Spreadsheet context) { + + SpreadsheetRow headerRow = context.getRows().get(0); + + InputOutputColumns columns = new InputOutputColumns(); + + HeaderValuesContainer hvc; + for (SpreadsheetCell cell : headerRow.getCells()) { + if (inputColumns.contains(cell.getColumn())) { + hvc = new HeaderValuesContainer(); + fillHvc(cell, context, hvc); + hvc.setId("Input" + cell.getColumn()); + columns.addInputHeader(hvc); + } else if (outputColumns.contains(cell.getColumn())) { + hvc = new HeaderValuesContainer(); + fillHvc(cell, context, hvc); + hvc.setId("Output" + cell.getColumn()); + columns.addOutputHeader(hvc); + } + } + + return columns; + } + + @Override + public HitPolicy determineHitPolicy(Spreadsheet context) { + return null; + } + + @Override + public List determineRuleRows(Spreadsheet context) { + List rows = context.getRows(); + return rows.subList(1, rows.size()); + } + + private void fillHvc(SpreadsheetCell cell, Spreadsheet context, HeaderValuesContainer hvc) { + hvc.setText(context.resolveCellContent(cell)); + hvc.setColumn(cell.getColumn()); + } +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/XlsxConverter.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/XlsxConverter.java new file mode 100644 index 0000000000..4a5cf4fcf2 --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/XlsxConverter.java @@ -0,0 +1,85 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx; + +import java.io.InputStream; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetAdapter; +import org.camunda.bpm.model.dmn.DmnModelInstance; +import org.docx4j.openpackaging.exceptions.Docx4JException; +import org.docx4j.openpackaging.packages.SpreadsheetMLPackage; +import org.docx4j.openpackaging.parts.DocPropsExtendedPart; +import org.docx4j.openpackaging.parts.SpreadsheetML.SharedStrings; +import org.docx4j.openpackaging.parts.SpreadsheetML.WorkbookPart; +import org.docx4j.openpackaging.parts.SpreadsheetML.WorksheetPart; + +/** + * @author Thorben Lindhauer + * + */ +public class XlsxConverter { + + public static final String DEFAULT_HISTORY_TIME_TO_LIVE = "P180D"; + + protected String historyTimeToLive = DEFAULT_HISTORY_TIME_TO_LIVE; + + protected SpreadsheetAdapter ioDetectionStrategy = new SimpleInputOutputDetectionStrategy(); + + public DmnModelInstance convert(InputStream inputStream) { + SpreadsheetMLPackage spreadSheetPackage = null; + try { + spreadSheetPackage = SpreadsheetMLPackage.load(inputStream); + } catch (Docx4JException e) { + // TODO: checked exception + throw new RuntimeException("cannot load document", e); + } + + WorkbookPart workbookPart = spreadSheetPackage.getWorkbookPart(); + // TODO: exception when no worksheet present + // TODO: make worksheet number configurable/import all worksheets? + org.camunda.bpm.dmn.xlsx.XlsxWorksheetContext worksheetContext = null; + + WorksheetPart worksheetPart; + try { + String worksheetName; + DocPropsExtendedPart docPropsExtendedPart = spreadSheetPackage.getDocPropsExtendedPart(); + if(docPropsExtendedPart!= null && docPropsExtendedPart.getContents().getTitlesOfParts() != null) { + worksheetName = (String) docPropsExtendedPart.getContents().getTitlesOfParts().getVector().getVariantOrI1OrI2().get(0).getValue(); + } else { + worksheetName = "default"; + } + worksheetPart = workbookPart.getWorksheet(0); + SharedStrings sharedStrings = workbookPart.getSharedStrings(); + worksheetContext = new XlsxWorksheetContext(sharedStrings.getContents(), worksheetPart.getContents(), worksheetName); + } catch (Exception e) { + throw new RuntimeException("Could not determine worksheet", e); + } + + return new XlsxWorksheetConverter(worksheetContext, ioDetectionStrategy, historyTimeToLive).convert(); + } + + public SpreadsheetAdapter getIoDetectionStrategy() { + return ioDetectionStrategy; + } + + public void setIoDetectionStrategy(SpreadsheetAdapter ioDetectionStrategy) { + this.ioDetectionStrategy = ioDetectionStrategy; + } + + public String getHistoryTimeToLive() { + return historyTimeToLive; + } + + public void setHistoryTimeToLive(String historyTimeToLive) { + this.historyTimeToLive = historyTimeToLive; + } +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/XlsxWorksheetContext.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/XlsxWorksheetContext.java new file mode 100644 index 0000000000..1cdd78e45c --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/XlsxWorksheetContext.java @@ -0,0 +1,81 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx; + +import java.util.ArrayList; +import java.util.List; +import org.camunda.bpm.dmn.xlsx.CellContentHandler; +import org.camunda.bpm.dmn.xlsx.api.Spreadsheet; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetCell; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetRow; +import org.camunda.bpm.dmn.xlsx.elements.IndexedRow; +import org.xlsx4j.sml.CTRst; +import org.xlsx4j.sml.CTSst; +import org.xlsx4j.sml.Cell; +import org.xlsx4j.sml.Row; +import org.xlsx4j.sml.STCellType; +import org.xlsx4j.sml.Worksheet; + +/** + * @author Thorben Lindhauer + */ +public class XlsxWorksheetContext implements Spreadsheet { + + protected List cellContentHandlers; + protected CTSst sharedStrings; + protected Worksheet worksheet; + protected String worksheetName; + + // cached state + protected List indexedRows; + + public XlsxWorksheetContext(CTSst sharedStrings, Worksheet worksheet, String worksheetName) { + this.sharedStrings = sharedStrings; + this.worksheet = worksheet; + this.cellContentHandlers = new ArrayList<>(); + this.worksheetName = worksheetName; + } + + public List getRows() { + if (indexedRows == null) { + indexedRows = new ArrayList<>(); + for (Row row : worksheet.getSheetData().getRow()) { + indexedRows.add(new IndexedRow(row)); + } + } + return indexedRows; + } + + public String resolveSharedString(int index) { + List siElements = sharedStrings.getSi(); + return siElements.get(index).getT().getValue(); + } + + @Override + public String resolveCellContent(SpreadsheetCell cell) { + Cell rawCell = cell.getRaw(); + + STCellType cellType = rawCell.getT(); + if (STCellType.S.equals(cellType)) { + int sharedStringIndex = Integer.parseInt(rawCell.getV()); + return resolveSharedString(sharedStringIndex); + } else { + return rawCell.getV(); + } + } + + @Override + public String getName() { + return worksheetName; + } +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/XlsxWorksheetConverter.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/XlsxWorksheetConverter.java new file mode 100644 index 0000000000..13e5f85c21 --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/XlsxWorksheetConverter.java @@ -0,0 +1,228 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx; + +import java.util.List; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetAdapter; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetCell; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetRow; +import org.camunda.bpm.dmn.xlsx.elements.HeaderValuesContainer; +import org.camunda.bpm.dmn.xlsx.elements.IndexedDmnColumns; +import org.camunda.bpm.model.dmn.Dmn; +import org.camunda.bpm.model.dmn.DmnModelInstance; +import org.camunda.bpm.model.dmn.HitPolicy; +import org.camunda.bpm.model.dmn.impl.DmnModelConstants; +import org.camunda.bpm.model.dmn.instance.Decision; +import org.camunda.bpm.model.dmn.instance.DecisionTable; +import org.camunda.bpm.model.dmn.instance.Definitions; +import org.camunda.bpm.model.dmn.instance.Description; +import org.camunda.bpm.model.dmn.instance.DmnElement; +import org.camunda.bpm.model.dmn.instance.Input; +import org.camunda.bpm.model.dmn.instance.InputEntry; +import org.camunda.bpm.model.dmn.instance.InputExpression; +import org.camunda.bpm.model.dmn.instance.NamedElement; +import org.camunda.bpm.model.dmn.instance.Output; +import org.camunda.bpm.model.dmn.instance.OutputEntry; +import org.camunda.bpm.model.dmn.instance.Rule; +import org.camunda.bpm.model.dmn.instance.Text; + +/** + * @author Thorben Lindhauer + */ +public class XlsxWorksheetConverter { + + static + { + org.camunda.bpm.dmn.xlsx.CellContentHandler.DEFAULT_HANDLERS.add(new DmnValueRangeConverter()); + org.camunda.bpm.dmn.xlsx.CellContentHandler.DEFAULT_HANDLERS.add(new FeelSimpleUnaryTestConverter()); + org.camunda.bpm.dmn.xlsx.CellContentHandler.DEFAULT_HANDLERS.add(new DmnValueStringConverter()); + CellContentHandler.DEFAULT_HANDLERS.add(new DmnValueNumberConverter()); + } + + protected final String historyTimeToLive; + + protected org.camunda.bpm.dmn.xlsx.XlsxWorksheetContext worksheetContext; + protected org.camunda.bpm.dmn.xlsx.DmnConversionContext dmnConversionContext; + protected SpreadsheetAdapter spreadsheetAdapter; + + public XlsxWorksheetConverter(XlsxWorksheetContext worksheetContext, SpreadsheetAdapter spreadsheetAdapter, String historyTimeToLive) { + this.worksheetContext = worksheetContext; + this.dmnConversionContext = new DmnConversionContext(worksheetContext, spreadsheetAdapter.getCellContentHandlers(worksheetContext)); + this.spreadsheetAdapter = spreadsheetAdapter; + this.historyTimeToLive = historyTimeToLive; + } + + public DmnModelInstance convert() { + + DmnModelInstance dmnModel = initializeEmptyDmnModel(); + + Decision decision = generateElement(dmnModel, Decision.class, worksheetContext.getName()); + decision.setName(spreadsheetAdapter.determineDecisionName(worksheetContext)); + decision.setCamundaHistoryTimeToLiveString(historyTimeToLive); + dmnModel.getDefinitions().addChildElement(decision); + + DecisionTable decisionTable = generateElement(dmnModel, DecisionTable.class, "decisionTable"); + decision.addChildElement(decisionTable); + + setHitPolicy(decisionTable); + convertInputsOutputs(dmnModel, decisionTable); + convertRules(dmnModel, decisionTable, spreadsheetAdapter.determineRuleRows(worksheetContext)); + + return dmnModel; + } + + public E generateNamedElement(DmnModelInstance modelInstance, Class elementClass, String name) { + E element = generateElement(modelInstance, elementClass, name); + element.setName(name); + return element; + } + + public E generateElement(DmnModelInstance modelInstance, Class elementClass, String id) { + E element = modelInstance.newInstance(elementClass); + element.setId(id); + return element; + } + + /** + * With a generated id + */ + public E generateElement(DmnModelInstance modelInstance, Class elementClass) { + // TODO: use a proper generator for random IDs + String generatedId = elementClass.getSimpleName() + Integer.toString((int) (Integer.MAX_VALUE * Math.random())); + return generateElement(modelInstance, elementClass, generatedId); + } + + protected void setHitPolicy(DecisionTable decisionTable) { + HitPolicy hitPolicy = spreadsheetAdapter.determineHitPolicy(worksheetContext); + if (hitPolicy != null) { + decisionTable.setHitPolicy(hitPolicy); + } + } + + protected void convertInputsOutputs(DmnModelInstance dmnModel, DecisionTable decisionTable) { + + InputOutputColumns inputOutputColumns = spreadsheetAdapter.determineInputOutputs(worksheetContext); + + // inputs + for (HeaderValuesContainer hvc : inputOutputColumns.getInputHeaders()) { + Input input = generateElement(dmnModel, Input.class, hvc.getId()); + decisionTable.addChildElement(input); + + // mandatory + InputExpression inputExpression = generateElement(dmnModel, InputExpression.class); + Text text = generateText(dmnModel, hvc.getText()); + inputExpression.setText(text); + input.setInputExpression(inputExpression); + + // optionals + if (hvc.getLabel() != null) { + input.setLabel(hvc.getLabel()); + } + if (hvc.getTypeRef() != null) { + inputExpression.setTypeRef(hvc.getTypeRef()); + } + if (hvc.getExpressionLanguage() != null) { + inputExpression.setExpressionLanguage(hvc.getExpressionLanguage()); + } + + dmnConversionContext.getIndexedDmnColumns().addInput(hvc.getColumn(), input); + } + + // outputs + for (HeaderValuesContainer hvc : inputOutputColumns.getOutputHeaders()) { + Output output = generateElement(dmnModel, Output.class, hvc.getId()); + decisionTable.addChildElement(output); + + // mandatory + output.setName(hvc.getText()); + + // optionals + if (hvc.getLabel() != null) { + output.setLabel(hvc.getLabel()); + } + if (hvc.getTypeRef() != null) { + output.setTypeRef(hvc.getTypeRef()); + } + + dmnConversionContext.getIndexedDmnColumns().addOutput(hvc.getColumn(), output); + } + + } + + protected void convertRules(DmnModelInstance dmnModel, DecisionTable decisionTable, List rulesRows) { + for (SpreadsheetRow rule : rulesRows) { + convertRule(dmnModel, decisionTable, rule); + } + } + + protected void convertRule(DmnModelInstance dmnModel, DecisionTable decisionTable, SpreadsheetRow ruleRow) { + Rule rule = generateElement(dmnModel, Rule.class, "excelRow" + ruleRow.getRaw().getR()); + decisionTable.addChildElement(rule); + + IndexedDmnColumns dmnColumns = dmnConversionContext.getIndexedDmnColumns(); + + for (Input input : dmnColumns.getOrderedInputs()) { + String xlsxColumn = dmnColumns.getSpreadsheetColumn(input); + SpreadsheetCell cell = ruleRow.getCell(xlsxColumn); + String coordinate = xlsxColumn + ruleRow.getRaw().getR(); + + InputEntry inputEntry = generateElement(dmnModel, InputEntry.class, coordinate); + String textValue = cell != null ? dmnConversionContext.resolveCellValue(cell) : getDefaultCellContent(); + Text text = generateText(dmnModel, textValue); + inputEntry.setText(text); + rule.addChildElement(inputEntry); + } + + for (Output output : dmnColumns.getOrderedOutputs()) { + String xlsxColumn = dmnColumns.getSpreadsheetColumn(output); + SpreadsheetCell cell = ruleRow.getCell(xlsxColumn); + String coordinate = xlsxColumn + ruleRow.getRaw().getR(); + + OutputEntry outputEntry = generateElement(dmnModel, OutputEntry.class, coordinate); + String textValue = cell != null ? dmnConversionContext.resolveCellValue(cell) : getDefaultCellContent(); + Text text = generateText(dmnModel, textValue); + outputEntry.setText(text); + rule.addChildElement(outputEntry); + } + + SpreadsheetCell annotationCell = ruleRow.getCells().get(ruleRow.getCells().size() - 1); + Description description = generateDescription(dmnModel, worksheetContext.resolveCellContent(annotationCell)); + rule.setDescription(description); + + } + + protected String getDefaultCellContent() { + return "-"; + } + + protected DmnModelInstance initializeEmptyDmnModel() { + DmnModelInstance dmnModel = Dmn.createEmptyModel(); + Definitions definitions = generateNamedElement(dmnModel, Definitions.class, "definitions"); + definitions.setNamespace(DmnModelConstants.CAMUNDA_NS); + dmnModel.setDefinitions(definitions); + + return dmnModel; + } + + protected Text generateText(DmnModelInstance dmnModel, String content) { + Text text = dmnModel.newInstance(Text.class); + text.setTextContent(content); + return text; + } + + protected Description generateDescription(DmnModelInstance dmnModel, String content) { + Description description = dmnModel.newInstance(Description.class); + description.setTextContent(content); + return description; + } +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/api/Spreadsheet.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/api/Spreadsheet.java new file mode 100644 index 0000000000..dc37c73a88 --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/api/Spreadsheet.java @@ -0,0 +1,24 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx.api; + +import java.util.List; + +public interface Spreadsheet { + + List getRows(); + + String resolveCellContent(SpreadsheetCell cell); + + String getName(); +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/api/SpreadsheetAdapter.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/api/SpreadsheetAdapter.java new file mode 100644 index 0000000000..bf12869dee --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/api/SpreadsheetAdapter.java @@ -0,0 +1,45 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx.api; + +import java.util.List; +import org.camunda.bpm.dmn.xlsx.CellContentHandler; +import org.camunda.bpm.dmn.xlsx.InputOutputColumns; +import org.camunda.bpm.model.dmn.HitPolicy; + +/** + * Implement this interface to tailor the conversion process to a specific format + * of your excel sheets. + */ +public interface SpreadsheetAdapter { + + InputOutputColumns determineInputOutputs(Spreadsheet spreadsheet); + + /** + * @return those rows that contain rule + */ + List determineRuleRows(Spreadsheet spreadsheet); + + /** + * @return null to use the DMN default + */ + HitPolicy determineHitPolicy(Spreadsheet spreadsheet); + + String determineDecisionName(Spreadsheet spreadsheet); + + /** + * order is important; add most specific converters first + */ + List getCellContentHandlers(Spreadsheet spreadsheet); + +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/api/SpreadsheetCell.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/api/SpreadsheetCell.java new file mode 100644 index 0000000000..864987e06d --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/api/SpreadsheetCell.java @@ -0,0 +1,27 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx.api; + +import org.xlsx4j.sml.Cell; + +public interface SpreadsheetCell { + + String getColumn(); + + int getRow(); + + /** + * @return the corresponding doc4j object => no API guarantees from here on :) + */ + Cell getRaw(); +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/api/SpreadsheetRow.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/api/SpreadsheetRow.java new file mode 100644 index 0000000000..1b1126da51 --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/api/SpreadsheetRow.java @@ -0,0 +1,33 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx.api; + +import java.util.Collection; +import java.util.List; +import org.xlsx4j.sml.Row; + +public interface SpreadsheetRow { + + Collection getColumns(); + + org.camunda.bpm.dmn.xlsx.api.SpreadsheetCell getCell(String column); + + List getCells(); + + boolean hasCells(); + + /** + * @return the corresponding doc4j object => no API guarantees from here on :) + */ + Row getRaw(); +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/CellHelper.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/CellHelper.java new file mode 100644 index 0000000000..9c8fc53f11 --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/CellHelper.java @@ -0,0 +1,18 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx.elements; + +/** + * @author Thorben Lindhauer + */ +public class CellHelper {} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/HeaderValuesContainer.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/HeaderValuesContainer.java new file mode 100644 index 0000000000..415a822cbc --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/HeaderValuesContainer.java @@ -0,0 +1,77 @@ +package org.camunda.bpm.dmn.xlsx.elements; + +import java.util.HashSet; +import java.util.Set; + +public class HeaderValuesContainer { + private static Set LANGUAGES; + + static { + LANGUAGES = new HashSet(); + LANGUAGES.add("javascript"); + LANGUAGES.add("groovy"); + LANGUAGES.add("python"); + LANGUAGES.add("jruby"); + LANGUAGES.add("juel"); + LANGUAGES.add("feel"); + } + + private String id; + private String text; + private String label; + private String typeRef; + private String expressionLanguage; + private String column; + + public String getExpressionLanguage() { + if (expressionLanguage != null && LANGUAGES.contains(expressionLanguage)) { + return expressionLanguage; + } else { + return null; + } + } + + public void setExpressionLanguage(String expressionLanguage) { + this.expressionLanguage = expressionLanguage; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getTypeRef() { + return typeRef; + } + + public void setTypeRef(String typeRef) { + this.typeRef = typeRef; + } + + public String getColumn() { + return column; + } + + public void setColumn(String column) { + this.column = column; + } +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/IndexedCell.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/IndexedCell.java new file mode 100644 index 0000000000..369702505a --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/IndexedCell.java @@ -0,0 +1,57 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx.elements; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetCell; +import org.xlsx4j.sml.Cell; + +/** + * @author Thorben Lindhauer + */ +public class IndexedCell implements SpreadsheetCell { + + public static final Pattern CELL_REF_PATTERN = Pattern.compile("([A-Z]+)([0-9]+)"); + + protected Cell cell; + protected String column; + protected int row; + + public IndexedCell(Cell cell) { + this.cell = cell; + + String cellReference = cell.getR(); + Matcher matcher = CELL_REF_PATTERN.matcher(cellReference); + + boolean matches = matcher.matches(); + if (!matches) { + throw new RuntimeException("Cannot parse cell reference " + cellReference); + } + + column = matcher.group(1); + row = Integer.parseInt(matcher.group(2)); + } + + public Cell getRaw() { + return cell; + } + + public String getColumn() { + return column; + } + + public int getRow() { + return row; + } +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/IndexedDmnColumns.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/IndexedDmnColumns.java new file mode 100644 index 0000000000..5e5b519057 --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/IndexedDmnColumns.java @@ -0,0 +1,59 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx.elements; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.camunda.bpm.model.dmn.instance.Input; +import org.camunda.bpm.model.dmn.instance.Output; + +/** + * @author Thorben Lindhauer + */ +public class IndexedDmnColumns { + + protected Map inputColumns = new HashMap<>(); + protected Map outputColumns = new HashMap<>(); + + // as they appear in the resulting DMN table + protected List orderedInputs = new ArrayList<>(); + protected List orderedOutputs = new ArrayList<>(); + + public List getOrderedInputs() { + return orderedInputs; + } + + public List getOrderedOutputs() { + return orderedOutputs; + } + + public String getSpreadsheetColumn(Input input) { + return inputColumns.get(input); + } + + public String getSpreadsheetColumn(Output output) { + return outputColumns.get(output); + } + + public void addInput(String column, Input input) { + this.orderedInputs.add(input); + this.inputColumns.put(input, column); + } + + public void addOutput(String column, Output output) { + this.orderedOutputs.add(output); + this.outputColumns.put(output, column); + } +} diff --git a/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/IndexedRow.java b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/IndexedRow.java new file mode 100644 index 0000000000..e86de697db --- /dev/null +++ b/routing/dmn-xlsx-converter/src/main/java/org/camunda/bpm/dmn/xlsx/elements/IndexedRow.java @@ -0,0 +1,77 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx.elements; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetCell; +import org.camunda.bpm.dmn.xlsx.api.SpreadsheetRow; +import org.xlsx4j.sml.Cell; +import org.xlsx4j.sml.Row; + +/** + * @author Thorben Lindhauer + * + */ +public class IndexedRow implements SpreadsheetRow { + + public static final Pattern CELL_REF_PATTERN = Pattern.compile("([A-Z]+)([0-9]+)"); + + protected Row row; + protected List cells; + protected Map cellsByColumn; + + public IndexedRow(Row row) { + this.row = row; + this.cells = new ArrayList<>(); + this.cellsByColumn = new HashMap<>(); + + for (Cell cell : row.getC()) { + IndexedCell indexedCell = new IndexedCell(cell); + String column = indexedCell.getColumn(); + cells.add(indexedCell); + cellsByColumn.put(column, indexedCell); + } + } + + public Row getRaw() { + return row; + } + + public Collection getColumns() { + return cellsByColumn.keySet(); + } + + public SpreadsheetCell getCell(String column) { + return cellsByColumn.get(column); + } + + public boolean hasCells() { + return !cells.isEmpty(); + } + + public List getCells() { + return cells; + } + + protected String extractColumn(Cell cell) { + String cellReference = cell.getR(); + Matcher matcher = CELL_REF_PATTERN.matcher(cellReference); + return matcher.group(1); + } +} diff --git a/routing/dmn-xlsx-converter/src/test/java/org/camunda/bpm/dmn/xlsx/DmnValueRangeMatcherTest.java b/routing/dmn-xlsx-converter/src/test/java/org/camunda/bpm/dmn/xlsx/DmnValueRangeMatcherTest.java new file mode 100644 index 0000000000..646668693c --- /dev/null +++ b/routing/dmn-xlsx-converter/src/test/java/org/camunda/bpm/dmn/xlsx/DmnValueRangeMatcherTest.java @@ -0,0 +1,53 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.regex.Matcher; +import org.camunda.bpm.dmn.xlsx.DmnValueRangeConverter; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/** + * @author Thorben Lindhauer + * + */ +public class DmnValueRangeMatcherTest { + + @ParameterizedTest + @CsvSource({ + "[1..9], true ", + "]1..9], true ", + "[1..9[, true ", + "]1..9[, true ", + "[100..900], true ", + "[10.1..909], true ", + "[10..90.1], true ", + "[10.1..90.1], true ", + "text, false ", + "[a..b], false ", + "[100..a], false ", + "[100..900, false ", + "100..900, false ", + "[100900], false ", + "[100.900], false ", + "[date and time(\"2018-05-17T00:00:00\")..date and time(\"2018-11-17T24:00:00\")], true" + }) + public void shouldMatchInclusiveInterval(String input, boolean shouldMatch) + { + Matcher matcher = DmnValueRangeConverter.RANGE_REGEX.matcher(input); + + assertThat(matcher.matches()).isEqualTo(shouldMatch); + } +} diff --git a/routing/dmn-xlsx-converter/src/test/java/org/camunda/bpm/dmn/xlsx/InputOutputDetectionStrategyTest.java b/routing/dmn-xlsx-converter/src/test/java/org/camunda/bpm/dmn/xlsx/InputOutputDetectionStrategyTest.java new file mode 100644 index 0000000000..cbc9d13064 --- /dev/null +++ b/routing/dmn-xlsx-converter/src/test/java/org/camunda/bpm/dmn/xlsx/InputOutputDetectionStrategyTest.java @@ -0,0 +1,45 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.InputStream; +import java.util.Collections; +import org.camunda.bpm.model.dmn.DmnModelInstance; +import org.camunda.bpm.model.dmn.instance.DecisionTable; +import org.junit.jupiter.api.Test; + +/** + * @author Thorben Lindhauer + */ +public class InputOutputDetectionStrategyTest { + + @Test + public void testStaticDetectionStrategy() { + XlsxConverter converter = new XlsxConverter(); + converter.setIoDetectionStrategy( + new StaticInputOutputDetectionStrategy(Collections.singleton("B"), + Collections.singleton("D"))); + InputStream inputStream = TestHelper.getClassPathResource("test2.xlsx"); + DmnModelInstance dmnModelInstance = converter.convert(inputStream); + assertThat(dmnModelInstance).isNotNull(); + + DecisionTable table = TestHelper.assertAndGetSingleDecisionTable(dmnModelInstance); + assertThat(table).isNotNull(); + assertThat(table.getInputs()).hasSize(1); + assertThat(table.getOutputs()).hasSize(1); + assertThat(table.getRules()).hasSize(4); + } + +} diff --git a/routing/dmn-xlsx-converter/src/test/java/org/camunda/bpm/dmn/xlsx/TestHelper.java b/routing/dmn-xlsx-converter/src/test/java/org/camunda/bpm/dmn/xlsx/TestHelper.java new file mode 100644 index 0000000000..f5c682c6c2 --- /dev/null +++ b/routing/dmn-xlsx-converter/src/test/java/org/camunda/bpm/dmn/xlsx/TestHelper.java @@ -0,0 +1,46 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.InputStream; +import java.util.Collection; +import org.camunda.bpm.model.dmn.DmnModelInstance; +import org.camunda.bpm.model.dmn.instance.Decision; +import org.camunda.bpm.model.dmn.instance.DecisionTable; + +/** + * @author Thorben Lindhauer + * + */ +public class TestHelper { + + public static InputStream getClassPathResource(String path) { + return TestHelper.class.getClassLoader().getResourceAsStream(path); + } + + public static DecisionTable assertAndGetSingleDecisionTable(DmnModelInstance dmnModel) { + assertThat(dmnModel.getDefinitions()).isNotNull(); + Collection decisions = dmnModel.getDefinitions().getChildElementsByType(Decision.class); + assertThat(decisions).hasSize(1); + + Decision decision = decisions.iterator().next(); + assertThat(decision).isNotNull(); + + Collection decisionTables = decision.getChildElementsByType(DecisionTable.class); + assertThat(decisionTables).hasSize(1); + + return decisionTables.iterator().next(); + } +} diff --git a/routing/dmn-xlsx-converter/src/test/java/org/camunda/bpm/dmn/xlsx/XslxToDmnConversionTest.java b/routing/dmn-xlsx-converter/src/test/java/org/camunda/bpm/dmn/xlsx/XslxToDmnConversionTest.java new file mode 100644 index 0000000000..cbc2554b90 --- /dev/null +++ b/routing/dmn-xlsx-converter/src/test/java/org/camunda/bpm/dmn/xlsx/XslxToDmnConversionTest.java @@ -0,0 +1,170 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.camunda.bpm.dmn.xlsx; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.InputStream; +import java.util.Iterator; +import org.camunda.bpm.model.dmn.DmnModelInstance; +import org.camunda.bpm.model.dmn.HitPolicy; +import org.camunda.bpm.model.dmn.instance.DecisionTable; +import org.camunda.bpm.model.dmn.instance.Input; +import org.camunda.bpm.model.dmn.instance.InputEntry; +import org.camunda.bpm.model.dmn.instance.Rule; +import org.junit.jupiter.api.Test; + +/** + * @author Thorben Lindhauer + * + */ +public class XslxToDmnConversionTest { + + public static final String DMN_11_NAMESPACE = "https://www.omg.org/spec/DMN/20191111/MODEL/"; + + private static final String JAVASCRIPT_SNIPPET = + "if (exp1 % 2 == 0)\n" + + " {erg = 2;}\n" + + "else\n" + + " {erg = 1;}\n" + + "erg;"; + + // TODO: assert input entry text content + + @Test + public void testSimpleConversion() { + XlsxConverter converter = new XlsxConverter(); + InputStream inputStream = TestHelper.getClassPathResource("test1.xlsx"); + DmnModelInstance dmnModelInstance = converter.convert(inputStream); + assertThat(dmnModelInstance).isNotNull(); + + DecisionTable table = TestHelper.assertAndGetSingleDecisionTable(dmnModelInstance); + assertThat(table).isNotNull(); + assertThat(table.getInputs()).hasSize(2); + assertThat(table.getOutputs()).hasSize(1); + assertThat(table.getRules()).hasSize(4); + } + + @Test + public void testConversionOfMixedNumberAndStringColumns() { + XlsxConverter converter = new XlsxConverter(); + InputStream inputStream = TestHelper.getClassPathResource("test2.xlsx"); + DmnModelInstance dmnModelInstance = converter.convert(inputStream); + assertThat(dmnModelInstance).isNotNull(); + + DecisionTable table = TestHelper.assertAndGetSingleDecisionTable(dmnModelInstance); + assertThat(table).isNotNull(); + assertThat(table.getInputs()).hasSize(3); + assertThat(table.getOutputs()).hasSize(1); + assertThat(table.getRules()).hasSize(4); + } + + @Test + public void testConversionOfEmptyCells() { + XlsxConverter converter = new XlsxConverter(); + InputStream inputStream = TestHelper.getClassPathResource("test3.xlsx"); + DmnModelInstance dmnModelInstance = converter.convert(inputStream); + assertThat(dmnModelInstance).isNotNull(); + + DecisionTable table = TestHelper.assertAndGetSingleDecisionTable(dmnModelInstance); + assertThat(table).isNotNull(); + assertThat(table.getInputs()).hasSize(3); + assertThat(table.getOutputs()).hasSize(1); + assertThat(table.getRules()).hasSize(4); + } + + @Test + public void testDmnNamespace() { + XlsxConverter converter = new XlsxConverter(); + InputStream inputStream = TestHelper.getClassPathResource("test1.xlsx"); + DmnModelInstance dmnModelInstance = converter.convert(inputStream); + + assertThat(dmnModelInstance.getDefinitions().getDomElement().getNamespaceURI()).isEqualTo(DMN_11_NAMESPACE); + } + + @Test + public void testConversionOfNullTitleOfParts() { + XlsxConverter converter = new XlsxConverter(); + InputStream inputStream = TestHelper.getClassPathResource("test4.xlsx"); + DmnModelInstance dmnModelInstance = converter.convert(inputStream); + assertThat(dmnModelInstance).isNotNull(); + + DecisionTable table = TestHelper.assertAndGetSingleDecisionTable(dmnModelInstance); + + assertThat(table).isNotNull(); + assertThat(table.getInputs()).hasSize(2); + assertThat(table.getOutputs()).hasSize(1); + assertThat(table.getRules()).hasSize(1); + } + + @Test + public void testConversionWithRanges() { + XlsxConverter converter = new XlsxConverter(); + InputStream inputStream = TestHelper.getClassPathResource("test5.xlsx"); + DmnModelInstance dmnModelInstance = converter.convert(inputStream); + assertThat(dmnModelInstance).isNotNull(); + + DecisionTable table = TestHelper.assertAndGetSingleDecisionTable(dmnModelInstance); + assertThat(table).isNotNull(); + assertThat(table.getInputs()).hasSize(1); + assertThat(table.getOutputs()).hasSize(1); + assertThat(table.getRules()).hasSize(4); + + Rule firstRule = table.getRules().iterator().next(); + + InputEntry inputEntry = firstRule.getInputEntries().iterator().next(); + String firstInput = inputEntry.getTextContent(); + assertThat(firstInput).isEqualTo("[1..2]"); + } + + @Test + public void testConversionWithComplexHeaders() { + XlsxConverter converter = new XlsxConverter(); + converter.setIoDetectionStrategy(new AdvancedSpreadsheetAdapter()); + InputStream inputStream = TestHelper.getClassPathResource("test6.xlsx"); + DmnModelInstance dmnModelInstance = converter.convert(inputStream); + assertThat(dmnModelInstance).isNotNull(); + + DecisionTable table = TestHelper.assertAndGetSingleDecisionTable(dmnModelInstance); + assertThat(table).isNotNull(); + assertThat(table.getInputs()).hasSize(2); + assertThat(table.getOutputs()).hasSize(2); + assertThat(table.getRules()).hasSize(2); + assertThat(table.getHitPolicy()).isEqualTo(HitPolicy.FIRST); + + Iterator inputIterator = table.getInputs().iterator(); + Input input = inputIterator.next(); + + assertThat(input.getId()).isEqualTo("input1"); + assertThat(input.getLabel()).isEqualTo("InputLabel1"); + assertThat(input.getInputExpression().getTypeRef()).isEqualTo("string"); + assertThat(input.getTextContent()).isEqualTo("Exp1"); + + input = inputIterator.next(); + assertThat(input.getId()).isEqualTo("input2"); + assertThat(input.getLabel()).isEqualTo("InputLabel2"); + assertThat(input.getInputExpression().getTypeRef()).isEqualTo("integer"); + assertThat(input.getInputExpression().getExpressionLanguage()).isEqualTo("javascript"); + assertThat(input.getInputExpression().getTextContent()).isEqualTo(JAVASCRIPT_SNIPPET); + + Iterator ruleIterator = table.getRules().iterator(); + Rule rule = ruleIterator.next(); + assertThat(rule.getDescription().getTextContent()).isEqualTo("Comment1"); + + InputEntry inputEntry = rule.getInputEntries().iterator().next(); + assertThat(inputEntry.getTextContent()).isEqualTo("\"Foo\""); + + rule = ruleIterator.next(); + assertThat(rule.getDescription().getTextContent()).isEqualTo("Another Comment"); + } +} diff --git a/routing/dmn-xlsx-converter/src/test/resources/log4j2-test.xml b/routing/dmn-xlsx-converter/src/test/resources/log4j2-test.xml new file mode 100644 index 0000000000..58fe9a427b --- /dev/null +++ b/routing/dmn-xlsx-converter/src/test/resources/log4j2-test.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/routing/dmn-xlsx-converter/src/test/resources/test1.xlsx b/routing/dmn-xlsx-converter/src/test/resources/test1.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..561601f9899156cbbaba476c39d610fbfa212e38 GIT binary patch literal 8221 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 literal 0 HcmV?d00001 diff --git a/routing/dmn-xlsx-converter/src/test/resources/test2.xlsx b/routing/dmn-xlsx-converter/src/test/resources/test2.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c74529b1de1c858c64afb2e7f6b73652b30fd266 GIT binary patch literal 8258 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 literal 0 HcmV?d00001 diff --git a/routing/dmn-xlsx-converter/src/test/resources/test3.xlsx b/routing/dmn-xlsx-converter/src/test/resources/test3.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..91dc41d2c7315a3a9f5cce549dbf998b27fd6e3d GIT binary patch literal 8252 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 U=>h=gu+Mu~4ljV|nE=550m{`iPXGV_ literal 0 HcmV?d00001 diff --git a/routing/dmn-xlsx-converter/src/test/resources/test4.xlsx b/routing/dmn-xlsx-converter/src/test/resources/test4.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..a2e93c15a67fb93f0ba5ac815049c3e0f4c36150 GIT binary patch literal 4785 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

k71LJC0L-* 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 literal 0 HcmV?d00001 diff --git a/routing/dmn-xlsx-converter/src/test/resources/test6.xlsx b/routing/dmn-xlsx-converter/src/test/resources/test6.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..7703ac43635f17fbdbe59257ff168cf02eb1b88c GIT binary patch literal 9571 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 literal 0 HcmV?d00001 diff --git a/routing/pom.xml b/routing/pom.xml index 61037a52ca..8b1197100b 100644 --- a/routing/pom.xml +++ b/routing/pom.xml @@ -17,6 +17,7 @@ + dmn-xlsx-converter taskana-spi-routing-dmn-router taskana-routing-rest diff --git a/routing/taskana-routing-rest/pom.xml b/routing/taskana-routing-rest/pom.xml index 9f4e9ec3c3..5b32ac0a44 100644 --- a/routing/taskana-routing-rest/pom.xml +++ b/routing/taskana-routing-rest/pom.xml @@ -31,6 +31,7 @@ dmn-xlsx-converter ${version.dmn-xlsx-converter} + jakarta.xml.bind jakarta.xml.bind-api