From 0b5489e399693c1d245366b95782192384a00663 Mon Sep 17 00:00:00 2001 From: Steve Lawrence Date: Fri, 26 May 2017 13:57:17 -0500 Subject: [PATCH] NIFI-3572 Add PipelineXml processor to support XProc XML pipelines via XMLCalabash --- nifi-assembly/pom.xml | 5 + .../nifi-pipelinexml-nar/pom.xml | 41 ++ .../src/main/resources/META-INF/LICENSE | 473 ++++++++++++++++++ .../src/main/resources/META-INF/NOTICE | 109 ++++ .../nifi-pipelinexml-processors/pom.xml | 86 ++++ .../processors/xmlcalabash/PipelineXml.java | 473 ++++++++++++++++++ .../xmlcalabash/PipelineXmlData.java | 60 +++ .../org.apache.nifi.processor.Processor | 15 + .../xmlcalabash/TestPipelineXml.java | 266 ++++++++++ .../src/test/resources/addAttributes.xpl | 18 + .../src/test/resources/addAttributes1.xml | 5 + .../src/test/resources/addAttributes2.xml | 5 + .../src/test/resources/addAttributes3.xml | 5 + .../src/test/resources/bad.xpl | 18 + .../src/test/resources/input.xml | 5 + .../src/test/resources/multipleOutputs.xpl | 27 + .../src/test/resources/noOutputs.xpl | 11 + .../src/test/resources/noPrimaryPort.xpl | 17 + .../nifi-xmlcalabash-bundle/pom.xml | 35 ++ nifi-nar-bundles/pom.xml | 1 + pom.xml | 6 + 21 files changed, 1681 insertions(+) create mode 100644 nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-nar/pom.xml create mode 100644 nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-nar/src/main/resources/META-INF/LICENSE create mode 100644 nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-nar/src/main/resources/META-INF/NOTICE create mode 100644 nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/pom.xml create mode 100644 nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/main/java/org/apache/nifi/processors/xmlcalabash/PipelineXml.java create mode 100644 nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/main/java/org/apache/nifi/processors/xmlcalabash/PipelineXmlData.java create mode 100644 nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor create mode 100644 nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/java/org/apache/nifi/processors/xmlcalabash/TestPipelineXml.java create mode 100644 nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/addAttributes.xpl create mode 100644 nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/addAttributes1.xml create mode 100644 nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/addAttributes2.xml create mode 100644 nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/addAttributes3.xml create mode 100644 nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/bad.xpl create mode 100644 nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/input.xml create mode 100644 nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/multipleOutputs.xpl create mode 100644 nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/noOutputs.xpl create mode 100644 nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/noPrimaryPort.xpl create mode 100644 nifi-nar-bundles/nifi-xmlcalabash-bundle/pom.xml diff --git a/nifi-assembly/pom.xml b/nifi-assembly/pom.xml index 5c7bff77ded2..de22aa66974c 100755 --- a/nifi-assembly/pom.xml +++ b/nifi-assembly/pom.xml @@ -476,6 +476,11 @@ nifi-hwx-schema-registry-nar nar + + org.apache.nifi + nifi-pipelinexml-nar + nar + diff --git a/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-nar/pom.xml b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-nar/pom.xml new file mode 100644 index 000000000000..847feb02e6f6 --- /dev/null +++ b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-nar/pom.xml @@ -0,0 +1,41 @@ + + + + 4.0.0 + + + org.apache.nifi + nifi-xmlcalabash-bundle + 1.3.0-SNAPSHOT + + + nifi-pipelinexml-nar + 1.3.0-SNAPSHOT + nar + + true + true + + + + + org.apache.nifi + nifi-pipelinexml-processors + 1.3.0-SNAPSHOT + + + + diff --git a/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-nar/src/main/resources/META-INF/LICENSE b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-nar/src/main/resources/META-INF/LICENSE new file mode 100644 index 000000000000..02c08bd92e9f --- /dev/null +++ b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-nar/src/main/resources/META-INF/LICENSE @@ -0,0 +1,473 @@ + + 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 + +NIFI PIPELINEXML PROCESSOR SUBCOMPONENTS: + +The NiFi PipelineXml Processor project contains subcomponents with separate +copyright notices and license terms. Your use of the source code for the these +subcomponents is subject to the terms and conditions of the following licenses. + + This product bundles 'HTML Parser' which is available under the following + license. + + This is for the HTML parser as a whole except the rewindable input stream, + the named character classes and the Live DOM Viewer. + For the copyright notices for individual files, please see individual files. + + /* + * Copyright (c) 2005, 2006, 2007 Henri Sivonen + * Copyright (c) 2007-2012 Mozilla Foundation + * Portions of comments Copyright 2004-2007 Apple Computer, Inc., Mozilla + * Foundation, and Opera Software ASA. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + + The following license is for the WHATWG spec from which the named character + data was extracted. + + /* + * Copyright 2004-2010 Apple Computer, Inc., Mozilla Foundation, and Opera + * Software ASA. + * + * You are granted a license to use, reproduce and create derivative works of + * this document. + */ + + The following license is for the rewindable input stream. + + /* + * Copyright (c) 2001-2003 Thai Open Source Software Center Ltd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of the Thai Open Source Software Center Ltd nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + The following license applies to the Live DOM Viewer: + + Copyright (c) 2000, 2006, 2008 Ian Hickson and various contributors + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + This product bundles 'ICU4J' which is available under the "ICU License": + + COPYRIGHT AND PERMISSION NOTICE + + Copyright (c) 1995-2012 International Business Machines Corporation and + others + + All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, provided that the above copyright notice(s) and this + permission notice appear in all copies of the Software and that both the + above copyright notice(s) and this permission notice appear in supporting + documentation. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE + BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, + OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + SOFTWARE. + + Except as contained in this notice, the name of a copyright holder shall + not be used in advertising or otherwise to promote the sale, use or other + dealings in this Software without prior written authorization of the + copyright holder. + + This product bundles 'ISO Relax' which is available under an "MIT" License. + + Copyright (c) 2001-2002, SourceForge ISO-RELAX Project (ASAMI Tomoharu, Daisuke + Okajima, Kohsuke Kawaguchi, and MURATA Makoto) + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + This product bundles 'Jing' which is available under a "BSD" License. + + Copyright (c) 2001-2003 Thai Open Source Software Center Ltd + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + Neither the name of the Thai Open Source Software Center Ltd nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + The product bundles 'MSV Core' which is available under a "BSD" License. For + details see, https://msv.java.net/License.txt + + Copyright (c) 2001,2013 Oracle and/or its affiliates. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of Oracle nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + The product bundles 'RelaxNG Datatype' which is available under an "BSD" + License. + + Copyright (c) 2001, Thai Open Source Software Center Ltd + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + Neither the name of the Thai Open Source Software Center Ltd nor + the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + The product bundles 'XSD Lib' which is available under a "BSD" License. For + details see, https://msv.java.net/License.txt + + Copyright (c) 2001,2013 Oracle and/or its affiliates. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of Oracle nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-nar/src/main/resources/META-INF/NOTICE b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-nar/src/main/resources/META-INF/NOTICE new file mode 100644 index 000000000000..5909736e666a --- /dev/null +++ b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-nar/src/main/resources/META-INF/NOTICE @@ -0,0 +1,109 @@ +nifi-pipelinexml-nar +Copyright 2017 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +****************** +Apache Software License v2 +****************** + +The following binary components are provided under the Apache Software License v2 + + (ASLv2) Apache Ant + The following NOTICE information applies: + Apache Ant + Copyright 1999-2012 The Apache Software Foundation + + The task is based on code Copyright (c) 2002, Landmark + Graphics Corp that has been kindly donated to the Apache Software + Foundation. + + (ASLv2) Apache Commons Codec + The following NOTICE information applies: + Apache Commons Codec + Copyright 2002-2014 The Apache Software Foundation + + src/test/org/apache/commons/codec/language/DoubleMetaphoneTest.java + contains test data from http://aspell.net/test/orig/batch0.tab. + Copyright (C) 2002 Kevin Atkinson (kevina@gnu.org) + + =============================================================================== + + The content of package org.apache.commons.codec.language.bm has been translated + from the original php source code available at http://stevemorse.org/phoneticinfo.htm + with permission from the original authors. + Original source copyright: + Copyright (c) 2008 Alexander Beider & Stephen P. Morse. + + (ASLv2) Apache Commons File Upload + The following NOTICE information applies: + Apache Commons Logging + Copyright 2003-2013 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (http://www.apache.org/). + + (ASLv2) Apache Commons IO + The following NOTICE information applies: + Apache Commons IO + Copyright 2002-2016 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (http://www.apache.org/). + + (ASLv2) Apache Commons Logging + The following NOTICE information applies: + Apache Commons Logging + Copyright 2003-2013 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (http://www.apache.org/). + + (ASLv2) Apache HttpClient + The following NOTICE information applies: + Apache HttpClient + Copyright 1999-2015 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (http://www.apache.org/). + + (ASLv2) Apache HttpCore + The following NOTICE information applies: + Apache HttpCore + Copyright 2005-2016 The Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (http://www.apache.org/). + + This project contains annotations derived from JCIP-ANNOTATIONS + Copyright (c) 2005 Brian Goetz and Tim Peierls. See http://www.jcip.net + + (ASLv2) Apache Log4j + The following NOTICE information applies: + Apache Log4j API + Copyright 1999-2014 Apache Software Foundation + + This product includes software developed at + The Apache Software Foundation (http://www.apache.org/). + +************************ +Common Development and Distribution License 1.1 +************************ + +The following binary components are provided under the Common Development and +Distribution License 1.1. See project link for details. + + (CDDL 1.0) (LGPL3.0) Restlet (org.restlet:org.restlet:jar:2.2.2 - http://restlet.org) + (CDDL 1.0) (LGPL3.0) Restlet File Upload (org.restlet:org.restlet.ext.fileupload:jar:2.2.2 - http://restlet.org) + (CDDL 1.0) (LGPL3.0) Restlet SLF4J (org.restlet:org.restlet.ext.slf4j:jar:2.2.2 - http://restlet.org) + (CDDL 1.0) (GPL2.0) XML Calabash (com.xmlcalabash:com.xmlcalabash:jar:1.1.15-96 - http://xmlcalabash.com) + +***************** +Mozilla Public License v2.0 +***************** + +The following binary components are provided under the Mozilla Public License +v2.0. See project link for details. + + (MPL 2.0) Saxon HE (net.sf.saxon:Saxon-HE:jar:9.6.0-5 - http://www.saxonica.com/) diff --git a/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/pom.xml b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/pom.xml new file mode 100644 index 000000000000..1d65aa1c55af --- /dev/null +++ b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/pom.xml @@ -0,0 +1,86 @@ + + + + 4.0.0 + + + org.apache.nifi + nifi-xmlcalabash-bundle + 1.3.0-SNAPSHOT + + + nifi-pipelinexml-processors + jar + + + + org.apache.nifi + nifi-api + + + org.apache.nifi + nifi-utils + + + org.apache.nifi + nifi-properties + + + com.xmlcalabash + xmlcalabash + 1.1.15-96 + + + + org.apache.nifi + nifi-mock + test + + + org.slf4j + slf4j-simple + test + + + junit + junit + test + + + + + + + org.apache.rat + apache-rat-plugin + + + src/test/resources/addAttributes.xpl + src/test/resources/addAttributes1.xml + src/test/resources/addAttributes2.xml + src/test/resources/addAttributes3.xml + src/test/resources/bad.xpl + src/test/resources/input.xml + src/test/resources/multipleOutputs.xpl + src/test/resources/noOutputs.xpl + src/test/resources/noPrimaryPort.xpl + + + + + + + diff --git a/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/main/java/org/apache/nifi/processors/xmlcalabash/PipelineXml.java b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/main/java/org/apache/nifi/processors/xmlcalabash/PipelineXml.java new file mode 100644 index 000000000000..02a0c137074a --- /dev/null +++ b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/main/java/org/apache/nifi/processors/xmlcalabash/PipelineXml.java @@ -0,0 +1,473 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.nifi.processors.xmlcalabash; + +import org.apache.commons.io.IOUtils; + +import org.apache.nifi.annotation.behavior.DynamicProperty; +import org.apache.nifi.annotation.behavior.DynamicRelationship; +import org.apache.nifi.annotation.behavior.EventDriven; +import org.apache.nifi.annotation.behavior.InputRequirement; +import org.apache.nifi.annotation.behavior.InputRequirement.Requirement; +import org.apache.nifi.annotation.behavior.SideEffectFree; +import org.apache.nifi.annotation.behavior.SupportsBatching; +import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.components.ValidationContext; +import org.apache.nifi.components.ValidationResult; +import org.apache.nifi.components.Validator; +import org.apache.nifi.expression.AttributeExpression; +import org.apache.nifi.flowfile.FlowFile; +import org.apache.nifi.flowfile.attributes.CoreAttributes; +import org.apache.nifi.annotation.behavior.WritesAttribute; +import org.apache.nifi.annotation.behavior.WritesAttributes; +import org.apache.nifi.annotation.lifecycle.OnScheduled; +import org.apache.nifi.annotation.lifecycle.OnStopped; +import org.apache.nifi.annotation.documentation.CapabilityDescription; +import org.apache.nifi.annotation.documentation.Tags; +import org.apache.nifi.processor.exception.ProcessException; +import org.apache.nifi.processor.AbstractProcessor; +import org.apache.nifi.processor.ProcessContext; +import org.apache.nifi.processor.ProcessSession; +import org.apache.nifi.processor.ProcessorInitializationContext; +import org.apache.nifi.processor.Relationship; +import org.apache.nifi.processor.util.StandardValidators; +import org.apache.nifi.util.StringUtils; + +import static org.apache.nifi.flowfile.attributes.FragmentAttributes.FRAGMENT_COUNT; +import static org.apache.nifi.flowfile.attributes.FragmentAttributes.FRAGMENT_ID; +import static org.apache.nifi.flowfile.attributes.FragmentAttributes.FRAGMENT_INDEX; +import static org.apache.nifi.flowfile.attributes.FragmentAttributes.SEGMENT_ORIGINAL_FILENAME; +import static org.apache.nifi.flowfile.attributes.FragmentAttributes.copyAttributesToOriginal; + +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.AbstractMap.SimpleEntry; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; + +import org.xml.sax.InputSource; + +import net.sf.saxon.s9api.QName; +import net.sf.saxon.s9api.SaxonApiException; +import net.sf.saxon.s9api.XdmNode; + +import com.xmlcalabash.core.XProcException; +import com.xmlcalabash.io.ReadablePipe; +import com.xmlcalabash.io.WritableDocument; +import com.xmlcalabash.model.RuntimeValue; +import com.xmlcalabash.model.Serialization; +import com.xmlcalabash.runtime.XPipeline; +import com.xmlcalabash.util.Input; + +@EventDriven +@SideEffectFree +@SupportsBatching +@InputRequirement(Requirement.INPUT_REQUIRED) +@Tags({"XML, XProc, XMLCalabash"}) +@CapabilityDescription( + "Inserts a FlowFile into a specified XProc XML pipeline, allowing one to perform " + + "complex validations and transformations of XML data within a single NiFi " + + "processor. This processor provides a FlowFile to the primary input port of the " + + "XProc pipeline. It is an error if the XProc pipeline does not define a primary " + + "input port. When data exits the XProc pipeline via one or more output ports, a " + + "FlowFile is created and transferred to a dynamic NiFi relationship having the " + + "same name as the output port. If a failure occurs during XProc processing, the " + + "original FlowFile is transferred to the 'pipeline failure' relationship and " + + "nothing transferred to any of the the dynamic output port relationships. " + + "Dynamic properties may be defined, with their names and values passed to the " + + "XProc pipeline as XProc options. Note that all input and output XML data " + + "reside in memory during XML pipeline processing. Also note that due the " + + "non-thread safe library used for pipeline processing, a pool of pipeline instances " + + "is created, with the pool size defined by the number of maximum concurrent tasks. " + + "If memory usage is a concern, the number of concurrent tasks should be reduced, " + + "thus limiting the number of XML Calabash pipeline instances created and XML data " + + "stored in memory. For more information on XProc, visit http://www.w3.org/TR/xproc/") +@DynamicProperty( + name = "XProc Option Name", + value = "XProc Option Value", + supportsExpressionLanguage = true, + description = "Option names and values passed to the XProc pipeline. The dynamic " + + "property name must be in Clark-notation, {uri}name, though the {uri} " + + "prefix may be optional depending on the XProc file. The property name " + + "is passed directly to the XProc engine as an option name along with its " + + "associated value.") +@DynamicRelationship( + name = "XProc Output Port", + description = + "A dynamic relationship is created for each output port defined in the XProc " + + "pipeline. When XML is written to an XProc output port, a FlowFile is created " + + "for the XML, which is transferred to the relationship of the same name. Based on " + + "the XProc pipeline, a single input FlowFile could result in outputs to more " + + "than one relationship. If an XProc output port specifies sequence='true', then " + + "multiple FlowFiles could be transferred to the same output relationship for a " + + "single input FlowFile.") +@WritesAttributes({ + @WritesAttribute(attribute = "fragment.identifier", + description = "All outputs produced from the same input FlowFile will have the same randomly generated UUID added for this attribute"), + @WritesAttribute(attribute = "fragment.index", + description = "A one-up number that indicates the ordering of output port FlowFiles that were created from a single parent FlowFile"), + @WritesAttribute(attribute = "fragment.count", + description = "The total number of FlowFiles generated from the input FlowFile"), + @WritesAttribute(attribute = "segment.original.filename ", + description = "The filename of the input FlowFile") +}) +public class PipelineXml extends AbstractProcessor { + + private String inputPort = null; + private List properties; + private AtomicReference> relationships = new AtomicReference<>(); + private BlockingQueue pipelinePool = null; + + private static String findPrimaryInputPort(XPipeline pipeline) { + for (String port : pipeline.getInputs()) { + final com.xmlcalabash.model.Input inputPort = pipeline.getDeclareStep().getInput(port); + if (inputPort.getPrimary() && !inputPort.getParameterInput()) { + return port; + } + } + return null; + } + + private static final Validator XML_PIPELINE_VALIDATOR = new Validator() { + @Override + public ValidationResult validate(String subject, String input, ValidationContext context) { + final ValidationResult.Builder builder = new ValidationResult.Builder(); + builder.subject(subject).input(input); + + PipelineXmlData pd = null; + try { + if (subject == XML_PIPELINE_CONFIG.getName()) { + pd = new PipelineXmlData(input, null); // base URI not needed for finding primary ports + } else if (subject == XML_PIPELINE_FILE.getName()) { + pd = new PipelineXmlData(new Input(input)); + } else { + return builder.valid(false).explanation("Can only validate XML Pipeline Config or XML Pipeline File").build(); + } + } catch (SaxonApiException | XProcException e) { + return builder.valid(false).explanation("XProc pipeline is invalid: " + e).build(); + } + + final String inputPort = findPrimaryInputPort(pd.pipeline); + if (inputPort == null) { + return builder.valid(false).explanation("XProc pipeline must define a primary non-parameter input port").build(); + } + + return builder.valid(true).build(); + } + }; + + private static final Validator XPROC_OPTION_NAME_VALIDATOR = new Validator() { + @Override + public ValidationResult validate(String optName, String optValue, ValidationContext context) { + final ValidationResult.Builder builder = new ValidationResult.Builder(); + builder.subject(optName).input(optValue); + + try { + QName.fromClarkName(optName); + builder.valid(true); + } catch (IllegalArgumentException e) { + builder.valid(false).explanation("Option name must be of the form {uri}local."); + } + + return builder.build(); + } + }; + + private static final Validator BASE_URI_VALIDATOR = new Validator() { + @Override + public ValidationResult validate(String optName, String optValue, ValidationContext context) { + final ValidationResult.Builder builder = new ValidationResult.Builder(); + builder.subject(optName).input(optValue); + + try { + URI uri = new URI(optValue); + if (uri.isAbsolute()) { + builder.valid(true); + } else { + builder.valid(false).explanation("Base URI must be an absolute URI of the form :"); + } + } catch (URISyntaxException e) { + builder.valid(false).explanation("Base URi is not a valid URI: " + e.getMessage()); + } + + return builder.build(); + } + }; + + + // note that the names of these properties and relationships intentionally + // have spaces so they cannot conflict with XProc option and output port + // names, which are restricted to QName's and NCName's + public static final PropertyDescriptor XML_PIPELINE_FILE = new PropertyDescriptor.Builder() + .name("xml pipeline file") + .displayName("XML Pipeline File") + .description("Full path to a file containing the XProc XML pipeline configuration. Only one of XML Pipeline File or XML Pipeline Config may be used.") + .required(false) + .addValidator(StandardValidators.FILE_EXISTS_VALIDATOR) + .addValidator(XML_PIPELINE_VALIDATOR) + .build(); + + public static final PropertyDescriptor XML_PIPELINE_CONFIG = new PropertyDescriptor.Builder() + .name("xml pipeline config") + .displayName("XML Pipeline Config") + .description("XProc XML pipeline configuration. Only one of XML Pipeline File or XML Pipeline Config may be used.") + .required(false) + .addValidator(Validator.VALID) + .addValidator(XML_PIPELINE_VALIDATOR) + .build(); + + public static final PropertyDescriptor BASE_URI = new PropertyDescriptor.Builder() + .name("base uri") + .displayName("Base URI") + .description("An absolute URI to used to resolve relative URIs in the XProc pipeline configuration. Must provide a scheme (e.g. file:, http:) followed by an absolute path. For example, file://path/for/resolving/ or http://example.com/resolving. Only required when the XML Pipeline Config property is provided.") + .required(false) + .addValidator(BASE_URI_VALIDATOR) + .build(); + + public static final Relationship REL_PIPELINE_FAILURE = new Relationship.Builder() + .name("pipeline failure") + .description("FlowFiles that fail XProc processing are routed here") + .build(); + public static final Relationship REL_PIPELINE_ORIGINAL = new Relationship.Builder() + .name("original xml") + .description("FlowFiles that successfully complete XProc processing are routed here") + .build(); + + @Override + protected void init(final ProcessorInitializationContext context) { + final List properties = new ArrayList<>(); + properties.add(XML_PIPELINE_FILE); + properties.add(XML_PIPELINE_CONFIG); + properties.add(BASE_URI); + this.properties = Collections.unmodifiableList(properties); + + final Set set = new HashSet<>(); + set.add(REL_PIPELINE_FAILURE); + set.add(REL_PIPELINE_ORIGINAL); + relationships = new AtomicReference<>(set); + } + + @Override + public Set getRelationships() { + return relationships.get(); + } + + @Override + public final List getSupportedPropertyDescriptors() { + return properties; + } + + @Override + protected PropertyDescriptor getSupportedDynamicPropertyDescriptor(final String propertyDescriptorName) { + return new PropertyDescriptor.Builder() + .name(propertyDescriptorName) + .expressionLanguageSupported(true) + .required(false) + .addValidator(XPROC_OPTION_NAME_VALIDATOR) + .addValidator(StandardValidators.createAttributeExpressionLanguageValidator(AttributeExpression.ResultType.STRING, true)) + .dynamic(true) + .build(); + } + + @Override + protected Collection customValidate(final ValidationContext validationContext) { + Set results = new HashSet<>(); + + final Set newRelationships = new HashSet<>(); + newRelationships.add(REL_PIPELINE_FAILURE); + newRelationships.add(REL_PIPELINE_ORIGINAL); + + Map propertyMap = validationContext.getProperties(); + final String pipelineFile = propertyMap.get(XML_PIPELINE_FILE); + final String pipelineConfig = propertyMap.get(XML_PIPELINE_CONFIG); + + if (StringUtils.isEmpty(pipelineFile) == StringUtils.isEmpty(pipelineConfig)) { + results.add(new ValidationResult.Builder().valid(false).explanation( + "Exactly one of XML Pipeline File or XML Pipeline Config must be set").build()); + this.relationships.set(newRelationships); + return results; + } + + PipelineXmlData pd = null; + try { + if (!StringUtils.isEmpty(pipelineFile)) { + pd = new PipelineXmlData(new Input(pipelineFile)); + } else { + final String baseURI = propertyMap.get(BASE_URI); + if (baseURI == null) { + results.add(new ValidationResult.Builder().valid(false).explanation( + "Base URI is required when XML Pipeline Config is set").build()); + this.relationships.set(newRelationships); + return results; + } + pd = new PipelineXmlData(pipelineConfig, new URI(baseURI)); + } + } catch (Exception e) { + // shouldn't be possible, everything used should have been validated in the individual validators + results.add(new ValidationResult.Builder().valid(false).explanation( + "Failed to parse pipeline data: " + e).build()); + this.relationships.set(newRelationships); + return results; + } + + inputPort = findPrimaryInputPort(pd.pipeline); + + // we know everything is valid, so lets add the new output port relationships + final Set outputPorts = pd.pipeline.getOutputs(); + for (final String outputPort: outputPorts) { + final Relationship outputRel = new Relationship.Builder() + .name(outputPort) + .description("The XProc output port named '" + outputPort + "'") + .build(); + newRelationships.add(outputRel); + } + + this.relationships.set(newRelationships); + + return results; + } + + @OnScheduled + public void onScheduled(final ProcessContext context) throws SaxonApiException, URISyntaxException { + final String pipelineFile = context.getProperty(XML_PIPELINE_FILE).getValue(); + final String pipelineConfig = context.getProperty(XML_PIPELINE_CONFIG).getValue(); + final int pipelinePoolSize = context.getMaxConcurrentTasks(); + pipelinePool = new ArrayBlockingQueue<>(pipelinePoolSize); + for (int i = 0; i < pipelinePoolSize; i++) { + final PipelineXmlData pd; + if (!StringUtils.isEmpty(pipelineFile)) { + pd = new PipelineXmlData(new Input(pipelineFile)); + } else { + final String baseURI = context.getProperty(BASE_URI).getValue(); + pd = new PipelineXmlData(pipelineConfig, new URI(baseURI)); + } + pipelinePool.add(pd); + } + } + + @OnStopped + public void onStopped(final ProcessContext context) { + pipelinePool.clear(); + pipelinePool = null; + } + + private void handleInput(PipelineXmlData pd, ProcessContext context, FlowFile original, InputStream stream) throws SaxonApiException { + XdmNode inputNode = pd.runtime.parse(new InputSource(stream)); + pd.pipeline.writeTo(inputPort, inputNode); + + for (final Map.Entry entry : context.getProperties().entrySet()) { + if (!entry.getKey().isDynamic()) { + continue; + } + final QName optName = QName.fromClarkName(entry.getKey().getName()); + final String value = context.newPropertyValue(entry.getValue()).evaluateAttributeExpressions(original).getValue(); + pd.pipeline.passOption(optName, new RuntimeValue(value)); + } + } + + private void handleOutput(PipelineXmlData pd, ProcessSession session, FlowFile original, List> outputs) throws SaxonApiException { + int fragmentCount = 0; + + for (final Relationship rel: getRelationships()) { + if (rel == REL_PIPELINE_FAILURE || rel == REL_PIPELINE_ORIGINAL) { + continue; + } + + final ReadablePipe rpipe = pd.pipeline.readFrom(rel.getName()); + final Serialization serial = pd.pipeline.getSerialization(rel.getName()); + + while (rpipe.moreDocuments()) { + final XdmNode node = rpipe.read(); + + FlowFile outputFF = session.create(original); + outputFF = session.write(outputFF, out -> { + final WritableDocument wd = new WritableDocument(pd.runtime, null, serial, out); + wd.write(node); + }); + + outputFF = session.putAttribute(outputFF, FRAGMENT_INDEX.key(), String.valueOf(fragmentCount++)); + outputs.add(new SimpleEntry(rel, outputFF)); + } + } + } + + @Override + public void onTrigger(final ProcessContext context, final ProcessSession session) throws ProcessException { + PipelineXmlData pd = null; + try { + pd = pipelinePool.take(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + + final FlowFile original = session.get(); + if (original == null) { + pipelinePool.add(pd); + return; + } + + final List> outputs = new ArrayList<>(); + + final InputStream stream = session.read(original); + try { + pd.pipeline.reset(); + handleInput(pd, context, original, stream); + pd.pipeline.run(); + handleOutput(pd, session, original, outputs); + + // We got here without any errors, transfor the original and output + // flow files + final String fragmentIdentifier = UUID.randomUUID().toString(); + final String numberOfOutputs = Integer.toString(outputs.size()); + final FlowFile originalToTransfer = copyAttributesToOriginal(session, original, fragmentIdentifier, outputs.size()); + session.transfer(originalToTransfer, REL_PIPELINE_ORIGINAL); + for (Map.Entry entry : outputs) { + final Relationship rel = entry.getKey(); + FlowFile ff = entry.getValue(); + ff = session.putAttribute(ff, FRAGMENT_COUNT.key(), numberOfOutputs); + ff = session.putAttribute(ff, FRAGMENT_ID.key(), fragmentIdentifier); + ff = session.putAttribute(ff, SEGMENT_ORIGINAL_FILENAME.key(), originalToTransfer.getAttribute(CoreAttributes.FILENAME.key())); + session.transfer(ff, rel); + } + } catch (SaxonApiException | XProcException e) { + // If we got here, there was an error and nothing was transferred. + // So transfer the original file to the pipeline failure + // relationship and remove any output flow files that we may have + // created before hitting the error. + getLogger().error("Failed to process {} due to {}", new Object[]{original, e}); + session.transfer(original, REL_PIPELINE_FAILURE); + for (Map.Entry entry : outputs) { + session.remove(entry.getValue()); + } + } finally { + // add the pipeline data back to the pool. The pool should always + // have enough capacity so this should never fail + pipelinePool.add(pd); + IOUtils.closeQuietly(stream); + } + } +} diff --git a/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/main/java/org/apache/nifi/processors/xmlcalabash/PipelineXmlData.java b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/main/java/org/apache/nifi/processors/xmlcalabash/PipelineXmlData.java new file mode 100644 index 000000000000..bc2b73afb8c5 --- /dev/null +++ b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/main/java/org/apache/nifi/processors/xmlcalabash/PipelineXmlData.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.nifi.processors.xmlcalabash; + +import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.net.URI; +import javax.xml.transform.sax.SAXSource; + +import org.xml.sax.InputSource; + +import net.sf.saxon.s9api.DocumentBuilder; +import net.sf.saxon.s9api.Processor; +import net.sf.saxon.s9api.SaxonApiException; +import net.sf.saxon.s9api.XdmNode; + +import com.xmlcalabash.util.Input; +import com.xmlcalabash.core.XProcConfiguration; +import com.xmlcalabash.core.XProcException; +import com.xmlcalabash.core.XProcRuntime; +import com.xmlcalabash.runtime.XPipeline; + +class PipelineXmlData { + static private final Processor saxon = new Processor(false); + static private final XProcConfiguration config = new XProcConfiguration(saxon); + public XProcRuntime runtime = null; + public XPipeline pipeline = null; + + public PipelineXmlData(String pipelineData, URI baseURI) throws SaxonApiException, XProcException { + InputStream stream = new ByteArrayInputStream(pipelineData.getBytes()); + DocumentBuilder builder = saxon.newDocumentBuilder(); + if (baseURI != null) { + builder.setBaseURI(baseURI); + } + XdmNode pipelineNode = builder.build(new SAXSource(new InputSource(stream))); + + runtime = new XProcRuntime(config); + pipeline = runtime.use(pipelineNode); + } + + public PipelineXmlData(Input pipelineFile) throws SaxonApiException, XProcException { + runtime = new XProcRuntime(config); + pipeline = runtime.load(pipelineFile); + } + +} diff --git a/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor new file mode 100644 index 000000000000..7219872030c3 --- /dev/null +++ b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor @@ -0,0 +1,15 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +org.apache.nifi.processors.xmlcalabash.PipelineXml diff --git a/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/java/org/apache/nifi/processors/xmlcalabash/TestPipelineXml.java b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/java/org/apache/nifi/processors/xmlcalabash/TestPipelineXml.java new file mode 100644 index 000000000000..180c5f808dbe --- /dev/null +++ b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/java/org/apache/nifi/processors/xmlcalabash/TestPipelineXml.java @@ -0,0 +1,266 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.nifi.processors.xmlcalabash; + +import java.io.IOException; +import java.nio.file.Paths; +import java.nio.file.Files; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; +import org.junit.Assert; + +import org.apache.nifi.components.ValidationResult; +import org.apache.nifi.util.MockFlowFile; +import org.apache.nifi.util.TestRunner; +import org.apache.nifi.util.TestRunners; + +import static org.apache.nifi.flowfile.attributes.FragmentAttributes.FRAGMENT_COUNT; +import static org.apache.nifi.flowfile.attributes.FragmentAttributes.FRAGMENT_INDEX; + +public class TestPipelineXml { + + @Test + public void testBadXPL() throws IOException { + final TestRunner testRunner = TestRunners.newTestRunner(PipelineXml.class); + final ValidationResult vr = testRunner.setProperty(PipelineXml.XML_PIPELINE_FILE, "src/test/resources/bad.xpl"); + testRunner.assertNotValid(); + Assert.assertTrue(vr.getExplanation().indexOf("default value on a required option") >= 0); + } + + @Test + public void testOptionUsingDefault() throws IOException { + final TestRunner testRunner = TestRunners.newTestRunner(PipelineXml.class); + testRunner.setProperty(PipelineXml.XML_PIPELINE_FILE, "src/test/resources/addAttributes.xpl"); + testRunner.setProperty("attributeValA", "attrA"); + testRunner.enqueue(Paths.get("src/test/resources/input.xml")); + testRunner.run(); + testRunner.assertTransferCount("result", 1); + testRunner.assertTransferCount("original xml", 1); + final MockFlowFile result = testRunner.getFlowFilesForRelationship("result").get(0); + final String expectedContent = new String(Files.readAllBytes(Paths.get("src/test/resources/addAttributes1.xml"))); + result.assertContentEquals(expectedContent); + } + + @Test + public void testPropertyOverrideOptionDefault() throws IOException { + final TestRunner testRunner = TestRunners.newTestRunner(PipelineXml.class); + testRunner.setProperty(PipelineXml.XML_PIPELINE_FILE, "src/test/resources/addAttributes.xpl"); + testRunner.setProperty("attributeValA", "attrA"); + testRunner.setProperty("attributeValB", "attrB"); + testRunner.enqueue(Paths.get("src/test/resources/input.xml")); + testRunner.run(); + testRunner.assertTransferCount("result", 1); + testRunner.assertTransferCount("original xml", 1); + final MockFlowFile result = testRunner.getFlowFilesForRelationship("result").get(0); + final String expectedContent = new String(Files.readAllBytes(Paths.get("src/test/resources/addAttributes2.xml"))); + result.assertContentEquals(expectedContent); + } + + @Test + public void testPropertyAsExpression() throws IOException { + final TestRunner testRunner = TestRunners.newTestRunner(PipelineXml.class); + testRunner.setProperty(PipelineXml.XML_PIPELINE_FILE, "src/test/resources/addAttributes.xpl"); + testRunner.setProperty("attributeValA", "${filename}"); + testRunner.setProperty("attributeValB", "attrB"); + testRunner.enqueue(Paths.get("src/test/resources/input.xml")); + testRunner.run(); + testRunner.assertTransferCount("result", 1); + testRunner.assertTransferCount("original xml", 1); + final MockFlowFile result = testRunner.getFlowFilesForRelationship("result").get(0); + final String expectedContent = new String(Files.readAllBytes(Paths.get("src/test/resources/addAttributes3.xml"))); + result.assertContentEquals(expectedContent); + } + + @Test + public void testConfig() throws IOException { + final TestRunner testRunner = TestRunners.newTestRunner(PipelineXml.class); + String config = new String(Files.readAllBytes(Paths.get("src/test/resources/addAttributes.xpl"))); + testRunner.setProperty(PipelineXml.BASE_URI, "http://example.com"); + testRunner.setProperty(PipelineXml.XML_PIPELINE_CONFIG, config); + testRunner.setProperty("attributeValA", "attrA"); + testRunner.enqueue(Paths.get("src/test/resources/input.xml")); + testRunner.run(); + testRunner.assertTransferCount("result", 1); + testRunner.assertTransferCount("original xml", 1); + final MockFlowFile result = testRunner.getFlowFilesForRelationship("result").get(0); + final String expectedContent = new String(Files.readAllBytes(Paths.get("src/test/resources/addAttributes1.xml"))); + result.assertContentEquals(expectedContent); + } + + @Test + public void testConfigNonFileInput() throws IOException { + final TestRunner testRunner = TestRunners.newTestRunner(PipelineXml.class); + String config = new String(Files.readAllBytes(Paths.get("src/test/resources/addAttributes.xpl"))); + testRunner.setProperty(PipelineXml.BASE_URI, "http://example.com"); + testRunner.setProperty(PipelineXml.XML_PIPELINE_CONFIG, config); + testRunner.setProperty("attributeValA", "attrA"); + byte[] bytes = Files.readAllBytes(Paths.get("src/test/resources/input.xml")); + testRunner.enqueue(bytes); + testRunner.run(); + testRunner.assertTransferCount("result", 1); + testRunner.assertTransferCount("original xml", 1); + final MockFlowFile result = testRunner.getFlowFilesForRelationship("result").get(0); + final String expectedContent = new String(Files.readAllBytes(Paths.get("src/test/resources/addAttributes1.xml"))); + result.assertContentEquals(expectedContent); + } + + @Test + public void testConfigNoBaseURI() throws IOException { + final TestRunner testRunner = TestRunners.newTestRunner(PipelineXml.class); + String config = new String(Files.readAllBytes(Paths.get("src/test/resources/addAttributes.xpl"))); + //testRunner.setProperty(PipelineXml.BASE_URI, "http://example.com"); + testRunner.setProperty(PipelineXml.XML_PIPELINE_CONFIG, config); + testRunner.setProperty("attributeValA", "attrA"); + testRunner.assertNotValid(); + } + + @Test + public void testConfigBaseURINoScheme() throws IOException { + final TestRunner testRunner = TestRunners.newTestRunner(PipelineXml.class); + String config = new String(Files.readAllBytes(Paths.get("src/test/resources/addAttributes.xpl"))); + testRunner.setProperty(PipelineXml.BASE_URI, "/path/to/file"); // missing a scheme + testRunner.setProperty(PipelineXml.XML_PIPELINE_CONFIG, config); + testRunner.setProperty("attributeValA", "attrA"); + testRunner.assertNotValid(); + } + + @Test + public void testConfigBaseURISyntaxError() throws IOException { + final TestRunner testRunner = TestRunners.newTestRunner(PipelineXml.class); + String config = new String(Files.readAllBytes(Paths.get("src/test/resources/addAttributes.xpl"))); + testRunner.setProperty(PipelineXml.BASE_URI, "$invalid:::"); // missing a scheme + testRunner.setProperty(PipelineXml.XML_PIPELINE_CONFIG, config); + testRunner.setProperty("attributeValA", "attrA"); + testRunner.assertNotValid(); + } + + @Test + public void testBothConfigAndFile() throws IOException { + final TestRunner testRunner = TestRunners.newTestRunner(PipelineXml.class); + String config = new String(Files.readAllBytes(Paths.get("src/test/resources/addAttributes.xpl"))); + testRunner.setProperty(PipelineXml.BASE_URI, "http://example.com"); + testRunner.setProperty(PipelineXml.XML_PIPELINE_CONFIG, config); + testRunner.setProperty(PipelineXml.XML_PIPELINE_FILE, "src/test/resources/addAttributes.xpl"); + testRunner.assertNotValid(); + } + + @Test + public void testNeighterConfigNorFile() throws IOException { + final TestRunner testRunner = TestRunners.newTestRunner(PipelineXml.class); + //String config = new String(Files.readAllBytes(Paths.get("src/test/resources/addAttributes.xpl"))); + //testRunner.setProperty(PipelineXml.XML_PIPELINE_CONFIG, config); + //testRunner.setProperty(PipelineXml.XML_PIPELINE_FILE, "src/test/resources/addAttributes.xpl"); + testRunner.assertNotValid(); + } + + @Test + public void testMissingRequiredOption() throws IOException { + final TestRunner testRunner = TestRunners.newTestRunner(PipelineXml.class); + testRunner.setProperty(PipelineXml.XML_PIPELINE_FILE, "src/test/resources/addAttributes.xpl"); + testRunner.enqueue(Paths.get("src/test/resources/input.xml")); + testRunner.run(); + testRunner.assertAllFlowFilesTransferred(PipelineXml.REL_PIPELINE_FAILURE); + final MockFlowFile failure = testRunner.getFlowFilesForRelationship(PipelineXml.REL_PIPELINE_FAILURE).get(0); + final String expectedContent = new String(Files.readAllBytes(Paths.get("src/test/resources/input.xml"))); + failure.assertContentEquals(expectedContent); + } + + @Test + public void testMultipleOutputs() throws IOException { + final TestRunner testRunner = TestRunners.newTestRunner(PipelineXml.class); + testRunner.setProperty(PipelineXml.XML_PIPELINE_FILE, "src/test/resources/multipleOutputs.xpl"); + testRunner.enqueue(Paths.get("src/test/resources/input.xml")); + testRunner.run(); + testRunner.assertTransferCount("a", 1); + testRunner.assertTransferCount("b", 2); + testRunner.assertTransferCount("original xml", 1); + final MockFlowFile a1 = testRunner.getFlowFilesForRelationship("a").get(0); + final MockFlowFile b1 = testRunner.getFlowFilesForRelationship("b").get(0); + final MockFlowFile b2 = testRunner.getFlowFilesForRelationship("b").get(1); + a1.assertContentEquals("Foo"); + b1.assertContentEquals("Bar"); + b2.assertContentEquals("Baz"); + a1.assertAttributeEquals(FRAGMENT_INDEX.key(), "0"); + b1.assertAttributeEquals(FRAGMENT_INDEX.key(), "1"); + b2.assertAttributeEquals(FRAGMENT_INDEX.key(), "2"); + a1.assertAttributeEquals(FRAGMENT_COUNT.key(), "3"); + b1.assertAttributeEquals(FRAGMENT_COUNT.key(), "3"); + b2.assertAttributeEquals(FRAGMENT_COUNT.key(), "3"); + } + + @Test + public void testNoOutputs() throws IOException { + final TestRunner testRunner = TestRunners.newTestRunner(PipelineXml.class); + testRunner.setProperty(PipelineXml.XML_PIPELINE_FILE, "src/test/resources/noOutputs.xpl"); + testRunner.enqueue(Paths.get("src/test/resources/input.xml")); + testRunner.run(); + } + + @Test + public void testNoPrimaryInputPort() throws IOException { + final TestRunner testRunner = TestRunners.newTestRunner(PipelineXml.class); + final ValidationResult vr = testRunner.setProperty(PipelineXml.XML_PIPELINE_FILE, "src/test/resources/noPrimaryPort.xpl"); + testRunner.assertNotValid(); + Assert.assertTrue(vr.getExplanation().indexOf("primary non-parameter input port") >= 0); + } + + @Test + public void testInputNotXML() throws IOException { + final TestRunner testRunner = TestRunners.newTestRunner(PipelineXml.class); + final ValidationResult vr = testRunner.setProperty(PipelineXml.XML_PIPELINE_FILE, "src/test/resources/noOutputs.xpl"); + testRunner.enqueue("not valid xml"); + testRunner.run(); + testRunner.assertAllFlowFilesTransferred(PipelineXml.REL_PIPELINE_FAILURE); + final MockFlowFile failure = testRunner.getFlowFilesForRelationship(PipelineXml.REL_PIPELINE_FAILURE).get(0); + failure.assertContentEquals("not valid xml"); + } + + @Test + public void testBaseURIExpression() throws IOException { + final TestRunner testRunner = TestRunners.newTestRunner(PipelineXml.class); + final Map attributes = new HashMap<>(); + attributes.put("absolute.path", "/path/to/file"); + testRunner.setProperty(PipelineXml.XML_PIPELINE_FILE, "src/test/resources/addAttributes.xpl"); + testRunner.setProperty("attributeValA", "attrA"); + testRunner.enqueue(Paths.get("src/test/resources/input.xml"), attributes); + testRunner.run(); + testRunner.assertTransferCount("result", 1); + testRunner.assertTransferCount("original xml", 1); + final MockFlowFile result = testRunner.getFlowFilesForRelationship("result").get(0); + final String expectedContent = new String(Files.readAllBytes(Paths.get("src/test/resources/addAttributes1.xml"))); + result.assertContentEquals(expectedContent); + } + + @Test + public void testNonFileBaseInputFlowFile() throws IOException { + final TestRunner testRunner = TestRunners.newTestRunner(PipelineXml.class); + testRunner.setProperty(PipelineXml.XML_PIPELINE_FILE, "src/test/resources/addAttributes.xpl"); + testRunner.setProperty("attributeValA", "attrA"); + byte[] bytes = Files.readAllBytes(Paths.get("src/test/resources/input.xml")); + testRunner.enqueue(bytes); + testRunner.run(); + testRunner.assertTransferCount("result", 1); + testRunner.assertTransferCount("original xml", 1); + final MockFlowFile result = testRunner.getFlowFilesForRelationship("result").get(0); + final String expectedContent = new String(Files.readAllBytes(Paths.get("src/test/resources/addAttributes1.xml"))); + result.assertContentEquals(expectedContent); + } + +} diff --git a/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/addAttributes.xpl b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/addAttributes.xpl new file mode 100644 index 000000000000..84a94a660d27 --- /dev/null +++ b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/addAttributes.xpl @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + diff --git a/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/addAttributes1.xml b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/addAttributes1.xml new file mode 100644 index 000000000000..469e3ec69da7 --- /dev/null +++ b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/addAttributes1.xml @@ -0,0 +1,5 @@ + + Foo + Bar + Baz + \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/addAttributes2.xml b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/addAttributes2.xml new file mode 100644 index 000000000000..8f629f6e5fc0 --- /dev/null +++ b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/addAttributes2.xml @@ -0,0 +1,5 @@ + + Foo + Bar + Baz + \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/addAttributes3.xml b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/addAttributes3.xml new file mode 100644 index 000000000000..e8573ab5e93b --- /dev/null +++ b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/addAttributes3.xml @@ -0,0 +1,5 @@ + + Foo + Bar + Baz + \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/bad.xpl b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/bad.xpl new file mode 100644 index 000000000000..873147e02c9f --- /dev/null +++ b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/bad.xpl @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + diff --git a/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/input.xml b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/input.xml new file mode 100644 index 000000000000..4523dac69cfc --- /dev/null +++ b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/input.xml @@ -0,0 +1,5 @@ + + Foo + Bar + Baz + diff --git a/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/multipleOutputs.xpl b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/multipleOutputs.xpl new file mode 100644 index 000000000000..6a8a5fd52ca0 --- /dev/null +++ b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/multipleOutputs.xpl @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/noOutputs.xpl b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/noOutputs.xpl new file mode 100644 index 000000000000..dcbdc0bf34ff --- /dev/null +++ b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/noOutputs.xpl @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/noPrimaryPort.xpl b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/noPrimaryPort.xpl new file mode 100644 index 000000000000..bc2066e41f24 --- /dev/null +++ b/nifi-nar-bundles/nifi-xmlcalabash-bundle/nifi-pipelinexml-processors/src/test/resources/noPrimaryPort.xpl @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/nifi-nar-bundles/nifi-xmlcalabash-bundle/pom.xml b/nifi-nar-bundles/nifi-xmlcalabash-bundle/pom.xml new file mode 100644 index 000000000000..0188513b7fee --- /dev/null +++ b/nifi-nar-bundles/nifi-xmlcalabash-bundle/pom.xml @@ -0,0 +1,35 @@ + + + + 4.0.0 + + + org.apache.nifi + nifi-nar-bundles + 1.3.0-SNAPSHOT + + + org.apache.nifi + nifi-xmlcalabash-bundle + 1.3.0-SNAPSHOT + pom + + + nifi-pipelinexml-processors + nifi-pipelinexml-nar + + + diff --git a/nifi-nar-bundles/pom.xml b/nifi-nar-bundles/pom.xml index a2887b8385da..5ef33c24e345 100755 --- a/nifi-nar-bundles/pom.xml +++ b/nifi-nar-bundles/pom.xml @@ -83,6 +83,7 @@ nifi-cybersecurity-bundle nifi-parquet-bundle nifi-extension-utils + nifi-xmlcalabash-bundle diff --git a/pom.xml b/pom.xml index 8794abd6e154..1f34510f9355 100644 --- a/pom.xml +++ b/pom.xml @@ -1433,6 +1433,12 @@ 1.3.0-SNAPSHOT nar + + org.apache.nifi + nifi-pipelinexml-nar + 1.3.0-SNAPSHOT + nar + org.apache.nifi nifi-properties