nifi-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jperciv...@apache.org
Subject [2/2] nifi git commit: NIFI-1976 - Windows Event Log native processor
Date Wed, 29 Jun 2016 22:01:54 GMT
NIFI-1976 - Windows Event Log native processor

This closes #525

Signed-off-by: jpercivall <joepercivall@yahoo.com>


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/65d89582
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/65d89582
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/65d89582

Branch: refs/heads/master
Commit: 65d895827b3ca979c41daa781f1cd0d04e24c65a
Parents: d639165
Author: Bryan Rosander <bryanrosander@gmail.com>
Authored: Tue Jun 7 08:57:24 2016 -0400
Committer: jpercivall <joepercivall@yahoo.com>
Committed: Wed Jun 29 17:48:39 2016 -0400

----------------------------------------------------------------------
 nifi-assembly/NOTICE                            |   5 +
 nifi-assembly/pom.xml                           |   5 +
 .../nifi-windows-event-log-nar/pom.xml          |  40 +++
 .../src/main/resources/META-INF/LICENSE         | 202 ++++++++++++
 .../src/main/resources/META-INF/NOTICE          |  23 ++
 .../nifi-windows-event-log-processors/pom.xml   |  66 ++++
 .../event/log/AlreadySubscribedException.java   |  24 ++
 .../event/log/ConsumeWindowsEventLog.java       | 318 +++++++++++++++++++
 .../windows/event/log/jna/ErrorLookup.java      |  51 +++
 .../jna/EventSubscribeXmlRenderingCallback.java | 108 +++++++
 .../windows/event/log/jna/WEvtApi.java          |  70 ++++
 .../org.apache.nifi.processor.Processor         |  15 +
 .../additionalDetails.html                      |  74 +++++
 .../log/ConsumeWindowsEventLogFailTest.java     |  39 +++
 .../event/log/ConsumeWindowsEventLogTest.java   | 268 ++++++++++++++++
 .../windows/event/log/JNAFailJUnitRunner.java   |  42 +++
 .../windows/event/log/JNAJUnitRunner.java       |  51 +++
 .../event/log/JNAOverridingJUnitRunner.java     |  99 ++++++
 .../windows/event/log/jna/ErrorLookupTest.java  |  54 ++++
 .../EventSubscribeXmlRenderingCallbackTest.java | 135 ++++++++
 .../nifi-windows-event-log-bundle/pom.xml       |  44 +++
 nifi-nar-bundles/pom.xml                        |   1 +
 pom.xml                                         |   6 +
 23 files changed, 1740 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/65d89582/nifi-assembly/NOTICE
----------------------------------------------------------------------
diff --git a/nifi-assembly/NOTICE b/nifi-assembly/NOTICE
index 8320bab..0c2a4a5 100644
--- a/nifi-assembly/NOTICE
+++ b/nifi-assembly/NOTICE
@@ -771,6 +771,11 @@ The following binary components are provided under the Apache Software License v
 
         Licensed under the Apache License, Version 2.0
 
+    (ASLv2) Java Native Access
+      The following NOTICE information applies:
+         Java Native Access
+         Copyright 2015 Java Native Access
+
     (ASLv2) HTrace Core
       The following NOTICE information applies:
         In addition, this product includes software dependencies. See

http://git-wip-us.apache.org/repos/asf/nifi/blob/65d89582/nifi-assembly/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-assembly/pom.xml b/nifi-assembly/pom.xml
index 6a75018..b7ef7d7 100644
--- a/nifi-assembly/pom.xml
+++ b/nifi-assembly/pom.xml
@@ -347,6 +347,11 @@ language governing permissions and limitations under the License. -->
             <artifactId>nifi-slack-nar</artifactId>
             <type>nar</type>
         </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-windows-event-log-nar</artifactId>
+            <type>nar</type>
+        </dependency>
     </dependencies>
 
     <properties>

http://git-wip-us.apache.org/repos/asf/nifi/blob/65d89582/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-nar/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-nar/pom.xml b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-nar/pom.xml
new file mode 100644
index 0000000..60ed53d
--- /dev/null
+++ b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-nar/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>nifi-windows-event-log-bundle</artifactId>
+        <groupId>org.apache.nifi</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.nifi</groupId>
+    <artifactId>nifi-windows-event-log-nar</artifactId>
+    <packaging>nar</packaging>
+    <properties>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
+        <source.skip>true</source.skip>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-standard-services-api-nar</artifactId>
+            <type>nar</type>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-windows-event-log-processors</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/nifi/blob/65d89582/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-nar/src/main/resources/META-INF/LICENSE
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-nar/src/main/resources/META-INF/LICENSE b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-nar/src/main/resources/META-INF/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-nar/src/main/resources/META-INF/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.

http://git-wip-us.apache.org/repos/asf/nifi/blob/65d89582/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-nar/src/main/resources/META-INF/NOTICE
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-nar/src/main/resources/META-INF/NOTICE b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-nar/src/main/resources/META-INF/NOTICE
new file mode 100644
index 0000000..c3e041e
--- /dev/null
+++ b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-nar/src/main/resources/META-INF/NOTICE
@@ -0,0 +1,23 @@
+nifi-windows-event-log-nar
+Copyright 2015-2016 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) Java Native Access
+    The following NOTICE information applies:
+       Java Native Access
+       Copyright 2015 Java Native Access
+
+  (ASLv2) Apache Commons Lang
+    The following NOTICE information applies:
+      Apache Commons Lang
+      Copyright 2001-2014 The Apache Software Foundation
+
+      This product includes software from the Spring Framework,
+      under the Apache License 2.0 (see: StringUtils.containsWhitespace())

http://git-wip-us.apache.org/repos/asf/nifi/blob/65d89582/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/pom.xml b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/pom.xml
new file mode 100644
index 0000000..551314b
--- /dev/null
+++ b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/pom.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>nifi-windows-event-log-bundle</artifactId>
+        <groupId>org.apache.nifi</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>nifi-windows-event-log-processors</artifactId>
+    <packaging>jar</packaging>
+
+    <properties>
+        <jna.version>4.2.2</jna.version>
+        <javassist.version>3.20.0-GA</javassist.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-properties</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-processor-utils</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>net.java.dev.jna</groupId>
+            <artifactId>jna</artifactId>
+            <version>${jna.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>net.java.dev.jna</groupId>
+            <artifactId>jna-platform</artifactId>
+            <version>${jna.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-mock</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.javassist</groupId>
+            <artifactId>javassist</artifactId>
+            <version>${javassist.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/nifi/blob/65d89582/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/AlreadySubscribedException.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/AlreadySubscribedException.java b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/AlreadySubscribedException.java
new file mode 100644
index 0000000..b28ac61
--- /dev/null
+++ b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/AlreadySubscribedException.java
@@ -0,0 +1,24 @@
+/*
+ * 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.windows.event.log;
+
+public class AlreadySubscribedException extends Exception {
+    public AlreadySubscribedException(String message) {
+        super(message);
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/65d89582/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/ConsumeWindowsEventLog.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/ConsumeWindowsEventLog.java b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/ConsumeWindowsEventLog.java
new file mode 100644
index 0000000..8a6f23c
--- /dev/null
+++ b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/ConsumeWindowsEventLog.java
@@ -0,0 +1,318 @@
+/*
+ * 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.windows.event.log;
+
+import com.sun.jna.platform.win32.Kernel32;
+import com.sun.jna.platform.win32.Kernel32Util;
+import com.sun.jna.platform.win32.WinNT;
+import org.apache.commons.io.Charsets;
+import org.apache.nifi.annotation.behavior.InputRequirement;
+import org.apache.nifi.annotation.behavior.TriggerSerially;
+import org.apache.nifi.annotation.behavior.WritesAttribute;
+import org.apache.nifi.annotation.behavior.WritesAttributes;
+import org.apache.nifi.annotation.documentation.CapabilityDescription;
+import org.apache.nifi.annotation.documentation.Tags;
+import org.apache.nifi.annotation.lifecycle.OnScheduled;
+import org.apache.nifi.annotation.lifecycle.OnStopped;
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.ValidationContext;
+import org.apache.nifi.components.ValidationResult;
+import org.apache.nifi.flowfile.FlowFile;
+import org.apache.nifi.flowfile.attributes.CoreAttributes;
+import org.apache.nifi.processor.AbstractSessionFactoryProcessor;
+import org.apache.nifi.processor.ProcessContext;
+import org.apache.nifi.processor.ProcessSession;
+import org.apache.nifi.processor.ProcessSessionFactory;
+import org.apache.nifi.processor.Relationship;
+import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.processor.util.StandardValidators;
+import org.apache.nifi.processors.windows.event.log.jna.ErrorLookup;
+import org.apache.nifi.processors.windows.event.log.jna.EventSubscribeXmlRenderingCallback;
+import org.apache.nifi.processors.windows.event.log.jna.WEvtApi;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+
+@InputRequirement(InputRequirement.Requirement.INPUT_FORBIDDEN)
+@Tags({"ingest", "event", "windows"})
+@TriggerSerially
+@CapabilityDescription("Registers a Windows Event Log Subscribe Callback to receive FlowFiles from Events on Windows.  These can be filtered via channel and XPath.")
+@WritesAttributes({
+        @WritesAttribute(attribute = "mime.type", description = "Will set a MIME type value of application/xml.")
+})
+public class ConsumeWindowsEventLog extends AbstractSessionFactoryProcessor {
+    public static final String DEFAULT_CHANNEL = "System";
+    public static final String DEFAULT_XPATH = "*";
+    public static final int DEFAULT_MAX_BUFFER = 1024 * 1024;
+    public static final int DEFAULT_MAX_QUEUE_SIZE = 1024;
+
+    public static final PropertyDescriptor CHANNEL = new PropertyDescriptor.Builder()
+            .name("channel")
+            .displayName("Channel")
+            .required(true)
+            .defaultValue(DEFAULT_CHANNEL)
+            .description("The Windows Event Log Channel to listen to.")
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .build();
+
+    public static final PropertyDescriptor QUERY = new PropertyDescriptor.Builder()
+            .name("query")
+            .displayName("XPath Query")
+            .required(true)
+            .defaultValue(DEFAULT_XPATH)
+            .description("XPath Query to filter events. (See https://msdn.microsoft.com/en-us/library/windows/desktop/dd996910(v=vs.85).aspx for examples.)")
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .build();
+
+    public static final PropertyDescriptor MAX_BUFFER_SIZE = new PropertyDescriptor.Builder()
+            .name("maxBuffer")
+            .displayName("Maximum Buffer Size")
+            .required(true)
+            .defaultValue(Integer.toString(DEFAULT_MAX_BUFFER))
+            .description("The individual Event Log XMLs are rendered to a buffer." +
+                    "  This specifies the maximum size in bytes that the buffer will be allowed to grow to. (Limiting the maximum size of an individual Event XML.)")
+            .addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR)
+            .build();
+
+    public static final PropertyDescriptor MAX_EVENT_QUEUE_SIZE = new PropertyDescriptor.Builder()
+            .name("maxQueue")
+            .displayName("Maximum queue size")
+            .required(true)
+            .defaultValue(Integer.toString(DEFAULT_MAX_QUEUE_SIZE))
+            .description("Events are received asynchronously and must be output as FlowFiles when the processor is triggered." +
+                    "  This specifies the maximum number of events to queue for transformation into FlowFiles.")
+            .addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR)
+            .build();
+
+    public static final List<PropertyDescriptor> PROPERTY_DESCRIPTORS = Collections.unmodifiableList(Arrays.asList(CHANNEL, QUERY, MAX_BUFFER_SIZE, MAX_EVENT_QUEUE_SIZE));
+
+    public static final Relationship REL_SUCCESS = new Relationship.Builder()
+            .name("success")
+            .description("Relationship for successfully consumed events.")
+            .build();
+
+    public static final Set<Relationship> RELATIONSHIPS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(REL_SUCCESS)));
+    public static final String APPLICATION_XML = "application/xml";
+    public static final String UNABLE_TO_SUBSCRIBE = "Unable to subscribe with provided parameters, received the following error code: ";
+    public static final String PROCESSOR_ALREADY_SUBSCRIBED = "Processor already subscribed to Event Log, expected cleanup to unsubscribe.";
+
+    private final WEvtApi wEvtApi;
+    private final Kernel32 kernel32;
+    private final ErrorLookup errorLookup;
+    private final String name;
+
+    private Throwable wEvtApiError = null;
+    private Throwable kernel32Error = null;
+
+    private BlockingQueue<String> renderedXMLs;
+    private WEvtApi.EVT_SUBSCRIBE_CALLBACK evtSubscribeCallback;
+    private WinNT.HANDLE subscriptionHandle;
+    private ProcessSessionFactory sessionFactory;
+    private String provenanceUri;
+
+    /**
+     * Framework constructor
+     */
+    public ConsumeWindowsEventLog() {
+        this(null, null);
+    }
+
+    /**
+     * Constructor that allows injection of JNA interfaces
+     *
+     * @param wEvtApi  event api interface
+     * @param kernel32 kernel interface
+     */
+    public ConsumeWindowsEventLog(WEvtApi wEvtApi, Kernel32 kernel32) {
+        this.wEvtApi = wEvtApi == null ? loadWEvtApi() : wEvtApi;
+        this.kernel32 = kernel32 == null ? loadKernel32() : kernel32;
+        this.errorLookup = new ErrorLookup(this.kernel32);
+        if (this.kernel32 != null) {
+            name = Kernel32Util.getComputerName();
+        } else {
+            // Won't be able to use the processor anyway because native libraries didn't load
+            name = null;
+        }
+    }
+
+    private WEvtApi loadWEvtApi() {
+        try {
+            return WEvtApi.INSTANCE;
+        } catch (Throwable e) {
+            wEvtApiError = e;
+            return null;
+        }
+    }
+
+    private Kernel32 loadKernel32() {
+        try {
+            return Kernel32.INSTANCE;
+        } catch (Throwable e) {
+            kernel32Error = e;
+            return null;
+        }
+    }
+
+    /**
+     * Register subscriber via native call
+     *
+     * @param context the process context
+     */
+    private String subscribe(ProcessContext context) throws URISyntaxException {
+        String channel = context.getProperty(CHANNEL).getValue();
+        String query = context.getProperty(QUERY).getValue();
+
+        renderedXMLs = new LinkedBlockingQueue<>(context.getProperty(MAX_EVENT_QUEUE_SIZE).asInteger());
+        provenanceUri = new URI("winlog", name, "/" + channel, query, null).toASCIIString();
+
+        evtSubscribeCallback = new EventSubscribeXmlRenderingCallback(getLogger(), s -> {
+            try {
+                renderedXMLs.put(s);
+            } catch (InterruptedException e) {
+                throw new IllegalStateException("Got interrupted while waiting to add to queue.", e);
+            }
+        }, context.getProperty(MAX_BUFFER_SIZE).asInteger(), wEvtApi, kernel32, errorLookup);
+
+        subscriptionHandle = wEvtApi.EvtSubscribe(null, null, channel, query, null, null,
+                evtSubscribeCallback, WEvtApi.EvtSubscribeFlags.SUBSCRIBE_TO_FUTURE | WEvtApi.EvtSubscribeFlags.EVT_SUBSCRIBE_STRICT);
+        if (!isSubscribed()) {
+            return UNABLE_TO_SUBSCRIBE + errorLookup.getLastError();
+        }
+        return null;
+    }
+
+    private boolean isSubscribed() {
+        return subscriptionHandle != null && subscriptionHandle.getPointer() != null;
+    }
+
+    @OnScheduled
+    public void onScheduled(ProcessContext context) throws AlreadySubscribedException, URISyntaxException {
+        if (isSubscribed()) {
+            throw new AlreadySubscribedException(PROCESSOR_ALREADY_SUBSCRIBED);
+        }
+        String errorMessage = subscribe(context);
+        if (errorMessage != null) {
+            getLogger().error(errorMessage);
+        }
+    }
+
+    /**
+     * Cleanup
+     */
+    @OnStopped
+    public void stop() {
+        if (isSubscribed()) {
+            wEvtApi.EvtClose(subscriptionHandle);
+        }
+        subscriptionHandle = null;
+        evtSubscribeCallback = null;
+        if (!renderedXMLs.isEmpty()) {
+            if (sessionFactory != null) {
+                getLogger().info("Finishing processing leftover events");
+                ProcessSession session = sessionFactory.createSession();
+                processQueue(session);
+            } else {
+                throw new ProcessException("Stopping the processor but there is no ProcessSessionFactory stored and there are messages in the internal queue. Removing the processor now will " +
+                        "clear the queue but will result in DATA LOSS. This is normally due to starting the processor, receiving events and stopping before the onTrigger happens. The messages " +
+                        "in the internal queue cannot finish processing until until the processor is triggered to run.");
+            }
+        }
+        sessionFactory = null;
+        provenanceUri = null;
+        renderedXMLs = null;
+    }
+
+    @Override
+    public void onTrigger(ProcessContext context, ProcessSessionFactory sessionFactory) throws ProcessException {
+        this.sessionFactory = sessionFactory;
+        if (!isSubscribed()) {
+            String errorMessage;
+            try {
+                errorMessage = subscribe(context);
+            } catch (URISyntaxException e) {
+                getLogger().error(e.getMessage(), e);
+                context.yield();
+                return;
+            }
+            if (errorMessage != null) {
+                context.yield();
+                getLogger().error(errorMessage);
+                return;
+            }
+        }
+        processQueue(sessionFactory.createSession());
+    }
+
+    private void processQueue(ProcessSession session) {
+        String xml;
+        while ((xml = renderedXMLs.peek()) != null) {
+            FlowFile flowFile = session.create();
+            byte[] xmlBytes = xml.getBytes(Charsets.UTF_8);
+            flowFile = session.write(flowFile, out -> out.write(xmlBytes));
+            flowFile = session.putAttribute(flowFile, CoreAttributes.MIME_TYPE.key(), APPLICATION_XML);
+            session.getProvenanceReporter().receive(flowFile, provenanceUri);
+            session.transfer(flowFile, REL_SUCCESS);
+            session.commit();
+            if (!renderedXMLs.remove(xml) && getLogger().isWarnEnabled()) {
+                getLogger().warn(new StringBuilder("Event ")
+                        .append(xml)
+                        .append(" had already been removed from queue, FlowFile ")
+                        .append(flowFile.getAttribute(CoreAttributes.UUID.key()))
+                        .append(" possible duplication of data")
+                        .toString());
+            }
+        }
+    }
+
+    @Override
+    protected Collection<ValidationResult> customValidate(ValidationContext validationContext) {
+        // We need to check to see if the native libraries loaded properly
+        List<ValidationResult> validationResults = new ArrayList<>(super.customValidate(validationContext));
+        if (wEvtApiError != null) {
+            validationResults.add(new ValidationResult.Builder().valid(false).subject("System Configuration")
+                    .explanation("NiFi failed to load wevtapi on this system.  This processor utilizes native Windows APIs and will only work on Windows. ("
+                            + wEvtApiError.getMessage() + ")").build());
+        }
+        if (kernel32Error != null) {
+            validationResults.add(new ValidationResult.Builder().valid(false).subject("System Configuration")
+                    .explanation("NiFi failed to load kernel32 on this system.  This processor utilizes native Windows APIs and will only work on Windows. ("
+                            + kernel32Error.getMessage() + ")").build());
+        }
+        return validationResults;
+    }
+
+    @Override
+    protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
+        return PROPERTY_DESCRIPTORS;
+    }
+
+    @Override
+    public Set<Relationship> getRelationships() {
+        return RELATIONSHIPS;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/65d89582/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/jna/ErrorLookup.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/jna/ErrorLookup.java b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/jna/ErrorLookup.java
new file mode 100644
index 0000000..b608743
--- /dev/null
+++ b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/jna/ErrorLookup.java
@@ -0,0 +1,51 @@
+/*
+ * 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.windows.event.log.jna;
+
+import com.sun.jna.platform.win32.Kernel32;
+import com.sun.jna.platform.win32.WinError;
+
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+
+/**
+ * Reverse lookup of error number to the named error if possible
+ */
+public class ErrorLookup {
+    private final Kernel32 kernel32;
+
+    public ErrorLookup(Kernel32 kernel32) {
+        this.kernel32 = kernel32;
+    }
+
+    public String getLastError() {
+        int lastError = kernel32.GetLastError();
+        return Arrays.stream(WinError.class.getDeclaredFields()).filter(field -> {
+            try {
+                return Modifier.isStatic(field.getModifiers())
+                        && field.getType() == int.class
+                        && field.getName().startsWith("ERROR")
+                        && (int) field.get(null) == lastError;
+            } catch (IllegalAccessException e) {
+                return false;
+            }
+        }).map(field -> field.getName() + "(" + lastError + ")")
+                .findFirst()
+                .orElse(Integer.toString(lastError));
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/65d89582/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/jna/EventSubscribeXmlRenderingCallback.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/jna/EventSubscribeXmlRenderingCallback.java b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/jna/EventSubscribeXmlRenderingCallback.java
new file mode 100644
index 0000000..a563ae8
--- /dev/null
+++ b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/jna/EventSubscribeXmlRenderingCallback.java
@@ -0,0 +1,108 @@
+/*
+ * 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.windows.event.log.jna;
+
+import com.sun.jna.Memory;
+import com.sun.jna.platform.win32.Kernel32;
+import com.sun.jna.platform.win32.W32Errors;
+import com.sun.jna.platform.win32.WinDef;
+import com.sun.jna.platform.win32.WinNT;
+import org.apache.commons.io.Charsets;
+import org.apache.nifi.logging.ComponentLog;
+
+import java.util.function.Consumer;
+
+/**
+ * Callback that will render the XML representation of the event using native Windows API
+ */
+public class EventSubscribeXmlRenderingCallback implements WEvtApi.EVT_SUBSCRIBE_CALLBACK {
+    public static final String RECEIVED_THE_FOLLOWING_WIN32_ERROR = "Received the following Win32 error: ";
+    public static final int INITIAL_BUFFER_SIZE = 1024;
+    public static final String EVT_RENDER_RETURNED_THE_FOLLOWING_ERROR_CODE = "EvtRender returned the following error code ";
+    public static final String MISSING_EVENT_MESSAGE = "Received missing event notification.  Consider triggering processor more frequently or increasing queue size.";
+
+    private final ComponentLog logger;
+    private final Consumer<String> consumer;
+    private final int maxBufferSize;
+    private final WEvtApi wEvtApi;
+    private final Kernel32 kernel32;
+    private final ErrorLookup errorLookup;
+
+    private int size;
+    private Memory buffer;
+    private Memory used;
+    private Memory propertyCount;
+
+    public EventSubscribeXmlRenderingCallback(ComponentLog logger, Consumer<String> consumer, int maxBufferSize, WEvtApi wEvtApi, Kernel32 kernel32, ErrorLookup errorLookup) {
+        this.logger = logger;
+        this.consumer = consumer;
+        this.maxBufferSize = maxBufferSize;
+        this.wEvtApi = wEvtApi;
+        this.kernel32 = kernel32;
+        this.size = Math.min(maxBufferSize, INITIAL_BUFFER_SIZE);
+        this.errorLookup = errorLookup;
+        this.buffer = new Memory(size);
+        this.used = new Memory(4);
+        this.propertyCount = new Memory(4);
+    }
+
+    @Override
+    public synchronized int onEvent(int evtSubscribeNotifyAction, WinDef.PVOID userContext, WinNT.HANDLE eventHandle) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("onEvent(" + evtSubscribeNotifyAction + ", " + userContext + ", " + eventHandle);
+        }
+
+        if (evtSubscribeNotifyAction == WEvtApi.EvtSubscribeNotifyAction.ERROR) {
+            if (eventHandle.getPointer().getInt(0) == WEvtApi.EvtSubscribeErrors.ERROR_EVT_QUERY_RESULT_STALE) {
+                logger.error(MISSING_EVENT_MESSAGE);
+            } else {
+                logger.error(RECEIVED_THE_FOLLOWING_WIN32_ERROR + eventHandle.getPointer().getInt(0));
+            }
+        } else if (evtSubscribeNotifyAction == WEvtApi.EvtSubscribeNotifyAction.DELIVER) {
+            wEvtApi.EvtRender(null, eventHandle, WEvtApi.EvtRenderFlags.EVENT_XML, size, buffer, used, propertyCount);
+
+            // Not enough room in buffer, resize so it's big enough
+            if (kernel32.GetLastError() == W32Errors.ERROR_INSUFFICIENT_BUFFER) {
+                int newMaxSize = used.getInt(0);
+                // Check for overflow or too big
+                if (newMaxSize < size || newMaxSize > maxBufferSize) {
+                    logger.error("Dropping event " + eventHandle + " because it couldn't be rendered within " + maxBufferSize + " bytes.");
+                    // Ignored, see https://msdn.microsoft.com/en-us/library/windows/desktop/aa385577(v=vs.85).aspx
+                    return 0;
+                }
+                size = newMaxSize;
+                buffer = new Memory(size);
+                wEvtApi.EvtRender(null, eventHandle, WEvtApi.EvtRenderFlags.EVENT_XML, size, buffer, used, propertyCount);
+            }
+
+            int lastError = kernel32.GetLastError();
+            if (lastError == W32Errors.ERROR_SUCCESS) {
+                int usedBytes = used.getInt(0);
+                String string = Charsets.UTF_16LE.decode(buffer.getByteBuffer(0, usedBytes)).toString();
+                if (string.endsWith("\u0000")) {
+                    string = string.substring(0, string.length() - 1);
+                }
+                consumer.accept(string);
+            } else {
+                logger.error(EVT_RENDER_RETURNED_THE_FOLLOWING_ERROR_CODE + errorLookup.getLastError() + ".");
+            }
+        }
+        // Ignored, see https://msdn.microsoft.com/en-us/library/windows/desktop/aa385577(v=vs.85).aspx
+        return 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/65d89582/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/jna/WEvtApi.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/jna/WEvtApi.java b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/jna/WEvtApi.java
new file mode 100644
index 0000000..b0c310f
--- /dev/null
+++ b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/java/org/apache/nifi/processors/windows/event/log/jna/WEvtApi.java
@@ -0,0 +1,70 @@
+/*
+ * 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.windows.event.log.jna;
+
+import com.sun.jna.Native;
+import com.sun.jna.Pointer;
+import com.sun.jna.platform.win32.WinDef;
+import com.sun.jna.platform.win32.WinNT;
+import com.sun.jna.win32.StdCallLibrary;
+import com.sun.jna.win32.W32APIOptions;
+
+/**
+ * JNA will create the instance of this interface with Native.loadLibrary().
+ * Please see https://msdn.microsoft.com/en-us/library/windows/desktop/aa385772(v=vs.85).aspx for documentation on the methods and data structures.
+ */
+public interface WEvtApi extends StdCallLibrary {
+    WEvtApi INSTANCE = (WEvtApi) Native.loadLibrary("wevtapi", WEvtApi.class, W32APIOptions.DEFAULT_OPTIONS);
+
+    WinNT.HANDLE EvtSubscribe(WinNT.HANDLE session, WinNT.HANDLE signalEvent, String channelName, String xpathQuery,
+                              WinNT.HANDLE bookmark, WinDef.PVOID context, EVT_SUBSCRIBE_CALLBACK evtSubscribeCallback, int flags);
+
+    boolean EvtRender(WinNT.HANDLE context, WinNT.HANDLE fragment, int flags, int bufferSize, Pointer buffer, Pointer bufferUsed, Pointer propertyCount);
+
+    boolean EvtClose(WinNT.HANDLE subscriptionHandle);
+
+    interface EvtSubscribeNotifyAction {
+        int ERROR = 0;
+        int DELIVER = 1;
+    }
+
+    interface EvtSubscribeFlags {
+        int SUBSCRIBE_TO_FUTURE = 1;
+        int EVT_SUBSCRIBE_STRICT = 0x10000;
+    }
+
+    interface EvtSubscribeErrors{
+        int ERROR_EVT_QUERY_RESULT_STALE = 15011;
+    }
+
+    interface EvtRenderFlags {
+        int EVENT_XML = 1;
+    }
+
+    interface EVT_SUBSCRIBE_CALLBACK extends StdCallCallback {
+        /**
+         * Callback method that will be invoked when new events come in
+         *
+         * @param evtSubscribeNotifyAction the notify action
+         * @param userContext              the user context
+         * @param eventHandle              the event handle
+         * @return an int that will be ignored by the Windows Log API (https://msdn.microsoft.com/en-us/library/windows/desktop/aa385577(v=vs.85).aspx)
+         */
+        int onEvent(int evtSubscribeNotifyAction, WinDef.PVOID userContext, WinNT.HANDLE eventHandle);
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/65d89582/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor
new file mode 100644
index 0000000..0a7a470
--- /dev/null
+++ b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-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.windows.event.log.ConsumeWindowsEventLog
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/65d89582/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/resources/docs/org.apache.nifi.processors.windows.event.log.ConsumeWindowsEventLog/additionalDetails.html
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/resources/docs/org.apache.nifi.processors.windows.event.log.ConsumeWindowsEventLog/additionalDetails.html b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/resources/docs/org.apache.nifi.processors.windows.event.log.ConsumeWindowsEventLog/additionalDetails.html
new file mode 100644
index 0000000..a527164
--- /dev/null
+++ b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/main/resources/docs/org.apache.nifi.processors.windows.event.log.ConsumeWindowsEventLog/additionalDetails.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html lang="en">
+    <!--
+      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.
+    -->
+    <head>
+        <meta charset="utf-8" />
+        <title>ParseEvtx</title>
+
+        <link rel="stylesheet" href="../../css/component-usage.css" type="text/css" />
+    </head>
+
+    <body>
+        <!-- Processor Documentation ================================================== -->
+        <h2>Description:</h2>
+        <p>This processor is used listen to Windows Event Log events. It has a success output that will contain an XML representation of the event.
+         </p>
+         <h2>Output XML Example:</h2>
+         <p>
+             <pre>
+&lt;Event xmlns=&quot;http://schemas.microsoft.com/win/2004/08/events/event&quot;&gt;
+  &lt;System&gt;
+    &lt;Provider Name=&quot;Service Control Manager&quot; Guid=&quot;{555908d1-a6d7-4695-8e1e-26931d2012f4}&quot; EventSourceName=&quot;Service Control Manager&quot;/&gt;
+    &lt;EventID Qualifiers=&quot;16384&quot;&gt;7036&lt;/EventID&gt;
+    &lt;Version&gt;0&lt;/Version&gt;
+    &lt;Level&gt;4&lt;/Level&gt;
+    &lt;Task&gt;0&lt;/Task&gt;
+    &lt;Opcode&gt;0&lt;/Opcode&gt;
+    &lt;Keywords&gt;0x8080000000000000&lt;/Keywords&gt;
+    &lt;TimeCreated SystemTime=&quot;2016-06-10T22:28:53.905233700Z&quot;/&gt;
+    &lt;EventRecordID&gt;34153&lt;/EventRecordID&gt;
+    &lt;Correlation/&gt;
+    &lt;Execution ProcessID=&quot;684&quot; ThreadID=&quot;3504&quot;/&gt;
+    &lt;Channel&gt;System&lt;/Channel&gt;
+    &lt;Computer&gt;WIN-O05CNUCF16M.hdf.local&lt;/Computer&gt;
+    &lt;Security/&gt;
+  &lt;/System&gt;
+  &lt;EventData&gt;
+    &lt;Data Name=&quot;param1&quot;&gt;Smart Card Device Enumeration Service&lt;/Data&gt;
+    &lt;Data Name=&quot;param2&quot;&gt;running&lt;/Data&gt;
+    &lt;Binary&gt;5300630044006500760069006300650045006E0075006D002F0034000000&lt;/Binary&gt;
+  &lt;/EventData&gt;
+&lt;/Event&gt;
+             </pre>
+        </p>
+        <h2>Permissions:</h2>
+        <p>
+            Your Windows User must have permissions to read the given Event Log.  This can be achieved through the following steps (Windows 2008 and newer):
+            <ol>
+                <li>Open a command prompt as your user.  Enter the command: wmic useraccount get name,sid</li>
+                <li>Note the SID of the user or group you'd like to allow to read a given channel</li>
+                <li>Open a command prompt as Administrator.  enter the command: wevtutil gl CHANNEL_NAME</li>
+                <li>Take the channelAccess Attribute starting with O:BAG, copy it into a text editor, and add (A;;0x1;;;YOUR_SID_FROM_BEFORE) to the end</li>
+                <li>Take that text and run the following command in your admin prompt (see below for example): wevtutil sl CHANNEL_NAME /ca:TEXT_FROM_PREVIOUS_STEP</li>
+            </ol>
+
+            <p>The following command is the exact one I used to add read access to the Security log for my user. (You can see all the possible channels with: wevtutil el):</p>
+            <p>wevtutil sl Security /ca:O:BAG:SYD:(A;;0xf0005;;;SY)(A;;0x5;;;BA)(A;;0x1;;;S-1-5-32-573)(A;;0x1;;;S-1-5-21-3589080292-3448680409-2446571098-1001)</p>
+
+            <p>These steps were adapted from <a href="https://blogs.technet.microsoft.com/janelewis/2010/04/30/giving-non-administrators-permission-to-read-event-logs-windows-2003-and-windows-2008/">this guide.</a></p>
+        </p>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/nifi/blob/65d89582/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/ConsumeWindowsEventLogFailTest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/ConsumeWindowsEventLogFailTest.java b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/ConsumeWindowsEventLogFailTest.java
new file mode 100644
index 0000000..2a7b6b7
--- /dev/null
+++ b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/ConsumeWindowsEventLogFailTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.windows.event.log;
+
+import org.apache.nifi.util.TestRunner;
+import org.apache.nifi.util.TestRunners;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test scenario where we can't load the native libraries
+ */
+@RunWith(JNAFailJUnitRunner.class)
+public class ConsumeWindowsEventLogFailTest {
+
+    /**
+     * The processor should never be valid because we're using JNAFailJUnitRunner
+     */
+    @Test
+    public void testValidate() {
+        TestRunner testRunner = TestRunners.newTestRunner(ConsumeWindowsEventLog.class);
+        testRunner.assertNotValid();
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/65d89582/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/ConsumeWindowsEventLogTest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/ConsumeWindowsEventLogTest.java b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/ConsumeWindowsEventLogTest.java
new file mode 100644
index 0000000..4af4d9b
--- /dev/null
+++ b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/ConsumeWindowsEventLogTest.java
@@ -0,0 +1,268 @@
+/*
+ * 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.windows.event.log;
+
+import com.sun.jna.Pointer;
+import com.sun.jna.platform.win32.Kernel32;
+import com.sun.jna.platform.win32.W32Errors;
+import com.sun.jna.platform.win32.WinDef;
+import com.sun.jna.platform.win32.WinError;
+import com.sun.jna.platform.win32.WinNT;
+import org.apache.commons.io.Charsets;
+import org.apache.nifi.annotation.lifecycle.OnScheduled;
+import org.apache.nifi.annotation.lifecycle.OnStopped;
+import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.processors.windows.event.log.jna.EventSubscribeXmlRenderingCallback;
+import org.apache.nifi.processors.windows.event.log.jna.WEvtApi;
+import org.apache.nifi.util.MockFlowFile;
+import org.apache.nifi.util.MockProcessSession;
+import org.apache.nifi.util.MockSessionFactory;
+import org.apache.nifi.util.ReflectionUtils;
+import org.apache.nifi.util.TestRunner;
+import org.apache.nifi.util.TestRunners;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(JNAJUnitRunner.class)
+public class ConsumeWindowsEventLogTest {
+    @Mock
+    Kernel32 kernel32;
+
+    @Mock
+    WEvtApi wEvtApi;
+
+    @Mock
+    WinNT.HANDLE subscriptionHandle;
+
+    @Mock
+    Pointer subscriptionPointer;
+
+    private ConsumeWindowsEventLog evtSubscribe;
+    private TestRunner testRunner;
+
+    public static List<WinNT.HANDLE> mockEventHandles(WEvtApi wEvtApi, Kernel32 kernel32, List<String> eventXmls) {
+        List<WinNT.HANDLE> eventHandles = new ArrayList<>();
+        for (String eventXml : eventXmls) {
+            WinNT.HANDLE eventHandle = mock(WinNT.HANDLE.class);
+            when(wEvtApi.EvtRender(isNull(WinNT.HANDLE.class), eq(eventHandle), eq(WEvtApi.EvtRenderFlags.EVENT_XML),
+                    anyInt(), any(Pointer.class), any(Pointer.class), any(Pointer.class))).thenAnswer(invocation -> {
+                Object[] arguments = invocation.getArguments();
+                Pointer bufferUsed = (Pointer) arguments[5];
+                byte[] array = Charsets.UTF_16LE.encode(eventXml).array();
+                if (array.length > (int) arguments[3]) {
+                    when(kernel32.GetLastError()).thenReturn(W32Errors.ERROR_INSUFFICIENT_BUFFER).thenReturn(W32Errors.ERROR_SUCCESS);
+                } else {
+                    ((Pointer) arguments[4]).write(0, array, 0, array.length);
+                }
+                bufferUsed.setInt(0, array.length);
+                return false;
+            });
+            eventHandles.add(eventHandle);
+        }
+        return eventHandles;
+    }
+
+    @Before
+    public void setup() {
+        evtSubscribe = new ConsumeWindowsEventLog(wEvtApi, kernel32);
+
+
+        when(subscriptionHandle.getPointer()).thenReturn(subscriptionPointer);
+
+        when(wEvtApi.EvtSubscribe(isNull(WinNT.HANDLE.class), isNull(WinNT.HANDLE.class), eq(ConsumeWindowsEventLog.DEFAULT_CHANNEL), eq(ConsumeWindowsEventLog.DEFAULT_XPATH),
+                isNull(WinNT.HANDLE.class), isNull(WinDef.PVOID.class), isA(EventSubscribeXmlRenderingCallback.class),
+                eq(WEvtApi.EvtSubscribeFlags.SUBSCRIBE_TO_FUTURE | WEvtApi.EvtSubscribeFlags.EVT_SUBSCRIBE_STRICT)))
+                .thenReturn(subscriptionHandle);
+
+        testRunner = TestRunners.newTestRunner(evtSubscribe);
+    }
+
+    @Test(timeout = 10 * 1000)
+    public void testProcessesBlockedEvents() throws UnsupportedEncodingException {
+        testRunner.setProperty(ConsumeWindowsEventLog.MAX_EVENT_QUEUE_SIZE, "1");
+        testRunner.run(1, false, true);
+        EventSubscribeXmlRenderingCallback renderingCallback = getRenderingCallback();
+
+        List<String> eventXmls = Arrays.asList("one", "two", "three", "four", "five", "six");
+        List<WinNT.HANDLE> eventHandles = mockEventHandles(wEvtApi, kernel32, eventXmls);
+        AtomicBoolean done = new AtomicBoolean(false);
+        new Thread(() -> {
+            for (WinNT.HANDLE eventHandle : eventHandles) {
+                renderingCallback.onEvent(WEvtApi.EvtSubscribeNotifyAction.DELIVER, null, eventHandle);
+            }
+            done.set(true);
+        }).start();
+
+        // Wait until the thread has really started
+        while (testRunner.getFlowFilesForRelationship(ConsumeWindowsEventLog.REL_SUCCESS).size() == 0) {
+            testRunner.run(1, false, false);
+        }
+
+        // Process rest of events
+        while (!done.get()) {
+            testRunner.run(1, false, false);
+        }
+
+        testRunner.run(1, true, false);
+
+        List<MockFlowFile> flowFilesForRelationship = testRunner.getFlowFilesForRelationship(ConsumeWindowsEventLog.REL_SUCCESS);
+        assertEquals(eventXmls.size(), flowFilesForRelationship.size());
+        for (int i = 0; i < eventXmls.size(); i++) {
+            flowFilesForRelationship.get(i).assertContentEquals(eventXmls.get(i));
+        }
+    }
+
+    @Test
+    public void testStopProcessesQueue() throws InvocationTargetException, IllegalAccessException {
+        testRunner.run(1, false);
+
+        List<String> eventXmls = Arrays.asList("one", "two", "three");
+        for (WinNT.HANDLE eventHandle : mockEventHandles(wEvtApi, kernel32, eventXmls)) {
+            getRenderingCallback().onEvent(WEvtApi.EvtSubscribeNotifyAction.DELIVER, null, eventHandle);
+        }
+
+        ReflectionUtils.invokeMethodsWithAnnotation(OnStopped.class, evtSubscribe, testRunner.getProcessContext());
+
+        List<MockFlowFile> flowFilesForRelationship = testRunner.getFlowFilesForRelationship(ConsumeWindowsEventLog.REL_SUCCESS);
+        assertEquals(eventXmls.size(), flowFilesForRelationship.size());
+        for (int i = 0; i < eventXmls.size(); i++) {
+            flowFilesForRelationship.get(i).assertContentEquals(eventXmls.get(i));
+        }
+    }
+
+    @Test
+    public void testScheduleErrorThenTriggerSubscribe() throws InvocationTargetException, IllegalAccessException {
+        evtSubscribe = new ConsumeWindowsEventLog(wEvtApi, kernel32);
+
+
+        when(subscriptionHandle.getPointer()).thenReturn(subscriptionPointer);
+
+        when(wEvtApi.EvtSubscribe(isNull(WinNT.HANDLE.class), isNull(WinNT.HANDLE.class), eq(ConsumeWindowsEventLog.DEFAULT_CHANNEL), eq(ConsumeWindowsEventLog.DEFAULT_XPATH),
+                isNull(WinNT.HANDLE.class), isNull(WinDef.PVOID.class), isA(EventSubscribeXmlRenderingCallback.class),
+                eq(WEvtApi.EvtSubscribeFlags.SUBSCRIBE_TO_FUTURE | WEvtApi.EvtSubscribeFlags.EVT_SUBSCRIBE_STRICT)))
+                .thenReturn(null).thenReturn(subscriptionHandle);
+
+        testRunner = TestRunners.newTestRunner(evtSubscribe);
+
+
+        testRunner.run(1, false, true);
+
+        WinNT.HANDLE handle = mockEventHandles(wEvtApi, kernel32, Arrays.asList("test")).get(0);
+        List<EventSubscribeXmlRenderingCallback> renderingCallbacks = getRenderingCallbacks(2);
+        EventSubscribeXmlRenderingCallback subscribeRenderingCallback = renderingCallbacks.get(0);
+        EventSubscribeXmlRenderingCallback renderingCallback = renderingCallbacks.get(1);
+        renderingCallback.onEvent(WEvtApi.EvtSubscribeNotifyAction.DELIVER, null, handle);
+
+        testRunner.run(1, true, false);
+
+        assertNotEquals(subscribeRenderingCallback, renderingCallback);
+        verify(wEvtApi).EvtClose(subscriptionHandle);
+    }
+
+    @Test
+    public void testScheduleError() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
+        evtSubscribe = new ConsumeWindowsEventLog(wEvtApi, kernel32);
+
+        when(wEvtApi.EvtSubscribe(isNull(WinNT.HANDLE.class), isNull(WinNT.HANDLE.class), eq(ConsumeWindowsEventLog.DEFAULT_CHANNEL), eq(ConsumeWindowsEventLog.DEFAULT_XPATH),
+                isNull(WinNT.HANDLE.class), isNull(WinDef.PVOID.class), isA(EventSubscribeXmlRenderingCallback.class),
+                eq(WEvtApi.EvtSubscribeFlags.SUBSCRIBE_TO_FUTURE | WEvtApi.EvtSubscribeFlags.EVT_SUBSCRIBE_STRICT)))
+                .thenReturn(null);
+
+        when(kernel32.GetLastError()).thenReturn(WinError.ERROR_ACCESS_DENIED);
+
+        testRunner = TestRunners.newTestRunner(evtSubscribe);
+
+        testRunner.run(1);
+        assertEquals(0, getCreatedSessions(testRunner).size());
+        verify(wEvtApi, never()).EvtClose(any(WinNT.HANDLE.class));
+    }
+
+    @Test
+    public void testStopClosesHandle() {
+        testRunner.run(1);
+        verify(wEvtApi).EvtClose(subscriptionHandle);
+    }
+
+    @Test(expected = ProcessException.class)
+    public void testScheduleQueueStopThrowsException() throws Throwable {
+        ReflectionUtils.invokeMethodsWithAnnotation(OnScheduled.class, evtSubscribe, testRunner.getProcessContext());
+
+        WinNT.HANDLE handle = mockEventHandles(wEvtApi, kernel32, Arrays.asList("test")).get(0);
+        getRenderingCallback().onEvent(WEvtApi.EvtSubscribeNotifyAction.DELIVER, null, handle);
+
+        try {
+            ReflectionUtils.invokeMethodsWithAnnotation(OnStopped.class, evtSubscribe, testRunner.getProcessContext());
+        } catch (InvocationTargetException e) {
+            throw e.getCause();
+        }
+    }
+
+    public EventSubscribeXmlRenderingCallback getRenderingCallback() {
+        return getRenderingCallbacks(1).get(0);
+    }
+
+    public List<EventSubscribeXmlRenderingCallback> getRenderingCallbacks(int times) {
+        ArgumentCaptor<EventSubscribeXmlRenderingCallback> callbackArgumentCaptor = ArgumentCaptor.forClass(EventSubscribeXmlRenderingCallback.class);
+        verify(wEvtApi, times(times)).EvtSubscribe(isNull(WinNT.HANDLE.class), isNull(WinNT.HANDLE.class), eq(ConsumeWindowsEventLog.DEFAULT_CHANNEL), eq(ConsumeWindowsEventLog.DEFAULT_XPATH),
+                isNull(WinNT.HANDLE.class), isNull(WinDef.PVOID.class), callbackArgumentCaptor.capture(),
+                eq(WEvtApi.EvtSubscribeFlags.SUBSCRIBE_TO_FUTURE | WEvtApi.EvtSubscribeFlags.EVT_SUBSCRIBE_STRICT));
+        return callbackArgumentCaptor.getAllValues();
+    }
+
+    @Test
+    public void testGetSupportedPropertyDescriptors() {
+        assertEquals(ConsumeWindowsEventLog.PROPERTY_DESCRIPTORS, evtSubscribe.getSupportedPropertyDescriptors());
+    }
+
+    @Test
+    public void testGetRelationships() {
+        assertEquals(ConsumeWindowsEventLog.RELATIONSHIPS, evtSubscribe.getRelationships());
+    }
+
+    private static Set<MockProcessSession> getCreatedSessions(TestRunner testRunner) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+        MockSessionFactory processSessionFactory = (MockSessionFactory) testRunner.getProcessSessionFactory();
+        Method getCreatedSessions = processSessionFactory.getClass().getDeclaredMethod("getCreatedSessions");
+        getCreatedSessions.setAccessible(true);
+        return (Set<MockProcessSession>) getCreatedSessions.invoke(processSessionFactory);
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/65d89582/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/JNAFailJUnitRunner.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/JNAFailJUnitRunner.java b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/JNAFailJUnitRunner.java
new file mode 100644
index 0000000..675375d
--- /dev/null
+++ b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/JNAFailJUnitRunner.java
@@ -0,0 +1,42 @@
+/*
+ * 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.windows.event.log;
+
+import org.junit.runners.model.InitializationError;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Native load failure to simulate case on all OSes (even Windows)
+ */
+public class JNAFailJUnitRunner extends JNAOverridingJUnitRunner {
+
+    public JNAFailJUnitRunner(Class<?> klass) throws InitializationError {
+        super(klass);
+    }
+
+    @Override
+    protected Map<String, Map<String, String>> getClassOverrideMap() {
+        Map<String, Map<String, String>> classOverrideMap = new HashMap<>();
+        Map<String, String> nativeOverrideMap = new HashMap<>();
+        nativeOverrideMap.put(LOAD_LIBRARY, "throw new " + UnsatisfiedLinkError.class.getCanonicalName() + "(\"JNAFailJUnitRunner\");");
+        classOverrideMap.put(NATIVE_CANONICAL_NAME, nativeOverrideMap);
+        return classOverrideMap;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/65d89582/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/JNAJUnitRunner.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/JNAJUnitRunner.java b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/JNAJUnitRunner.java
new file mode 100644
index 0000000..b1608e3
--- /dev/null
+++ b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/JNAJUnitRunner.java
@@ -0,0 +1,51 @@
+/*
+ * 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.windows.event.log;
+
+import com.sun.jna.platform.win32.Kernel32Util;
+import org.junit.runners.model.InitializationError;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Can't even use the JNA interface classes if the native library won't load.  This is a workaround to allow mocking them for unit tests.
+ */
+public class JNAJUnitRunner extends JNAOverridingJUnitRunner {
+    public static final String TEST_COMPUTER_NAME = "testComputerName";
+    public static final String KERNEL_32_UTIL_CANONICAL_NAME = Kernel32Util.class.getCanonicalName();
+
+    public JNAJUnitRunner(Class<?> klass) throws InitializationError {
+        super(klass);
+    }
+
+    @Override
+    protected Map<String, Map<String, String>> getClassOverrideMap() {
+        Map<String, Map<String, String>> classOverrideMap = new HashMap<>();
+
+        Map<String, String> nativeOverrideMap = new HashMap<>();
+        nativeOverrideMap.put(LOAD_LIBRARY, "return null;");
+        classOverrideMap.put(NATIVE_CANONICAL_NAME, nativeOverrideMap);
+
+        Map<String, String> kernel32UtilMap = new HashMap<>();
+        kernel32UtilMap.put("getComputerName", "return \"" + TEST_COMPUTER_NAME + "\";");
+        classOverrideMap.put(KERNEL_32_UTIL_CANONICAL_NAME, kernel32UtilMap);
+
+        return classOverrideMap;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/65d89582/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/JNAOverridingJUnitRunner.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/JNAOverridingJUnitRunner.java b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/JNAOverridingJUnitRunner.java
new file mode 100644
index 0000000..6bfcaa0
--- /dev/null
+++ b/nifi-nar-bundles/nifi-windows-event-log-bundle/nifi-windows-event-log-processors/src/test/java/org/apache/nifi/processors/windows/event/log/JNAOverridingJUnitRunner.java
@@ -0,0 +1,99 @@
+/*
+ * 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.windows.event.log;
+
+import com.sun.jna.Native;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtMethod;
+import org.junit.runner.Description;
+import org.junit.runner.Runner;
+import org.junit.runner.notification.RunNotifier;
+import org.junit.runners.model.InitializationError;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import java.net.URLClassLoader;
+import java.util.Map;
+
+/**
+ * Can't even use the JNA interface classes if the native library won't load.  This is a workaround to allow mocking them for unit tests.
+ */
+public abstract class JNAOverridingJUnitRunner extends Runner {
+    public static final String NATIVE_CANONICAL_NAME = Native.class.getCanonicalName();
+    public static final String LOAD_LIBRARY = "loadLibrary";
+    private final Runner delegate;
+
+    public JNAOverridingJUnitRunner(Class<?> klass) throws InitializationError {
+        Map<String, Map<String, String>> classOverrideMap = getClassOverrideMap();
+        ClassLoader jnaMockClassloader = new URLClassLoader(((URLClassLoader) JNAOverridingJUnitRunner.class.getClassLoader()).getURLs(), null) {
+            @Override
+            protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+                Map<String, String> classOverrides = classOverrideMap.get(name);
+                if (classOverrides != null) {
+                    ClassPool classPool = ClassPool.getDefault();
+                    try {
+                        CtClass ctClass = classPool.get(name);
+                        try {
+                            for (Map.Entry<String, String> methodAndBody : classOverrides.entrySet()) {
+                                for (CtMethod loadLibrary : ctClass.getDeclaredMethods(methodAndBody.getKey())) {
+                                    loadLibrary.setBody(methodAndBody.getValue());
+                                }
+                            }
+
+                            byte[] bytes = ctClass.toBytecode();
+                            Class<?> definedClass = defineClass(name, bytes, 0, bytes.length);
+                            if (resolve) {
+                                resolveClass(definedClass);
+                            }
+                            return definedClass;
+                        } finally {
+                            ctClass.detach();
+                        }
+                    } catch (Exception e) {
+                        throw new ClassNotFoundException(name, e);
+                    }
+                } else if (name.startsWith("org.junit.")) {
+                    Class<?> result = JNAOverridingJUnitRunner.class.getClassLoader().loadClass(name);
+                    if (resolve) {
+                        resolveClass(result);
+                    }
+                    return result;
+                }
+                return super.loadClass(name, resolve);
+            }
+        };
+        try {
+            delegate = (Runner) jnaMockClassloader.loadClass(MockitoJUnitRunner.class.getCanonicalName()).getConstructor(Class.class)
+                    .newInstance(jnaMockClassloader.loadClass(klass.getCanonicalName()));
+        } catch (Exception e) {
+            throw new InitializationError(e);
+        }
+    }
+
+    protected abstract Map<String, Map<String, String>> getClassOverrideMap();
+
+    @Override
+    public Description getDescription() {
+        return delegate.getDescription();
+    }
+
+    @Override
+    public void run(RunNotifier notifier) {
+        delegate.run(notifier);
+    }
+}


Mime
View raw message