* Marker annotation a {@link org.apache.nifi.processor.Processor Processor},
* {@link org.apache.nifi.controller.ControllerService ControllerService}, or
* {@link org.apache.nifi.reporting.ReportingTask ReportingTask}
* implementation can use to indicate a method
* should be called whenever the component is added to the flow. This method
* will be called once for the entire life of a component instance.
- *
+ *
+ *
+ *
+ * Methods with this annotation are called without any arguments, as all settings
+ * and properties can be assumed to be the defaults.
+ *
+ *
+ *
* If any method annotated with this annotation throws a Throwable, the component
* will not be added to the flow.
- *
+ *
+ *
* @author none
*/
@Documented
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/annotation/lifecycle/OnDisabled.java b/nifi/nifi-api/src/main/java/org/apache/nifi/annotation/lifecycle/OnDisabled.java
index 0f78010026..b227968931 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/annotation/lifecycle/OnDisabled.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/annotation/lifecycle/OnDisabled.java
@@ -23,19 +23,32 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import org.apache.nifi.controller.ConfigurationContext;
+
/**
- * Marker annotation a {@link org.apache.nifi.processor.Processor Processor},
- * {@link org.apache.nifi.controller.ControllerService ControllerService} or
- * {@link org.apache.nifi.reporting.ReportingTask ReportingTask}
- * can use to indicate a method should be called whenever the component is disabled.
+ *
+ * Marker annotation a {@link org.apache.nifi.controller.ControllerService ControllerService}
+ * can use to indicate a method should be called whenever the service is disabled.
+ *
*
*
- * Methods using this annotation must take no arguments. If a method with this annotation
- * throws a Throwable, a log message and bulletin will be issued for the component, but
- * the component will still be disabled.
+ * Methods using this annotation are permitted to take zero arguments or to take a single
+ * argument of type {@link ConfigurationContext}. If a method with this annotation
+ * throws a Throwable, a log message and bulletin will be issued for the service, and the
+ * service will remain in a 'DISABLING' state. When this occurs, the method with this annotation
+ * will be called again after some period of time. This will continue until the method returns
+ * without throwing any Throwable. Until that time, the service will remain in a 'DISABLING' state
+ * and cannot be enabled again.
+ *
+ *
+ *
+ * Note that this annotation will be ignored if applied to a ReportingTask or Processor. For a Controller
+ * Service, enabling and disabling are considered lifecycle events, as the action makes them usable or
+ * unusable by other components. However, for a Processor and a Reporting
+ * Task, these are not lifecycle events but rather a mechanism to allow a component to be excluded when
+ * starting or stopping a group of components.
*
- * Marker annotation a {@link org.apache.nifi.processor.Processor Processor},
- * {@link org.apache.nifi.controller.ControllerService ControllerService} or
- * {@link org.apache.nifi.reporting.ReportingTask ReportingTask}
- * can use to indicate a method should be called whenever the component is enabled.
- * Any method that has this annotation will be called every time a user enables the component.
+ * Marker annotation a {@link org.apache.nifi.controller.ControllerService ControllerService}
+ * can use to indicate a method should be called whenever the service is enabled.
+ * Any method that has this annotation will be called every time a user enables the service.
* Additionally, each time that NiFi is restarted, if NiFi is configured to "auto-resume state"
- * and the component is enabled (whether stopped or running), the method will be invoked.
+ * and the service is enabled, the method will be invoked.
*
*
*
- * Methods using this annotation must take either 0 arguments or a single argument.
- *
- *
- *
- * If using 1 argument and the component using the annotation is a Processor, that argument must
- * be of type {@link org.apache.nifi.processor.ProcessContext ProcessContext}.
- *
- *
- *
- * If using 1 argument and the component using the annotation is a Reporting Task or Controller Service,
- * that argument must be of type {@link org.apache.nifi.controller.ConfigurationContext ConfigurationContext}.
+ * Methods using this annotation must take either 0 arguments or a single argument of type
+ * {@link org.apache.nifi.controller.ConfigurationContext ConfigurationContext}.
*
*
*
* If a method with this annotation throws a Throwable, a log message and bulletin will be issued
- * for the component, but the component will still be enabled.
+ * for the component. In this event, the service will remain in an 'ENABLING' state and will not be
+ * usable. All methods with this annotation will then be called again after a delay. The service will
+ * not be made available for use until all methods with this annotation have returned without throwing
+ * anything.
+ *
+ *
+ *
+ * Note that this annotation will be ignored if applied to a ReportingTask or Processor. For a Controller
+ * Service, enabling and disabling are considered lifecycle events, as the action makes them usable or
+ * unusable by other components. However, for a Processor and a Reporting
+ * Task, these are not lifecycle events but rather a mechanism to allow a component to be excluded when
+ * starting or stopping a group of components.
*
* Marker annotation a {@link org.apache.nifi.processor.Processor Processor},
* {@link org.apache.nifi.controller.ControllerService ControllerService}, or
* {@link org.apache.nifi.reporting.ReportingTask ReportingTask} implementation
@@ -32,7 +36,15 @@ import java.lang.annotation.Target;
* component instance. If the method throw any Throwable, that Throwable will be
* caught and logged but will not prevent subsequent methods with this annotation
* or removal of the component from the flow.
- *
+ *
+ *
+ *
+ * Methods with this annotation are permitted to take no arguments or to take a single
+ * argument. If using a single argument, that argument must be of type {@link ConfigurationContext}
+ * if the component is a ReportingTask or a ControllerService. If the component is a Processor,
+ * then the argument must be of type {@link ProcessContext}.
+ *
* Marker annotation a {@link org.apache.nifi.processor.Processor Processor},
* {@link org.apache.nifi.controller.ControllerService ControllerService}, or
* {@link org.apache.nifi.reporting.ReportingTask ReportingTask} implementation
@@ -31,7 +35,14 @@ import java.lang.annotation.Target;
* This will be called at most once for each component in a JVM lifetime.
* It is not, however, guaranteed that this method will be called on shutdown, as
* the service may be killed suddenly.
- *
+ *
+ *
+ *
+ * Methods with this annotation are permitted to take either 0 or 1 argument. If an argument
+ * is used, it must be of type {@link ConfigurationContext} if the component is a ReportingTask
+ * or Controller Service, or of type {@link ProcessContext} if the component is a Processor.
+ *
* Marker annotation a {@link org.apache.nifi.processor.Processor Processor} or
@@ -47,6 +50,12 @@ import java.lang.annotation.Target;
* longer scheduled to run (as opposed to after all threads have returned from the
* onTrigger method), see the {@link OnUnscheduled} annotation.
*
+ *
+ *
+ * Methods with this annotation are permitted to take either 0 or 1 argument. If an argument
+ * is used, it must be of type {@link ConfigurationContext} if the component is a ReportingTask
+ * or of type {@link ProcessContext} if the component is a Processor.
+ *
*
* @author none
*/
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/annotation/lifecycle/OnUnscheduled.java b/nifi/nifi-api/src/main/java/org/apache/nifi/annotation/lifecycle/OnUnscheduled.java
index b1dbde1bf2..5c7e13dc2c 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/annotation/lifecycle/OnUnscheduled.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/annotation/lifecycle/OnUnscheduled.java
@@ -47,8 +47,6 @@ import java.lang.annotation.Target;
* If using 1 argument and the component using the annotation is a Reporting Task, that argument must
* be of type {@link org.apache.nifi.controller.ConfigurationContext ConfigurationContext}.
*
- *
- * @author none
*/
@Documented
@Target({ElementType.METHOD})
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/components/PropertyDescriptor.java b/nifi/nifi-api/src/main/java/org/apache/nifi/components/PropertyDescriptor.java
index 82372af540..e62ff7962c 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/components/PropertyDescriptor.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/components/PropertyDescriptor.java
@@ -142,9 +142,19 @@ public final class PropertyDescriptor implements Comparable
final Set validIdentifiers = context.getControllerServiceLookup().getControllerServiceIdentifiers(controllerServiceDefinition);
if (validIdentifiers != null && validIdentifiers.contains(input)) {
final ControllerService controllerService = context.getControllerServiceLookup().getControllerService(input);
- if (!context.getControllerServiceLookup().isControllerServiceEnabled(controllerService)) {
+ if ( !context.isValidationRequired(controllerService) ) {
return new ValidationResult.Builder()
- .input(input)
+ .input(input)
+ .subject(getName())
+ .valid(true)
+ .build();
+ }
+
+ final String serviceId = controllerService.getIdentifier();
+ if (!context.getControllerServiceLookup().isControllerServiceEnabled(serviceId) &&
+ !context.getControllerServiceLookup().isControllerServiceEnabling(serviceId)) {
+ return new ValidationResult.Builder()
+ .input(context.getControllerServiceLookup().getControllerServiceName(serviceId))
.subject(getName())
.valid(false)
.explanation("Controller Service " + controllerService + " is disabled")
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/components/ValidationContext.java b/nifi/nifi-api/src/main/java/org/apache/nifi/components/ValidationContext.java
index b7b72c5141..61b68a249c 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/components/ValidationContext.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/components/ValidationContext.java
@@ -80,6 +80,15 @@ public interface ValidationContext {
*/
String getAnnotationData();
+ /**
+ * There are times when the framework needs to consider a component valid, even if it
+ * references an invalid ControllerService. This method will return false
+ * if the component is to be considered valid even if the given Controller Service is referenced
+ * and is invalid.
+ * @param service
+ */
+ boolean isValidationRequired(ControllerService service);
+
/**
* Returns true if the given value contains a NiFi Expression Language expression,
* false if it does not
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/controller/AbstractControllerService.java b/nifi/nifi-api/src/main/java/org/apache/nifi/controller/AbstractControllerService.java
index c12f2f8d1f..71cdd231ea 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/controller/AbstractControllerService.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/controller/AbstractControllerService.java
@@ -22,6 +22,7 @@ import org.apache.nifi.components.AbstractConfigurableComponent;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.components.PropertyValue;
import org.apache.nifi.controller.annotation.OnConfigured;
+import org.apache.nifi.logging.ComponentLog;
import org.apache.nifi.processor.ProcessorInitializationContext;
import org.apache.nifi.reporting.InitializationException;
@@ -30,11 +31,13 @@ public abstract class AbstractControllerService extends AbstractConfigurableComp
private String identifier;
private ControllerServiceLookup serviceLookup;
private volatile ConfigurationContext configContext;
-
+ private ComponentLog logger;
+
@Override
public final void initialize(final ControllerServiceInitializationContext context) throws InitializationException {
this.identifier = context.getIdentifier();
serviceLookup = context.getControllerServiceLookup();
+ logger = context.getLogger();
init(context);
}
@@ -88,4 +91,12 @@ public abstract class AbstractControllerService extends AbstractConfigurableComp
*/
protected void init(final ControllerServiceInitializationContext config) throws InitializationException {
}
+
+ /**
+ * Returns the logger that has been provided to the component by the framework in its initialize method.
+ * @return
+ */
+ protected ComponentLog getLogger() {
+ return logger;
+ }
}
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/controller/ControllerServiceInitializationContext.java b/nifi/nifi-api/src/main/java/org/apache/nifi/controller/ControllerServiceInitializationContext.java
index b5b0412cb3..d34c6354ad 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/controller/ControllerServiceInitializationContext.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/controller/ControllerServiceInitializationContext.java
@@ -16,6 +16,8 @@
*/
package org.apache.nifi.controller;
+import org.apache.nifi.logging.ComponentLog;
+
public interface ControllerServiceInitializationContext {
/**
@@ -33,4 +35,12 @@ public interface ControllerServiceInitializationContext {
* @return
*/
ControllerServiceLookup getControllerServiceLookup();
+
+ /**
+ * Returns a logger that can be used to log important events in a standard way and generate
+ * bulletins when appropriate
+ *
+ * @return
+ */
+ ComponentLog getLogger();
}
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/controller/ControllerServiceLookup.java b/nifi/nifi-api/src/main/java/org/apache/nifi/controller/ControllerServiceLookup.java
index 77b8e6296d..4b96f626a6 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/controller/ControllerServiceLookup.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/controller/ControllerServiceLookup.java
@@ -41,6 +41,18 @@ public interface ControllerServiceLookup {
*/
boolean isControllerServiceEnabled(String serviceIdentifier);
+ /**
+ * Returns true if the Controller Service with the given
+ * identifier has been enabled but is still in the transitioning state,
+ * otherwise returns false.
+ * If the given identifier is not known by this ControllerServiceLookup,
+ * returns false.
+ *
+ * @param serviceIdentifier
+ * @return
+ */
+ boolean isControllerServiceEnabling(String serviceIdentifier);
+
/**
* Returns true if the given Controller Service is enabled,
* false otherwise. If the given Controller Service is not
@@ -63,4 +75,11 @@ public interface ControllerServiceLookup {
*/
Set getControllerServiceIdentifiers(Class extends ControllerService> serviceType) throws IllegalArgumentException;
+ /**
+ * Returns the name of the Controller service with the given identifier. If no service can be
+ * found with this identifier, returns {@code null}.
+ * @param serviceIdentifier
+ * @return
+ */
+ String getControllerServiceName(String serviceIdentifier);
}
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/logging/ComponentLog.java b/nifi/nifi-api/src/main/java/org/apache/nifi/logging/ComponentLog.java
new file mode 100644
index 0000000000..c070e23698
--- /dev/null
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/logging/ComponentLog.java
@@ -0,0 +1,100 @@
+/*
+ * 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.logging;
+
+
+/**
+ *
+ * The ComponentLog provides a mechanism to ensure that all NiFi components are logging and reporting
+ * information in a consistent way. When messages are logged to the ComponentLog, each message has the
+ * following characteristics:
+ *
+ *
+ *
+ *
+ * The toString() of the component is automatically prepended to the message so that it is clear
+ * which component is providing the information. This is important, since a single component may have many
+ * different instances within the same NiFi instance.
+ *
+ *
+ * If the last value in an Object[] argument that is passed to the logger is a Throwable, then the logged message
+ * will include a toString() of the Throwable; in addition, if the component's logger is set to
+ * DEBUG level via the logback configuration, the Stacktrace will also be logged. This provides a mechanism to easily
+ * enable stacktraces in the logs when they are desired without filling the logs with unneeded stack traces for messages
+ * that end up occurring often.
+ *
+ *
+ * Any message that is logged with a Severity level that meets or exceeds the configured Bulletin Level for that component
+ * will also cause a Bulletin to be generated, so that the message is visible in the UI, allowing Dataflow Managers
+ * to understand that a problem exists and what the issue is.
+ *
+ *
+ *
+ */
+public interface ComponentLog {
+ void warn(String msg, Throwable t);
+
+ void warn(String msg, Object[] os);
+
+ void warn(String msg, Object[] os, Throwable t);
+
+ void warn(String msg);
+
+ void trace(String msg, Throwable t);
+
+ void trace(String msg, Object[] os);
+
+ void trace(String msg);
+
+ void trace(String msg, Object[] os, Throwable t);
+
+ boolean isWarnEnabled();
+
+ boolean isTraceEnabled();
+
+ boolean isInfoEnabled();
+
+ boolean isErrorEnabled();
+
+ boolean isDebugEnabled();
+
+ void info(String msg, Throwable t);
+
+ void info(String msg, Object[] os);
+
+ void info(String msg);
+
+ void info(String msg, Object[] os, Throwable t);
+
+ String getName();
+
+ void error(String msg, Throwable t);
+
+ void error(String msg, Object[] os);
+
+ void error(String msg);
+
+ void error(String msg, Object[] os, Throwable t);
+
+ void debug(String msg, Throwable t);
+
+ void debug(String msg, Object[] os);
+
+ void debug(String msg, Object[] os, Throwable t);
+
+ void debug(String msg);
+}
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/logging/ProcessorLog.java b/nifi/nifi-api/src/main/java/org/apache/nifi/logging/ProcessorLog.java
index c5fa7b15ca..0d66d8553b 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/logging/ProcessorLog.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/logging/ProcessorLog.java
@@ -16,58 +16,15 @@
*/
package org.apache.nifi.logging;
-public interface ProcessorLog {
- void warn(String msg, Throwable t);
-
- void warn(String msg, Object[] os);
-
- void warn(String msg, Object[] os, Throwable t);
-
- void warn(String msg);
-
- void trace(String msg, Throwable t);
-
- void trace(String msg, Object[] os);
-
- void trace(String msg);
-
- void trace(String msg, Object[] os, Throwable t);
-
- boolean isWarnEnabled();
-
- boolean isTraceEnabled();
-
- boolean isInfoEnabled();
-
- boolean isErrorEnabled();
-
- boolean isDebugEnabled();
-
- void info(String msg, Throwable t);
-
- void info(String msg, Object[] os);
-
- void info(String msg);
-
- void info(String msg, Object[] os, Throwable t);
-
- String getName();
-
- void error(String msg, Throwable t);
-
- void error(String msg, Object[] os);
-
- void error(String msg);
-
- void error(String msg, Object[] os, Throwable t);
-
- void debug(String msg, Throwable t);
-
- void debug(String msg, Object[] os);
-
- void debug(String msg, Object[] os, Throwable t);
-
- void debug(String msg);
+/**
+ * The ProcessorLog is an extension of ComponentLog but provides no additional functionality.
+ * It exists because ProcessorLog was created first,
+ * but when Controller Services and Reporting Tasks began to be used more heavily loggers
+ * were needed for them as well. We did not want to return a ProcessorLog to a ControllerService
+ * or a ReportingTask, so all of the methods were moved to a higher interface named ComponentLog.
+ * However, we kept the ProcessorLog interface around in order to maintain backward compatibility.
+ */
+public interface ProcessorLog extends ComponentLog {
}
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/reporting/AbstractReportingTask.java b/nifi/nifi-api/src/main/java/org/apache/nifi/reporting/AbstractReportingTask.java
index 5ed8f24ac4..efcf2a3637 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/reporting/AbstractReportingTask.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/reporting/AbstractReportingTask.java
@@ -20,6 +20,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.nifi.components.AbstractConfigurableComponent;
import org.apache.nifi.controller.ControllerServiceLookup;
+import org.apache.nifi.logging.ComponentLog;
import org.apache.nifi.processor.ProcessorInitializationContext;
public abstract class AbstractReportingTask extends AbstractConfigurableComponent implements ReportingTask {
@@ -28,10 +29,12 @@ public abstract class AbstractReportingTask extends AbstractConfigurableComponen
private String name;
private long schedulingNanos;
private ControllerServiceLookup serviceLookup;
+ private ComponentLog logger;
@Override
public final void initialize(final ReportingInitializationContext config) throws InitializationException {
identifier = config.getIdentifier();
+ logger = config.getLogger();
name = config.getName();
schedulingNanos = config.getSchedulingPeriod(TimeUnit.NANOSECONDS);
serviceLookup = config.getControllerServiceLookup();
@@ -91,4 +94,11 @@ public abstract class AbstractReportingTask extends AbstractConfigurableComponen
protected void init(final ReportingInitializationContext config) throws InitializationException {
}
+ /**
+ * Returns the logger that has been provided to the component by the framework in its initialize method.
+ * @return
+ */
+ protected ComponentLog getLogger() {
+ return logger;
+ }
}
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/reporting/ReportingInitializationContext.java b/nifi/nifi-api/src/main/java/org/apache/nifi/reporting/ReportingInitializationContext.java
index a0ae88ea31..6b84589d75 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/reporting/ReportingInitializationContext.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/reporting/ReportingInitializationContext.java
@@ -19,6 +19,7 @@ package org.apache.nifi.reporting;
import java.util.concurrent.TimeUnit;
import org.apache.nifi.controller.ControllerServiceLookup;
+import org.apache.nifi.logging.ComponentLog;
import org.apache.nifi.scheduling.SchedulingStrategy;
/**
@@ -77,4 +78,13 @@ public interface ReportingInitializationContext {
* @return
*/
SchedulingStrategy getSchedulingStrategy();
+
+
+ /**
+ * Returns a logger that can be used to log important events in a standard way and generate
+ * bulletins when appropriate
+ *
+ * @return
+ */
+ ComponentLog getLogger();
}
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/web/ClusterRequestException.java b/nifi/nifi-api/src/main/java/org/apache/nifi/web/ClusterRequestException.java
index 0ecea3b56b..ee5f417d1f 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/web/ClusterRequestException.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/web/ClusterRequestException.java
@@ -17,6 +17,7 @@
package org.apache.nifi.web;
/**
+ * An general error occurred when attempting to communicate with the cluster.
*/
public class ClusterRequestException extends RuntimeException {
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/web/ComponentDetails.java b/nifi/nifi-api/src/main/java/org/apache/nifi/web/ComponentDetails.java
new file mode 100644
index 0000000000..0b68ed95ac
--- /dev/null
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/web/ComponentDetails.java
@@ -0,0 +1,157 @@
+/*
+ * 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.web;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * Details about a given component. Contains configuration and current validation errors.
+ */
+public class ComponentDetails {
+
+ private final String id;
+ private final String name;
+ private final String type;
+ private final String state;
+ private final String annotationData;
+ private final Map properties;
+ private final Collection validationErrors;
+
+ private ComponentDetails(final Builder builder) {
+ this.id = builder.id;
+ this.name = builder.name;
+ this.type = builder.type;
+ this.state = builder.state;
+ this.annotationData = builder.annotationData;
+ this.properties = builder.properties;
+ this.validationErrors = builder.validationErrors;
+ }
+
+ /**
+ * The component id.
+ *
+ * @return
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * The component name.
+ *
+ * @return
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * The component type.
+ *
+ * @return
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * The component state.
+ *
+ * @return
+ */
+ public String getState() {
+ return state;
+ }
+
+ /**
+ * The component's annotation data.
+ *
+ * @return
+ */
+ public String getAnnotationData() {
+ return annotationData;
+ }
+
+ /**
+ * Mapping of component properties.
+ *
+ * @return
+ */
+ public Map getProperties() {
+ return properties;
+ }
+
+ /**
+ * Current validation errors for the component.
+ *
+ * @return
+ */
+ public Collection getValidationErrors() {
+ return validationErrors;
+ }
+
+ public static final class Builder {
+
+ private String id;
+ private String name;
+ private String type;
+ private String state;
+ private String annotationData;
+ private Map properties;
+ private Collection validationErrors;
+
+ public Builder id(final String id) {
+ this.id = id;
+ return this;
+ }
+
+ public Builder name(final String name) {
+ this.name = name;
+ return this;
+ }
+
+ public Builder type(final String type) {
+ this.type = type;
+ return this;
+ }
+
+ public Builder state(final String state) {
+ this.state = state;
+ return this;
+ }
+
+ public Builder annotationData(final String annotationData) {
+ this.annotationData = annotationData;
+ return this;
+ }
+
+ public Builder properties(final Map properties) {
+ this.properties = properties;
+ return this;
+ }
+
+ public Builder validateErrors(final Collection validationErrors) {
+ this.validationErrors = validationErrors;
+ return this;
+ }
+
+ public ComponentDetails build() {
+ return new ComponentDetails(this);
+ }
+ }
+}
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/web/ConfigurationAction.java b/nifi/nifi-api/src/main/java/org/apache/nifi/web/ConfigurationAction.java
new file mode 100644
index 0000000000..066e77254c
--- /dev/null
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/web/ConfigurationAction.java
@@ -0,0 +1,137 @@
+/*
+ * 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.web;
+
+/**
+ * An action that represents the configuration of a component.
+ */
+public class ConfigurationAction {
+
+ private final String id;
+ private final String name;
+ private final String type;
+ private final String field;
+ private final String previousValue;
+ private final String value;
+
+ private ConfigurationAction(final Builder builder) {
+ this.id = builder.id;
+ this.name = builder.name;
+ this.type = builder.type;
+ this.field = builder.field;
+ this.previousValue = builder.previousValue;
+ this.value = builder.value;
+ }
+
+ /**
+ * The id of the component being modified.
+ *
+ * @return
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * The name of the component being modified.
+ *
+ * @return
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * The type of the component being modified.
+ *
+ * @return
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Gets the name of the field, property, etc that has been modified.
+ *
+ * @return
+ */
+ public String getField() {
+ return field;
+ }
+
+ /**
+ * Gets the previous value.
+ *
+ * @return
+ */
+ public String getPreviousValue() {
+ return previousValue;
+ }
+
+ /**
+ * Gets the new value.
+ *
+ * @return
+ */
+ public String getValue() {
+ return value;
+ }
+
+ public static class Builder {
+
+ private String id;
+ private String name;
+ private String type;
+ private String field;
+ private String previousValue;
+ private String value;
+
+ public Builder id(final String id) {
+ this.id = id;
+ return this;
+ }
+
+ public Builder name(final String name) {
+ this.name = name;
+ return this;
+ }
+
+ public Builder type(final String type) {
+ this.type = type;
+ return this;
+ }
+
+ public Builder field(final String field) {
+ this.field = field;
+ return this;
+ }
+
+ public Builder previousValue(final String previousValue) {
+ this.previousValue = previousValue;
+ return this;
+ }
+
+ public Builder value(final String value) {
+ this.value = value;
+ return this;
+ }
+
+ public ConfigurationAction build() {
+ return new ConfigurationAction(this);
+ }
+ }
+}
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebConfigurationContext.java b/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebConfigurationContext.java
new file mode 100644
index 0000000000..50f0ca30f3
--- /dev/null
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebConfigurationContext.java
@@ -0,0 +1,102 @@
+/*
+ * 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.web;
+
+import java.util.Collection;
+
+import org.apache.nifi.controller.ControllerService;
+
+/**
+ * NiFi web context providing limited access to dataflow configuration for
+ * component custom UIs.
+ */
+public interface NiFiWebConfigurationContext {
+
+ /**
+ * Gets the ControllerService for the specified identifier. If a
+ * corresponding service cannot be found, null is returned. If this NiFi is
+ * clustered, the only services available will be those those
+ * availability is NCM only.
+ *
+ * @param serviceIdentifier
+ * @return
+ */
+ ControllerService getControllerService(String serviceIdentifier);
+
+ /**
+ * Provides a mechanism for custom UIs to save actions to appear in NiFi
+ * configuration history. Note all fields within each Action must be
+ * populated. Null values will result in a failure to insert the audit
+ * record. Since the saving to these actions is separate from the actual
+ * configuration change, a failure to insert here will just generate a
+ * warning log message. The recording of these actions typically happens
+ * after a configuration change is applied. Since those changes have already
+ * been applied to the flow, we cannot revert them because of a failure to
+ * insert an audit record.
+ *
+ * @param requestContext
+ * @param actions
+ * @throws IllegalArgumentException When the requestContext isn't fully populated or
+ * isn't appropriate for the given request
+ */
+ void saveActions(NiFiWebRequestContext requestContext, Collection actions);
+
+ /**
+ * Gets the current user dn. Returns null if no user is found.
+ *
+ * @return
+ */
+ String getCurrentUserDn();
+
+ /**
+ * Gets the current user name. Returns null if no user is found.
+ *
+ * @return
+ */
+ String getCurrentUserName();
+
+ /**
+ * Sets the annotation data for the underlying component.
+ *
+ * @param configurationContext
+ * @param annotationData
+ * @return the configuration for the underlying component
+ * @throws ResourceNotFoundException if the underlying component does not exit
+ * @throws InvalidRevisionException if a revision other than the current
+ * revision is given
+ * @throws ClusterRequestException if the annotation data was unable to be
+ * set for the underlying component. This exception will only be thrown when operating
+ * in a cluster.
+ * @throws IllegalArgumentException When the requestContext isn't fully populated or
+ * isn't appropriate for the given request
+ */
+ ComponentDetails setAnnotationData(NiFiWebConfigurationRequestContext configurationContext, String annotationData) throws ResourceNotFoundException, InvalidRevisionException, ClusterRequestException;
+
+ /**
+ * Gets the details for the underlying component (including configuration, validation errors, and annotation data).
+ *
+ * @param requestContext
+ * @return the configuration for the underlying component
+ * @throws ResourceNotFoundException if the underlying component does not exit
+ * @throws ClusterRequestException if the underlying component was unable to be
+ * retrieved from the cluster. This exception will only be thrown when
+ * operating in a cluster.
+ * @throws IllegalArgumentException When the requestContext isn't fully populated or
+ * isn't appropriate for the given request
+ */
+ ComponentDetails getComponentDetails(NiFiWebRequestContext requestContext) throws ResourceNotFoundException, ClusterRequestException;
+}
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebConfigurationRequestContext.java b/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebConfigurationRequestContext.java
new file mode 100644
index 0000000000..791224122a
--- /dev/null
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebConfigurationRequestContext.java
@@ -0,0 +1,31 @@
+/*
+ * 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.web;
+
+/**
+ * Contextual details required to make a configuration request from a UI extension.
+ */
+public interface NiFiWebConfigurationRequestContext extends NiFiWebRequestContext {
+
+ /**
+ * The revision to include in the request.
+ *
+ * @return the revision
+ */
+ Revision getRevision();
+
+}
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContext.java b/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContext.java
index 4c4f25d38f..01702addf8 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContext.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContext.java
@@ -24,6 +24,7 @@ import org.apache.nifi.controller.ControllerService;
* NiFi web context providing limited access to dataflow configuration for
* processor custom UIs.
*/
+@Deprecated
public interface NiFiWebContext {
/**
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContextConfig.java b/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContextConfig.java
index 808b9d66a9..2df94e4aa4 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContextConfig.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebContextConfig.java
@@ -19,6 +19,7 @@ package org.apache.nifi.web;
/**
* Context configuration for methods invoked from the NiFiWebContext.
*/
+@Deprecated
public interface NiFiWebContextConfig {
/**
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebRequestContext.java b/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebRequestContext.java
new file mode 100644
index 0000000000..ac38221ae1
--- /dev/null
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/web/NiFiWebRequestContext.java
@@ -0,0 +1,58 @@
+/*
+ * 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.web;
+
+/**
+ * Contextual details required to make a request from a UI extension.
+ */
+public interface NiFiWebRequestContext {
+
+ /**
+ * Returns the type of UI extension is making the request.
+ *
+ * @return
+ */
+ UiExtensionType getExtensionType();
+
+ /**
+ * The request protocol scheme (http or https). When scheme is https, the
+ * X509Certificate can be used for subsequent remote requests.
+ *
+ * @return the protocol scheme
+ */
+ String getScheme();
+
+ /**
+ * The id of the component.
+ *
+ * @return the ID
+ */
+ String getId();
+
+ /**
+ * Returns the proxied entities chain. The format of the chain is as
+ * follows:
+ *
+ *
+ * <CN=original-proxied-entity><CN=first-proxy><CN=second-proxy>...
+ *
+ *
+ * @return the proxied entities chain or null if no chain
+ */
+ String getProxiedEntitiesChain();
+
+}
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/web/ProcessorConfigurationAction.java b/nifi/nifi-api/src/main/java/org/apache/nifi/web/ProcessorConfigurationAction.java
index 8385e4a239..ce5e069d30 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/web/ProcessorConfigurationAction.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/web/ProcessorConfigurationAction.java
@@ -19,6 +19,7 @@ package org.apache.nifi.web;
/**
*
*/
+@Deprecated
public class ProcessorConfigurationAction {
private final String processorId;
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/web/ProcessorInfo.java b/nifi/nifi-api/src/main/java/org/apache/nifi/web/ProcessorInfo.java
index 04810981b6..e87e73e306 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/web/ProcessorInfo.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/web/ProcessorInfo.java
@@ -22,6 +22,7 @@ import java.util.Map;
/**
*
*/
+@Deprecated
public class ProcessorInfo {
private final String id;
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/web/Revision.java b/nifi/nifi-api/src/main/java/org/apache/nifi/web/Revision.java
index 1881c2f526..8a6275e1c5 100644
--- a/nifi/nifi-api/src/main/java/org/apache/nifi/web/Revision.java
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/web/Revision.java
@@ -37,12 +37,12 @@ public class Revision implements Serializable {
* the client ID
*/
private final String clientId;
-
+
public Revision(Long revision, String clientId) {
this.version = revision;
this.clientId = clientId;
}
-
+
public String getClientId() {
return clientId;
}
@@ -51,34 +51,6 @@ public class Revision implements Serializable {
return version;
}
- /**
- * A factory method for creating a new Revision instance whose version is
- * this instance's version plus 1.
- *
- * @return an updated revision
- */
- public Revision increment() {
- final long incrementedVersion;
- if (version == null) {
- incrementedVersion = 0;
- } else {
- incrementedVersion = version + 1;
- }
- return new Revision(incrementedVersion, clientId);
- }
-
- /**
- * A factory method for creating a new Revision instance whose version is
- * this instance's version plus 1 and whose client ID is the given client
- * ID.
- *
- * @param clientId the client ID
- * @return an updated revision
- */
- public Revision increment(String clientId) {
- return new Revision(increment().getVersion(), clientId);
- }
-
@Override
public boolean equals(final Object obj) {
diff --git a/nifi/nifi-api/src/main/java/org/apache/nifi/web/UiExtensionType.java b/nifi/nifi-api/src/main/java/org/apache/nifi/web/UiExtensionType.java
new file mode 100644
index 0000000000..0bbda16d66
--- /dev/null
+++ b/nifi/nifi-api/src/main/java/org/apache/nifi/web/UiExtensionType.java
@@ -0,0 +1,31 @@
+/*
+ * 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.web;
+
+/**
+ * Types of UI extensions. Since a UI extension could support multiple
+ * types of custom UIs it will need to include the type so the framework
+ * can appropriate understand and process the request (recording actions
+ * in the audit database, replicating a request throughout the cluster to
+ * the appropriate endpoints, etc).
+ */
+public enum UiExtensionType {
+ ContentViewer,
+ ProcessorConfiguration,
+ ControllerServiceConfiguration,
+ ReportingTaskConfiguration
+}
diff --git a/nifi/nifi-assembly/NOTICE b/nifi/nifi-assembly/NOTICE
index 8d7db8d7ec..f14c662257 100644
--- a/nifi/nifi-assembly/NOTICE
+++ b/nifi/nifi-assembly/NOTICE
@@ -501,6 +501,54 @@ The following binary components are provided under the Apache Software License v
Apache License Version 2.0 http://www.apache.org/licenses/.
(c) Daniel Lemire, http://lemire.me/en/
+ (ASLv2) Twitter4J
+ The following NOTICE information applies:
+ Copyright 2007 Yusuke Yamamoto
+
+ Twitter4J includes software from JSON.org to parse JSON response from the Twitter API. You can see the license term at http://www.JSON.org/license.html
+
+ (ASLv2) JOAuth
+ The following NOTICE information applies:
+ JOAuth
+ Copyright 2010-2013 Twitter, Inc
+
+ Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
+
+ (ASLv2) Hosebird Client
+ The following NOTICE information applies:
+ Hosebird Client (hbc)
+ Copyright 2013 Twitter, Inc.
+
+ Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
+
+ (ASLv2) GeoIP2 Java API
+ The following NOTICE information applies:
+ GeoIP2 Java API
+ This software is Copyright (c) 2013 by MaxMind, Inc.
+
+ This is free software, licensed under the Apache License, Version 2.0.
+
+ (ASLv2) Google HTTP Client Library for Java
+ The following NOTICE information applies:
+ Google HTTP Client Library for Java
+
+ This is free software, licensed under the Apache License, Version 2.0.
+
+ (ASLv2) Amazon Web Services SDK
+ The following NOTICE information applies:
+ Copyright 2010-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+
+ This product includes software developed by
+ Amazon Technologies, Inc (http://www.amazon.com/).
+
+ **********************
+ THIRD PARTY COMPONENTS
+ **********************
+ This software includes third party software subject to the following copyrights:
+ - XML parsing and utility functions from JetS3t - Copyright 2006-2009 James Murty.
+ - JSON parsing and utility functions from JSON.org - Copyright 2002 JSON.org.
+ - PKCS#1 PEM encoded private key parsing and utility functions from oauth.googlecode.com - Copyright 1998-2010 AOL Inc.
+
************************
Common Development and Distribution License 1.1
@@ -540,6 +588,14 @@ The following binary components are provided under the Common Development and Di
(CDDL 1.0) JavaServer Pages(TM) API (javax.servlet.jsp:jsp-api:jar:2.1 - http://jsp.java.net)
(CDDL 1.0) SR 250 Common Annotations For The JavaTM Platform (javax.annotation:jsr250-api:jar:1.0 - http://jcp.org/aboutJava/communityprocess/final/jsr250/index.html)
+************************
+Creative Commons Attribution-ShareAlike 3.0
+************************
+
+The following binary components are provided under the Creative Commons Attribution-ShareAlike 3.0. See project link for details.
+
+ (CCAS 3.0) MaxMind DB (https://github.com/maxmind/MaxMind-DB)
+
************************
Eclipse Public License 1.0
************************
@@ -559,6 +615,15 @@ The following binary components are provided under the Mozilla Public License v2
(MPL 2.0) Saxon HE (net.sf.saxon:Saxon-HE:jar:9.6.0-4 - http://www.saxonica.com/)
+*****************
+Mozilla Public License v1.1
+*****************
+
+The following binary components are provided under the Mozilla Public License v1.1. See project link for details.
+
+ (MPL 1.1) HAPI Base (ca.uhn.hapi:hapi-base:2.2 - http://hl7api.sourceforge.net/)
+ (MPL 1.1) HAPI Structures (ca.uhn.hapi:hapi-structures-v*:2.2 - http://hl7api.sourceforge.net/)
+
*****************
Public Domain
*****************
diff --git a/nifi/nifi-assembly/pom.xml b/nifi/nifi-assembly/pom.xml
index cae0f00a90..13ffba802d 100644
--- a/nifi/nifi-assembly/pom.xml
+++ b/nifi/nifi-assembly/pom.xml
@@ -1,459 +1,484 @@
-
-
- 4.0.0
-
- org.apache.nifi
- nifi
- 0.1.0-incubating-SNAPSHOT
-
- nifi-assembly
- pom
- This is the assembly Apache NiFi (incubating)
-
-
-
- maven-assembly-plugin
-
- nifi-${project.version}
- false
-
-
-
- make shared resource
-
- single
-
- package
-
-
- src/main/assembly/dependencies.xml
-
- posix
-
-
-
-
-
-
-
-
- ch.qos.logback
- logback-classic
- compile
-
-
- org.slf4j
- jcl-over-slf4j
- compile
-
-
- org.slf4j
- jul-to-slf4j
- compile
-
-
- org.slf4j
- log4j-over-slf4j
- compile
-
-
- org.slf4j
- slf4j-api
- compile
-
-
- org.apache.nifi
- nifi-api
-
-
- org.apache.nifi
- nifi-runtime
-
-
- org.apache.nifi
- nifi-bootstrap
-
-
- org.apache.nifi
- nifi-resources
- resources
- runtime
- zip
-
-
- org.apache.nifi
- nifi-docs
- resources
- runtime
- zip
-
-
- org.apache.nifi
- nifi-framework-nar
- nar
-
-
- org.apache.nifi
- nifi-provenance-repository-nar
- nar
-
-
- org.apache.nifi
- nifi-standard-services-api-nar
- nar
-
-
- org.apache.nifi
- nifi-ssl-context-service-nar
- nar
-
-
- org.apache.nifi
- nifi-distributed-cache-services-nar
- nar
-
-
- org.apache.nifi
- nifi-standard-nar
- nar
-
-
- org.apache.nifi
- nifi-jetty-bundle
- nar
-
-
- org.apache.nifi
- nifi-update-attribute-nar
- nar
-
-
- org.apache.nifi
- nifi-hadoop-libraries-nar
- nar
-
-
- org.apache.nifi
- nifi-hadoop-nar
- nar
-
-
- org.apache.nifi
- nifi-kafka-nar
- nar
-
+
+
+ 4.0.0
+
+ org.apache.nifi
+ nifi
+ 0.1.0-incubating-SNAPSHOT
+
+ nifi-assembly
+ pom
+ This is the assembly Apache NiFi (incubating)
+
+
+
+ maven-assembly-plugin
+
+ nifi-${project.version}
+ false
+
+
+
+ make shared resource
+
+ single
+
+ package
+
+
+ src/main/assembly/dependencies.xml
+
+ posix
+
+
+
+
+
+
+
- org.apache.nifi
- nifi-http-context-map-nar
- nar
-
+ ch.qos.logback
+ logback-classic
+ compile
+
- org.apache.nifi
- nifi-kite-nar
- nar
-
-
-
-
-
- 256
- 512
- 128
- 128
- 10m
- 10
-
-
- ${project.version}
- true
- 10 sec
- 500 ms
- 30 sec
- 10 millis
+ org.slf4j
+ jcl-over-slf4j
+ compile
+
+
+ org.slf4j
+ jul-to-slf4j
+ compile
+
+
+ org.slf4j
+ log4j-over-slf4j
+ compile
+
+
+ org.slf4j
+ slf4j-api
+ compile
+
+
+ org.apache.nifi
+ nifi-api
+
+
+ org.apache.nifi
+ nifi-runtime
+
+
+ org.apache.nifi
+ nifi-bootstrap
+
+
+ org.apache.nifi
+ nifi-resources
+ resources
+ runtime
+ zip
+
+
+ org.apache.nifi
+ nifi-docs
+ resources
+ runtime
+ zip
+
+
+ org.apache.nifi
+ nifi-framework-nar
+ nar
+
+
+ org.apache.nifi
+ nifi-provenance-repository-nar
+ nar
+
+
+ org.apache.nifi
+ nifi-standard-services-api-nar
+ nar
+
+
+ org.apache.nifi
+ nifi-ssl-context-service-nar
+ nar
+
+
+ org.apache.nifi
+ nifi-distributed-cache-services-nar
+ nar
+
+
+ org.apache.nifi
+ nifi-standard-nar
+ nar
+
+
+ org.apache.nifi
+ nifi-jetty-bundle
+ nar
+
+
+ org.apache.nifi
+ nifi-update-attribute-nar
+ nar
+
+
+ org.apache.nifi
+ nifi-hadoop-libraries-nar
+ nar
+
+
+ org.apache.nifi
+ nifi-hadoop-nar
+ nar
+
+
+ org.apache.nifi
+ nifi-kafka-nar
+ nar
+
+
+ org.apache.nifi
+ nifi-http-context-map-nar
+ nar
+
+
+ org.apache.nifi
+ nifi-kite-nar
+ nar
+
+
+ org.apache.nifi
+ nifi-social-media-nar
+ 0.1.0-incubating-SNAPSHOT
+ nar
+
+
+ org.apache.nifi
+ nifi-hl7-nar
+ 0.1.0-incubating-SNAPSHOT
+ nar
+
+
+ org.apache.nifi
+ nifi-language-translation-nar
+ 0.1.0-incubating-SNAPSHOT
+ nar
+
+
+ org.apache.nifi
+ nifi-geo-nar
+ 0.1.0-incubating-SNAPSHOT
+ nar
+
+
- ./conf/flow.xml.gz
- ./conf/archive/
- ./conf/reporting-tasks.xml
- ./conf/controller-services.xml
- ./conf/authority-providers.xml
- ./conf/templates
- ./database_repository
+
+
+ 256
+ 512
+ 128
+ 128
+ 10m
+ 10
- org.apache.nifi.controller.repository.WriteAheadFlowFileRepository
- ./flowfile_repository
- 256
- 2 mins
- false
- org.apache.nifi.controller.FileSystemSwapManager
- 20000
- 5 sec
- 1
- 5 sec
- 4
-
- org.apache.nifi.controller.repository.FileSystemRepository
- 10 MB
- 100
- ./content_repository
-
-
- false
- false
-
-
-
-
- 30 sec
- ./lib
- ./work/nar/
- ./work/docs/components
-
- PBEWITHMD5AND256BITAES-CBC-OPENSSL
- BC
- ;LOCK_TIMEOUT=25000;WRITE_DELAY=0;AUTO_SERVER=FALSE
+
+ ${project.version}
+ true
+ 10 sec
+ 500 ms
+ 30 sec
+ 10 millis
- 9990
-
-
- org.apache.nifi.provenance.PersistentProvenanceRepository
- ./provenance_repository
- 24 hours
- 1 GB
- 5 mins
- 100 MB
- 2
- true
- EventType, FlowFileUUID, Filename, ProcessorID
-
- 500 MB
- false
- 16
-
-
- 100000
-
-
- org.apache.nifi.controller.status.history.VolatileComponentStatusRepository
- 288
- 5 mins
-
-
- ./lib
-
- 8080
-
-
- ./work/jetty
- 200
-
-
-
-
-
-
-
-
-
-
- ./conf/authorized-users.xml
- 24 hours
- file-provider
-
-
-
-
-
-
- 5 sec
- false
- 30 sec
- 45 sec
- false
-
-
- 500 ms
- 3
- 1 sec
+ ./conf/flow.xml.gz
+ ./conf/archive/
+ ./conf/authority-providers.xml
+ ./conf/templates
+ ./database_repository
-
- false
-
-
- 2
-
-
-
-
- false
-
-
-
- 10
- 30 sec
- 30 sec
- 10
- 5 sec
- 10
- 0 sec
-
-
-
- rpm
-
- false
-
-
-
-
- maven-dependency-plugin
-
-
- unpack-shared-resources
-
- unpack-dependencies
-
- generate-resources
-
- ${project.build.directory}/generated-resources
- nifi-resources
- org.apache.nifi
- false
-
-
-
- unpack-docs
-
- unpack-dependencies
-
- generate-resources
-
- ${project.build.directory}/generated-docs
- nifi-docs
- org.apache.nifi
- false
-
-
-
-
-
- org.codehaus.mojo
- rpm-maven-plugin
-
- Apache NiFi (incubating)
- Apache Nifi (incubating) is dataflow system based on the Flow-Based Programming concepts.
- Apache License, Version 2.0 and others (see included LICENSE file)
- http://nifi.incubator.apache.org
- Utilities
- /opt/nifi
-
- _use_internal_dependency_generator 0
-
- 750
- 640
- root
- root
-
-
-
- build-bin-rpm
-
- attached-rpm
-
-
- bin
-
- nifi
-
-
-
- /opt/nifi/nifi-${project.version}
-
-
- /opt/nifi/nifi-${project.version}
-
-
-
-
-
-
-
-
- /opt/nifi/nifi-${project.version}/bin
- 750
-
-
-
-
-
- /opt/nifi/nifi-${project.version}/conf
- true
-
-
-
-
-
- /opt/nifi/nifi-${project.version}/lib
-
-
- org.apache.nifi:nifi-bootstrap
- org.apache.nifi:nifi-resources
- org.apache.nifi:nifi-docs
-
-
-
-
- /opt/nifi/nifi-${project.version}/lib/bootstrap
-
-
- org.apache.nifi:nifi-bootstrap
-
-
-
-
- /opt/nifi/nifi-${project.version}/docs
-
-
-
-
-
-
-
-
-
-
-
-
-
+ org.apache.nifi.controller.repository.WriteAheadFlowFileRepository
+ ./flowfile_repository
+ 256
+ 2 mins
+ false
+ org.apache.nifi.controller.FileSystemSwapManager
+ 20000
+ 5 sec
+ 1
+ 5 sec
+ 4
+
+ org.apache.nifi.controller.repository.FileSystemRepository
+ 10 MB
+ 100
+ ./content_repository
+
+
+ false
+ false
+
+
+
+
+ 30 sec
+ ./lib
+ ./work/nar/
+ ./work/docs/components
+
+ PBEWITHMD5AND256BITAES-CBC-OPENSSL
+ BC
+ ;LOCK_TIMEOUT=25000;WRITE_DELAY=0;AUTO_SERVER=FALSE
+
+ 9990
+
+
+ org.apache.nifi.provenance.PersistentProvenanceRepository
+ ./provenance_repository
+ 24 hours
+ 1 GB
+ 5 mins
+ 100 MB
+ 2
+ true
+ EventType, FlowFileUUID,
+ Filename, ProcessorID
+
+ 500 MB
+ false
+ 16
+
+
+ 100000
+
+
+ org.apache.nifi.controller.status.history.VolatileComponentStatusRepository
+ 288
+ 5 mins
+
+
+ ./lib
+
+ 8080
+
+
+ ./work/jetty
+ 200
+
+
+
+
+
+
+
+
+
+
+ ./conf/authorized-users.xml
+ 24 hours
+ file-provider
+
+
+
+
+
+
+ 5 sec
+ false
+ 30 sec
+ 45 sec
+ false
+
+
+ 500 ms
+ 3
+ 1 sec
+
+
+ false
+
+
+ 2
+
+
+
+
+ false
+
+
+
+ 10
+ 30 sec
+ 30 sec
+ 10
+ 5 sec
+ 10
+ 0 sec
+
+
+
+ rpm
+
+ false
+
+
+
+
+ maven-dependency-plugin
+
+
+ unpack-shared-resources
+
+ unpack-dependencies
+
+ generate-resources
+
+ ${project.build.directory}/generated-resources
+ nifi-resources
+ org.apache.nifi
+ false
+
+
+
+ unpack-docs
+
+ unpack-dependencies
+
+ generate-resources
+
+ ${project.build.directory}/generated-docs
+ nifi-docs
+ org.apache.nifi
+ false
+
+
+
+
+
+ org.codehaus.mojo
+ rpm-maven-plugin
+
+ Apache NiFi (incubating)
+ Apache Nifi (incubating) is dataflow system based on
+ the Flow-Based Programming concepts.
+ Apache License, Version 2.0 and others (see included
+ LICENSE file)
+ http://nifi.incubator.apache.org
+ Utilities
+ /opt/nifi
+
+ _use_internal_dependency_generator 0
+
+ 750
+ 640
+ root
+ root
+
+
+
+ build-bin-rpm
+
+ attached-rpm
+
+
+ bin
+
+ nifi
+
+
+
+ /opt/nifi/nifi-${project.version}
+
+
+ /opt/nifi/nifi-${project.version}
+
+
+
+
+
+
+
+
+ /opt/nifi/nifi-${project.version}/bin
+ 750
+
+
+
+
+
+ /opt/nifi/nifi-${project.version}/conf
+ true
+
+
+
+
+
+ /opt/nifi/nifi-${project.version}/lib
+
+
+ org.apache.nifi:nifi-bootstrap
+ org.apache.nifi:nifi-resources
+ org.apache.nifi:nifi-docs
+
+
+
+
+ /opt/nifi/nifi-${project.version}/lib/bootstrap
+
+
+ org.apache.nifi:nifi-bootstrap
+
+
+
+
+ /opt/nifi/nifi-${project.version}/docs
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/nifi/nifi-commons/nifi-hl7-query-language/.gitignore b/nifi/nifi-commons/nifi-hl7-query-language/.gitignore
new file mode 100644
index 0000000000..e91d5c41bb
--- /dev/null
+++ b/nifi/nifi-commons/nifi-hl7-query-language/.gitignore
@@ -0,0 +1,3 @@
+/target/
+/target/
+/target/
diff --git a/nifi/nifi-commons/nifi-hl7-query-language/pom.xml b/nifi/nifi-commons/nifi-hl7-query-language/pom.xml
new file mode 100644
index 0000000000..7daa400835
--- /dev/null
+++ b/nifi/nifi-commons/nifi-hl7-query-language/pom.xml
@@ -0,0 +1,122 @@
+
+
+
+ 4.0.0
+
+
+ org.apache.nifi
+ nifi-commons
+ 0.1.0-incubating-SNAPSHOT
+
+
+ nifi-hl7-query-language
+ jar
+
+
+
+ maven-compiler-plugin
+
+
+ 1.7
+
+
+
+ org.antlr
+ antlr3-maven-plugin
+
+
+
+ antlr
+
+
+
+
+
+ org.apache.rat
+ apache-rat-plugin
+
+
+ src/test/resources/hypoglycemia
+ src/test/resources/hyperglycemia
+
+
+
+
+
+
+
+
+ org.antlr
+ antlr-runtime
+ 3.5.2
+
+
+
+
+ ca.uhn.hapi
+ hapi-base
+ 2.2
+
+
+ ca.uhn.hapi
+ hapi-structures-v21
+ 2.2
+
+
+ ca.uhn.hapi
+ hapi-structures-v22
+ 2.2
+
+
+ ca.uhn.hapi
+ hapi-structures-v23
+ 2.2
+
+
+ ca.uhn.hapi
+ hapi-structures-v231
+ 2.2
+
+
+ ca.uhn.hapi
+ hapi-structures-v24
+ 2.2
+
+
+ ca.uhn.hapi
+ hapi-structures-v25
+ 2.2
+
+
+ ca.uhn.hapi
+ hapi-structures-v251
+ 2.2
+
+
+ ca.uhn.hapi
+ hapi-structures-v26
+ 2.2
+
+
+
+
+ junit
+ junit
+ test
+
+
+
diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/antlr3/org/apache/nifi/hl7/query/antlr/HL7QueryLexer.g b/nifi/nifi-commons/nifi-hl7-query-language/src/main/antlr3/org/apache/nifi/hl7/query/antlr/HL7QueryLexer.g
new file mode 100644
index 0000000000..478028b9f7
--- /dev/null
+++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/antlr3/org/apache/nifi/hl7/query/antlr/HL7QueryLexer.g
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+
+lexer grammar HL7QueryLexer;
+
+@header {
+ package org.apache.nifi.hl7.query.antlr;
+ import org.apache.nifi.hl7.query.exception.HL7QueryParsingException;
+}
+
+@rulecatch {
+ catch(final Exception e) {
+ throw new HL7QueryParsingException(e);
+ }
+}
+
+@members {
+ public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
+ final StringBuilder sb = new StringBuilder();
+ if ( e.token == null ) {
+ sb.append("Unrecognized token ");
+ } else {
+ sb.append("Unexpected token '").append(e.token.getText()).append("' ");
+ }
+ sb.append("at line ").append(e.line);
+ if ( e.approximateLineInfo ) {
+ sb.append(" (approximately)");
+ }
+ sb.append(", column ").append(e.charPositionInLine);
+ sb.append(". Query: ").append(e.input.toString());
+
+ throw new HL7QueryParsingException(sb.toString());
+ }
+
+ public void recover(RecognitionException e) {
+ final StringBuilder sb = new StringBuilder();
+ if ( e.token == null ) {
+ sb.append("Unrecognized token ");
+ } else {
+ sb.append("Unexpected token '").append(e.token.getText()).append("' ");
+ }
+ sb.append("at line ").append(e.line);
+ if ( e.approximateLineInfo ) {
+ sb.append(" (approximately)");
+ }
+ sb.append(", column ").append(e.charPositionInLine);
+ sb.append(". Query: ").append(e.input.toString());
+
+ throw new HL7QueryParsingException(sb.toString());
+ }
+}
+
+
+// PUNCTUATION & SPECIAL CHARACTERS
+WHITESPACE : (' '|'\t'|'\n'|'\r')+ { $channel = HIDDEN; };
+COMMENT : '#' ( ~('\n') )* '\n' { $channel = HIDDEN; };
+
+LPAREN : '(';
+RPAREN : ')';
+LBRACE : '{';
+RBRACE : '}';
+COLON : ':';
+COMMA : ',';
+DOT : '.';
+SEMICOLON : ';';
+
+
+
+// OPERATORS
+EQUALS : '=';
+NOT_EQUALS : '!=';
+GT : '>';
+GE : '>=';
+LT : '<';
+LE : '<=';
+REGEX : 'MATCHES REGEX';
+LIKE : 'LIKE';
+IS_NULL : 'IS NULL';
+NOT_NULL : 'NOT NULL';
+
+
+// KEYWORDS
+AND : 'AND';
+OR : 'OR';
+NOT : 'NOT';
+
+TRUE : 'true';
+FALSE : 'false';
+
+SELECT : 'select' | 'SELECT';
+DECLARE : 'declare' | 'DECLARE';
+OPTIONAL : 'optional' | 'OPTIONAL';
+REQUIRED : 'required' | 'REQUIRED';
+AS : 'as' | 'AS';
+WHERE : 'where' | 'WHERE';
+
+MESSAGE : 'MESSAGE' | 'message';
+SEGMENT : 'SEGMENT' | 'segment';
+
+
+SEGMENT_NAME : LETTER ALPHA_NUMERIC ALPHA_NUMERIC;
+
+
+NUMBER : ('0'..'9')+;
+fragment LETTER : 'A'..'Z';
+fragment ALPHA_NUMERIC : 'A'..'Z' | '0'..'9';
+
+
+// STRINGS
+STRING_LITERAL
+@init{StringBuilder lBuf = new StringBuilder();}
+ :
+ (
+ '"'
+ (
+ escaped=ESC {lBuf.append(getText());} |
+ normal = ~( '"' | '\\' | '\n' | '\r' | '\t' ) { lBuf.appendCodePoint(normal);}
+ )*
+ '"'
+ )
+ {
+ setText(lBuf.toString());
+ }
+ |
+ (
+ '\''
+ (
+ escaped=ESC {lBuf.append(getText());} |
+ normal = ~( '\'' | '\\' | '\n' | '\r' | '\t' ) { lBuf.appendCodePoint(normal);}
+ )*
+ '\''
+ )
+ {
+ setText(lBuf.toString());
+ }
+ ;
+
+
+fragment
+ESC
+ : '\\'
+ (
+ '"' { setText("\""); }
+ | '\'' { setText("\'"); }
+ | 'r' { setText("\r"); }
+ | 'n' { setText("\n"); }
+ | 't' { setText("\t"); }
+ | '\\' { setText("\\\\"); }
+ | nextChar = ~('"' | '\'' | 'r' | 'n' | 't' | '\\')
+ {
+ StringBuilder lBuf = new StringBuilder(); lBuf.append("\\\\").appendCodePoint(nextChar); setText(lBuf.toString());
+ }
+ )
+ ;
+
+IDENTIFIER : (
+ ~('$' | '{' | '}' | '(' | ')' | '[' | ']' | ',' | ':' | ';' | '/' | '*' | '\'' | ' ' | '\t' | '\r' | '\n' | '0'..'9' | '.')
+ ~('$' | '{' | '}' | '(' | ')' | '[' | ']' | ',' | ':' | ';' | '/' | '*' | '\'' | ' ' | '\t' | '\r' | '\n' | '.')*
+ );
diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/antlr3/org/apache/nifi/hl7/query/antlr/HL7QueryParser.g b/nifi/nifi-commons/nifi-hl7-query-language/src/main/antlr3/org/apache/nifi/hl7/query/antlr/HL7QueryParser.g
new file mode 100644
index 0000000000..f051872eba
--- /dev/null
+++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/antlr3/org/apache/nifi/hl7/query/antlr/HL7QueryParser.g
@@ -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.
+ */
+
+parser grammar HL7QueryParser;
+
+options {
+ output=AST;
+ tokenVocab=HL7QueryLexer;
+}
+
+tokens {
+ QUERY;
+ DECLARATION;
+}
+
+@header {
+ package org.apache.nifi.hl7.query.antlr;
+ import org.apache.nifi.hl7.query.exception.HL7QueryParsingException;
+}
+
+@members {
+ public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
+ final StringBuilder sb = new StringBuilder();
+ if ( e.token == null ) {
+ sb.append("Unrecognized token ");
+ } else {
+ sb.append("Unexpected token '").append(e.token.getText()).append("' ");
+ }
+ sb.append("at line ").append(e.line);
+ if ( e.approximateLineInfo ) {
+ sb.append(" (approximately)");
+ }
+ sb.append(", column ").append(e.charPositionInLine);
+ sb.append(". Query: ").append(e.input.toString());
+
+ throw new HL7QueryParsingException(sb.toString());
+ }
+
+ public void recover(final RecognitionException e) {
+ final StringBuilder sb = new StringBuilder();
+ if ( e.token == null ) {
+ sb.append("Unrecognized token ");
+ } else {
+ sb.append("Unexpected token '").append(e.token.getText()).append("' ");
+ }
+ sb.append("at line ").append(e.line);
+ if ( e.approximateLineInfo ) {
+ sb.append(" (approximately)");
+ }
+ sb.append(", column ").append(e.charPositionInLine);
+ sb.append(". Query: ").append(e.input.toString());
+
+ throw new HL7QueryParsingException(sb.toString());
+ }
+}
+
+
+declareClause : DECLARE^ declaration (COMMA! declaration)*;
+
+requiredOrOptional : REQUIRED | OPTIONAL;
+declaration : IDENTIFIER AS requiredOrOptional SEGMENT_NAME ->
+ ^(DECLARATION IDENTIFIER requiredOrOptional SEGMENT_NAME);
+
+
+selectClause : SELECT^ selectableClause;
+selectableClause : selectable (COMMA! selectable)*;
+selectable : (MESSAGE | ref | field)^ (AS! IDENTIFIER^)?;
+
+
+whereClause : WHERE^ conditions;
+
+conditions : condition ((AND^ | OR^) condition)*;
+
+condition : NOT^ condition | LPAREN! conditions RPAREN! | evaluation;
+
+evaluation : expression
+ (
+ unaryOperator^
+ | (binaryOperator^ expression)
+ );
+
+expression : (LPAREN! expr RPAREN!) | expr;
+expr : ref | field | STRING_LITERAL | NUMBER;
+
+unaryOperator : IS_NULL | NOT_NULL;
+binaryOperator : EQUALS | NOT_EQUALS | LT | GT | LE | GE;
+
+ref : (SEGMENT_NAME | IDENTIFIER);
+field : ref DOT^ NUMBER
+ (DOT^ NUMBER (DOT^ NUMBER (DOT^ NUMBER)?)?)?;
+
+
+query : declareClause? selectClause whereClause? EOF ->
+ ^(QUERY declareClause? selectClause whereClause?);
diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/EmptyField.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/EmptyField.java
new file mode 100644
index 0000000000..be645e59c8
--- /dev/null
+++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/EmptyField.java
@@ -0,0 +1,37 @@
+/*
+ * 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.hl7.hapi;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.nifi.hl7.model.HL7Component;
+import org.apache.nifi.hl7.model.HL7Field;
+
+public class EmptyField implements HL7Field {
+
+ @Override
+ public String getValue() {
+ return null;
+ }
+
+ @Override
+ public List getComponents() {
+ return Collections.emptyList();
+ }
+
+}
diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/HapiField.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/HapiField.java
new file mode 100644
index 0000000000..056b6b677d
--- /dev/null
+++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/HapiField.java
@@ -0,0 +1,83 @@
+/*
+ * 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.hl7.hapi;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.nifi.hl7.model.HL7Component;
+import org.apache.nifi.hl7.model.HL7Field;
+
+import ca.uhn.hl7v2.model.Composite;
+import ca.uhn.hl7v2.model.ExtraComponents;
+import ca.uhn.hl7v2.model.Primitive;
+import ca.uhn.hl7v2.model.Type;
+import ca.uhn.hl7v2.model.Varies;
+import ca.uhn.hl7v2.parser.EncodingCharacters;
+import ca.uhn.hl7v2.parser.PipeParser;
+
+public class HapiField implements HL7Field, HL7Component {
+ private final String value;
+ private final List components;
+
+ public HapiField(final Type type) {
+ this.value = PipeParser.encode(type, EncodingCharacters.defaultInstance());
+
+ final List componentList = new ArrayList<>();
+ if ( type instanceof Composite ) {
+ final Composite composite = (Composite) type;
+
+ for ( final Type component : composite.getComponents() ) {
+ componentList.add(new HapiField(component));
+ }
+ }
+
+ final ExtraComponents extra = type.getExtraComponents();
+ if ( extra != null && extra.numComponents() > 0 ) {
+ final String singleFieldValue;
+ if ( type instanceof Primitive ) {
+ singleFieldValue = ((Primitive) type).getValue();
+ } else {
+ singleFieldValue = this.value;
+ }
+ componentList.add(new SingleValueField(singleFieldValue));
+
+ for (int i=0; i < extra.numComponents(); i++) {
+ final Varies varies = extra.getComponent(i);
+ componentList.add(new HapiField(varies));
+ }
+ }
+
+ this.components = Collections.unmodifiableList(componentList);
+ }
+
+ @Override
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public List getComponents() {
+ return components;
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+}
diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/HapiMessage.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/HapiMessage.java
new file mode 100644
index 0000000000..ddd28b2bf9
--- /dev/null
+++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/HapiMessage.java
@@ -0,0 +1,94 @@
+/*
+ * 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.hl7.hapi;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.nifi.hl7.model.HL7Message;
+import org.apache.nifi.hl7.model.HL7Segment;
+
+import ca.uhn.hl7v2.HL7Exception;
+import ca.uhn.hl7v2.model.Group;
+import ca.uhn.hl7v2.model.Message;
+import ca.uhn.hl7v2.model.Segment;
+import ca.uhn.hl7v2.model.Structure;
+
+public class HapiMessage implements HL7Message {
+ private final Message message;
+ private final List allSegments;
+ private final Map> segmentMap;
+
+ public HapiMessage(final Message message) throws HL7Exception {
+ this.message = message;
+
+ allSegments = new ArrayList<>();
+ populateSegments(message, allSegments);
+
+ segmentMap = new HashMap<>();
+ for ( final HL7Segment segment : allSegments ) {
+ final String segmentName = segment.getName();
+ List segmentList = segmentMap.get(segmentName);
+ if ( segmentList == null ) {
+ segmentList = new ArrayList<>();
+ segmentMap.put(segmentName, segmentList);
+ }
+
+ segmentList.add(segment);
+ }
+ }
+
+ private void populateSegments(final Group group, final List segments) throws HL7Exception {
+ for ( final String structureName : group.getNames() ) {
+ final Structure[] structures = group.getAll(structureName);
+ if ( group.isGroup(structureName) ) {
+ for ( final Structure structure : structures ) {
+ populateSegments((Group) structure, segments);
+ }
+ } else {
+ for ( final Structure structure : structures ) {
+ final Segment segment = (Segment) structure;
+ final HapiSegment hapiSegment = new HapiSegment(segment);
+ segments.add(hapiSegment);
+ }
+ }
+ }
+ }
+
+ @Override
+ public List getSegments() {
+ return Collections.unmodifiableList(allSegments);
+ }
+
+ @Override
+ public List getSegments(final String segmentType) {
+ final List segments = segmentMap.get(segmentType);
+ if ( segments == null ) {
+ return Collections.emptyList();
+ }
+
+ return Collections.unmodifiableList(segments);
+ }
+
+ @Override
+ public String toString() {
+ return message.toString();
+ }
+}
diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/HapiSegment.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/HapiSegment.java
new file mode 100644
index 0000000000..d50afdb960
--- /dev/null
+++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/HapiSegment.java
@@ -0,0 +1,69 @@
+/*
+ * 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.hl7.hapi;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.nifi.hl7.model.HL7Field;
+import org.apache.nifi.hl7.model.HL7Segment;
+
+import ca.uhn.hl7v2.HL7Exception;
+import ca.uhn.hl7v2.model.Segment;
+import ca.uhn.hl7v2.model.Type;
+
+public class HapiSegment implements HL7Segment {
+ private final Segment segment;
+ private final List fields;
+
+ public HapiSegment(final Segment segment) throws HL7Exception {
+ this.segment = segment;
+
+ final List fieldList = new ArrayList<>();
+ for (int i=1; i <= segment.numFields(); i++) {
+ final Type[] types = segment.getField(i);
+
+ if ( types == null || types.length == 0 ) {
+ fieldList.add(new EmptyField());
+ continue;
+ }
+
+ for ( final Type type : types ) {
+ fieldList.add(new HapiField(type));
+ }
+ }
+
+ this.fields = Collections.unmodifiableList(fieldList);
+ }
+
+
+ @Override
+ public String getName() {
+ return segment.getName();
+ }
+
+ @Override
+ public List getFields() {
+ return fields;
+ }
+
+ @Override
+ public String toString() {
+ return segment.toString();
+ }
+}
diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/SingleValueField.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/SingleValueField.java
new file mode 100644
index 0000000000..ed99077b45
--- /dev/null
+++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/SingleValueField.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.hl7.hapi;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.nifi.hl7.model.HL7Component;
+import org.apache.nifi.hl7.model.HL7Field;
+
+public class SingleValueField implements HL7Field {
+ private final String value;
+
+ public SingleValueField(final String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public List getComponents() {
+ return Collections.emptyList();
+ }
+
+}
diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/io/HL7Reader.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/io/HL7Reader.java
new file mode 100644
index 0000000000..e7b31a4c4a
--- /dev/null
+++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/io/HL7Reader.java
@@ -0,0 +1,27 @@
+/*
+ * 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.hl7.io;
+
+import java.io.IOException;
+
+import org.apache.nifi.hl7.model.HL7Message;
+
+public interface HL7Reader {
+
+ HL7Message nextMessage() throws IOException;
+
+}
diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/io/exception/InvalidHL7Exception.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/io/exception/InvalidHL7Exception.java
new file mode 100644
index 0000000000..669f40c6bc
--- /dev/null
+++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/io/exception/InvalidHL7Exception.java
@@ -0,0 +1,40 @@
+/*
+ * 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.hl7.io.exception;
+
+import java.io.IOException;
+
+public class InvalidHL7Exception extends IOException {
+ private static final long serialVersionUID = -5675416667224562441L;
+
+ public InvalidHL7Exception() {
+ super();
+ }
+
+ public InvalidHL7Exception(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public InvalidHL7Exception(String message) {
+ super(message);
+ }
+
+ public InvalidHL7Exception(Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Component.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Component.java
new file mode 100644
index 0000000000..cf355041b1
--- /dev/null
+++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Component.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.hl7.model;
+
+import java.util.List;
+
+public interface HL7Component {
+ String getValue();
+ List getComponents();
+}
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/Availability.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Field.java
similarity index 87%
rename from nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/Availability.java
rename to nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Field.java
index 38df6f754e..4086e581d1 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/Availability.java
+++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Field.java
@@ -14,11 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.nifi.controller;
+package org.apache.nifi.hl7.model;
-public enum Availability {
- CLUSTER_MANAGER_ONLY,
- NODE_ONLY,
- BOTH;
+public interface HL7Field extends HL7Component {
}
diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Message.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Message.java
new file mode 100644
index 0000000000..dd9c2a9ff4
--- /dev/null
+++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Message.java
@@ -0,0 +1,27 @@
+/*
+ * 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.hl7.model;
+
+import java.util.List;
+
+public interface HL7Message {
+
+ List getSegments();
+
+ List getSegments(String segmentType);
+
+}
diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Segment.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Segment.java
new file mode 100644
index 0000000000..de5aaa1d4b
--- /dev/null
+++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Segment.java
@@ -0,0 +1,27 @@
+/*
+ * 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.hl7.model;
+
+import java.util.List;
+
+public interface HL7Segment {
+
+ String getName();
+
+ List getFields();
+
+}
diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/Declaration.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/Declaration.java
new file mode 100644
index 0000000000..0903cc8d30
--- /dev/null
+++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/Declaration.java
@@ -0,0 +1,29 @@
+/*
+ * 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.hl7.query;
+
+import org.apache.nifi.hl7.model.HL7Message;
+
+public interface Declaration {
+
+ String getAlias();
+
+ boolean isRequired();
+
+ Object getDeclaredValue(HL7Message message);
+
+}
diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/HL7Query.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/HL7Query.java
new file mode 100644
index 0000000000..a036106481
--- /dev/null
+++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/HL7Query.java
@@ -0,0 +1,412 @@
+/*
+ * 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.hl7.query;
+
+import static org.apache.nifi.hl7.query.antlr.HL7QueryParser.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.antlr.runtime.ANTLRStringStream;
+import org.antlr.runtime.CharStream;
+import org.antlr.runtime.CommonTokenStream;
+import org.antlr.runtime.tree.Tree;
+import org.apache.nifi.hl7.model.HL7Message;
+import org.apache.nifi.hl7.query.evaluator.BooleanEvaluator;
+import org.apache.nifi.hl7.query.evaluator.Evaluator;
+import org.apache.nifi.hl7.query.evaluator.IntegerEvaluator;
+import org.apache.nifi.hl7.query.evaluator.comparison.EqualsEvaluator;
+import org.apache.nifi.hl7.query.evaluator.comparison.GreaterThanEvaluator;
+import org.apache.nifi.hl7.query.evaluator.comparison.GreaterThanOrEqualEvaluator;
+import org.apache.nifi.hl7.query.evaluator.comparison.IsNullEvaluator;
+import org.apache.nifi.hl7.query.evaluator.comparison.LessThanEvaluator;
+import org.apache.nifi.hl7.query.evaluator.comparison.LessThanOrEqualEvaluator;
+import org.apache.nifi.hl7.query.evaluator.comparison.NotEqualsEvaluator;
+import org.apache.nifi.hl7.query.evaluator.comparison.NotEvaluator;
+import org.apache.nifi.hl7.query.evaluator.comparison.NotNullEvaluator;
+import org.apache.nifi.hl7.query.evaluator.literal.IntegerLiteralEvaluator;
+import org.apache.nifi.hl7.query.evaluator.literal.StringLiteralEvaluator;
+import org.apache.nifi.hl7.query.evaluator.logic.AndEvaluator;
+import org.apache.nifi.hl7.query.evaluator.logic.OrEvaluator;
+import org.apache.nifi.hl7.query.evaluator.message.DeclaredReferenceEvaluator;
+import org.apache.nifi.hl7.query.evaluator.message.DotEvaluator;
+import org.apache.nifi.hl7.query.evaluator.message.MessageEvaluator;
+import org.apache.nifi.hl7.query.evaluator.message.SegmentEvaluator;
+import org.apache.nifi.hl7.query.exception.HL7QueryParsingException;
+import org.apache.nifi.hl7.query.result.MissedResult;
+import org.apache.nifi.hl7.query.result.StandardQueryResult;
+
+import org.apache.nifi.hl7.query.antlr.HL7QueryLexer;
+import org.apache.nifi.hl7.query.antlr.HL7QueryParser;
+
+
+public class HL7Query {
+ private final Tree tree;
+ private final String query;
+ private final Set declarations = new HashSet<>();
+
+ private final List selections;
+ private final BooleanEvaluator whereEvaluator;
+
+ private HL7Query(final Tree tree, final String query) {
+ this.tree = tree;
+ this.query = query;
+
+ List select = null;
+ BooleanEvaluator where = null;
+ for (int i=0; i < tree.getChildCount(); i++) {
+ final Tree child = tree.getChild(i);
+
+ switch (child.getType()) {
+ case DECLARE:
+ processDeclare(child);
+ break;
+ case SELECT:
+ select = processSelect(child);
+ break;
+ case WHERE:
+ where = processWhere(child);
+ break;
+ default:
+ throw new HL7QueryParsingException("Found unexpected clause at root level: " + tree.getText());
+ }
+ }
+
+ this.whereEvaluator = where;
+ this.selections = select;
+ }
+
+ private void processDeclare(final Tree declare) {
+ for (int i=0; i < declare.getChildCount(); i++) {
+ final Tree declarationTree = declare.getChild(i);
+
+ final String identifier = declarationTree.getChild(0).getText();
+ final Tree requiredOrOptionalTree = declarationTree.getChild(1);
+ final boolean required = requiredOrOptionalTree.getType() == REQUIRED;
+
+ final String segmentName = declarationTree.getChild(2).getText();
+
+ final Declaration declaration = new Declaration() {
+ @Override
+ public String getAlias() {
+ return identifier;
+ }
+
+ @Override
+ public boolean isRequired() {
+ return required;
+ }
+
+ @Override
+ public Object getDeclaredValue(final HL7Message message) {
+ if ( message == null ) {
+ return null;
+ }
+
+ return message.getSegments(segmentName);
+ }
+ };
+
+ declarations.add(declaration);
+ }
+ }
+
+ private List processSelect(final Tree select) {
+ final List selections = new ArrayList<>();
+
+ for (int i=0; i < select.getChildCount(); i++) {
+ final Tree selectable = select.getChild(i);
+
+ final String alias = getSelectedName(selectable);
+ final Evaluator> selectionEvaluator = buildReferenceEvaluator(selectable);
+ final Selection selection = new Selection(selectionEvaluator, alias);
+ selections.add(selection);
+ }
+
+ return selections;
+ }
+
+
+ private String getSelectedName(final Tree selectable) {
+ if ( selectable.getChildCount() == 0 ) {
+ return selectable.getText();
+ } else if (selectable.getType() == DOT ) {
+ return getSelectedName(selectable.getChild(0)) + "." + getSelectedName(selectable.getChild(1));
+ } else {
+ return selectable.getChild(selectable.getChildCount() - 1).getText();
+ }
+ }
+
+
+ private BooleanEvaluator processWhere(final Tree where) {
+ return buildBooleanEvaluator(where.getChild(0));
+ }
+
+
+ private Evaluator> buildReferenceEvaluator(final Tree tree) {
+ switch (tree.getType()) {
+ case MESSAGE:
+ return new MessageEvaluator();
+ case SEGMENT_NAME:
+ return new SegmentEvaluator(new StringLiteralEvaluator(tree.getText()));
+ case IDENTIFIER:
+ return new DeclaredReferenceEvaluator(new StringLiteralEvaluator(tree.getText()));
+ case DOT:
+ final Tree firstChild = tree.getChild(0);
+ final Tree secondChild = tree.getChild(1);
+ return new DotEvaluator(buildReferenceEvaluator(firstChild), buildIntegerEvaluator(secondChild));
+ case STRING_LITERAL:
+ return new StringLiteralEvaluator(tree.getText());
+ case NUMBER:
+ return new IntegerLiteralEvaluator(Integer.parseInt(tree.getText()));
+ default:
+ throw new HL7QueryParsingException("Failed to build evaluator for " + tree.getText());
+ }
+ }
+
+
+ private IntegerEvaluator buildIntegerEvaluator(final Tree tree) {
+ switch (tree.getType()) {
+ case NUMBER:
+ return new IntegerLiteralEvaluator(Integer.parseInt(tree.getText()));
+ default:
+ throw new HL7QueryParsingException("Failed to build Integer Evaluator for " + tree.getText());
+ }
+ }
+
+
+ private BooleanEvaluator buildBooleanEvaluator(final Tree tree) {
+ // TODO: add Date comparisons
+ // LT/GT/GE/GE should allow for dates based on Field's Type
+ // BETWEEN
+ // DATE('2015/01/01')
+ // DATE('2015/01/01 12:00:00')
+ // DATE('24 HOURS AGO')
+ // DATE('YESTERDAY')
+
+ switch (tree.getType()) {
+ case EQUALS:
+ return new EqualsEvaluator(buildReferenceEvaluator(tree.getChild(0)), buildReferenceEvaluator(tree.getChild(1)));
+ case NOT_EQUALS:
+ return new NotEqualsEvaluator(buildReferenceEvaluator(tree.getChild(0)), buildReferenceEvaluator(tree.getChild(1)));
+ case GT:
+ return new GreaterThanEvaluator(buildReferenceEvaluator(tree.getChild(0)), buildReferenceEvaluator(tree.getChild(1)));
+ case LT:
+ return new LessThanEvaluator(buildReferenceEvaluator(tree.getChild(0)), buildReferenceEvaluator(tree.getChild(1)));
+ case GE:
+ return new GreaterThanOrEqualEvaluator(buildReferenceEvaluator(tree.getChild(0)), buildReferenceEvaluator(tree.getChild(1)));
+ case LE:
+ return new LessThanOrEqualEvaluator(buildReferenceEvaluator(tree.getChild(0)), buildReferenceEvaluator(tree.getChild(1)));
+ case NOT:
+ return new NotEvaluator(buildBooleanEvaluator(tree.getChild(0)));
+ case AND:
+ return new AndEvaluator(buildBooleanEvaluator(tree.getChild(0)), buildBooleanEvaluator(tree.getChild(1)));
+ case OR:
+ return new OrEvaluator(buildBooleanEvaluator(tree.getChild(0)), buildBooleanEvaluator(tree.getChild(1)));
+ case IS_NULL:
+ return new IsNullEvaluator(buildReferenceEvaluator(tree.getChild(0)));
+ case NOT_NULL:
+ return new NotNullEvaluator(buildReferenceEvaluator(tree.getChild(0)));
+ default:
+ throw new HL7QueryParsingException("Cannot build boolean evaluator for '" + tree.getText() + "'");
+ }
+ }
+
+
+ Tree getTree() {
+ return tree;
+ }
+
+ public String getQuery() {
+ return query;
+ }
+
+ @Override
+ public String toString() {
+ return "HL7Query[" + query + "]";
+ }
+
+ public static HL7Query compile(final String query) {
+ try {
+ final CommonTokenStream lexerTokenStream = createTokenStream(query);
+ final HL7QueryParser parser = new HL7QueryParser(lexerTokenStream);
+ final Tree tree = (Tree) parser.query().getTree();
+
+ return new HL7Query(tree, query);
+ } catch (final HL7QueryParsingException e) {
+ throw e;
+ } catch (final Exception e) {
+ throw new HL7QueryParsingException(e);
+ }
+ }
+
+ private static CommonTokenStream createTokenStream(final String expression) throws HL7QueryParsingException {
+ final CharStream input = new ANTLRStringStream(expression);
+ final HL7QueryLexer lexer = new HL7QueryLexer(input);
+ return new CommonTokenStream(lexer);
+ }
+
+ public List> getReturnTypes() {
+ final List> returnTypes = new ArrayList<>();
+
+ for ( final Selection selection : selections ) {
+ returnTypes.add( selection.getEvaluator().getType() );
+ }
+
+ return returnTypes;
+ }
+
+ @SuppressWarnings("unchecked")
+ public QueryResult evaluate(final HL7Message message) {
+
+ int totalIterations = 1;
+ final LinkedHashMap> possibleValueMap = new LinkedHashMap<>();
+ for ( final Declaration declaration : declarations ) {
+ final Object value = declaration.getDeclaredValue(message);
+ if ( value == null && declaration.isRequired() ) {
+ return new MissedResult(selections);
+ }
+
+ final List