NIFI-506: Initial import of HL7 work
Project: http://git-wip-us.apache.org/repos/asf/incubator-nifi/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-nifi/commit/45416dc6 Tree: http://git-wip-us.apache.org/repos/asf/incubator-nifi/tree/45416dc6 Diff: http://git-wip-us.apache.org/repos/asf/incubator-nifi/diff/45416dc6 Branch: refs/heads/NIFI-271 Commit: 45416dc66bc212bacf5a8429e4ae2ae880c0672c Parents: e8fde85 Author: Mark Payne <marka...@hotmail.com> Authored: Thu Apr 9 17:54:33 2015 -0400 Committer: Mark Payne <marka...@hotmail.com> Committed: Thu Apr 9 17:54:33 2015 -0400 ---------------------------------------------------------------------- .../nifi-hl7-query-language/.gitignore | 3 + .../nifi-hl7-query-language/pom.xml | 115 ++++++ .../apache/nifi/hl7/query/antlr/HL7QueryLexer.g | 156 +++++++ .../nifi/hl7/query/antlr/HL7QueryParser.g | 91 ++++ .../org/apache/nifi/hl7/hapi/EmptyField.java | 37 ++ .../org/apache/nifi/hl7/hapi/HapiField.java | 83 ++++ .../org/apache/nifi/hl7/hapi/HapiMessage.java | 94 +++++ .../org/apache/nifi/hl7/hapi/HapiSegment.java | 69 ++++ .../apache/nifi/hl7/hapi/SingleValueField.java | 42 ++ .../java/org/apache/nifi/hl7/io/HL7Reader.java | 27 ++ .../hl7/io/exception/InvalidHL7Exception.java | 40 ++ .../org/apache/nifi/hl7/model/HL7Component.java | 24 ++ .../org/apache/nifi/hl7/model/HL7Field.java | 21 + .../org/apache/nifi/hl7/model/HL7Message.java | 27 ++ .../org/apache/nifi/hl7/model/HL7Segment.java | 27 ++ .../org/apache/nifi/hl7/query/Declaration.java | 29 ++ .../org/apache/nifi/hl7/query/HL7Query.java | 412 +++++++++++++++++++ .../org/apache/nifi/hl7/query/QueryResult.java | 29 ++ .../org/apache/nifi/hl7/query/ResultHit.java | 25 ++ .../org/apache/nifi/hl7/query/Selection.java | 37 ++ .../hl7/query/evaluator/BooleanEvaluator.java | 24 ++ .../nifi/hl7/query/evaluator/Evaluator.java | 27 ++ .../hl7/query/evaluator/IntegerEvaluator.java | 26 ++ .../hl7/query/evaluator/StringEvaluator.java | 25 ++ .../comparison/AbstractComparisonEvaluator.java | 106 +++++ .../comparison/AbstractNumericComparison.java | 67 +++ .../evaluator/comparison/EqualsEvaluator.java | 32 ++ .../comparison/GreaterThanEvaluator.java | 34 ++ .../comparison/GreaterThanOrEqualEvaluator.java | 34 ++ .../evaluator/comparison/IsNullEvaluator.java | 69 ++++ .../evaluator/comparison/LessThanEvaluator.java | 31 ++ .../comparison/LessThanOrEqualEvaluator.java | 31 ++ .../comparison/NotEqualsEvaluator.java | 32 ++ .../evaluator/comparison/NotEvaluator.java | 36 ++ .../evaluator/comparison/NotNullEvaluator.java | 65 +++ .../literal/IntegerLiteralEvaluator.java | 36 ++ .../literal/StringLiteralEvaluator.java | 35 ++ .../hl7/query/evaluator/logic/AndEvaluator.java | 43 ++ .../hl7/query/evaluator/logic/OrEvaluator.java | 43 ++ .../message/DeclaredReferenceEvaluator.java | 42 ++ .../query/evaluator/message/DotEvaluator.java | 88 ++++ .../query/evaluator/message/FieldEvaluator.java | 67 +++ .../evaluator/message/MessageEvaluator.java | 34 ++ .../evaluator/message/SegmentEvaluator.java | 51 +++ .../exception/HL7QueryParsingException.java | 37 ++ .../nifi/hl7/query/result/MissedResult.java | 56 +++ .../hl7/query/result/StandardQueryResult.java | 69 ++++ .../hl7/query/result/StandardResultHit.java | 41 ++ .../org/apache/nifi/hl7/query/TestHL7Query.java | 352 ++++++++++++++++ .../src/test/resources/hyperglycemia | 5 + .../src/test/resources/hypoglycemia | 5 + .../src/test/resources/metabolic-panel | 23 ++ .../resources/unsolicited-vaccine-update-long | 16 + .../resources/unsolicited-vaccine-update-short | 4 + .../src/test/resources/vaccine-query | 3 + .../src/test/resources/vaers-message-long | 60 +++ .../nifi-hl7-bundle/nifi-hl7-nar/pom.xml | 36 ++ .../nifi-hl7-processors/.gitignore | 1 + .../nifi-hl7-bundle/nifi-hl7-processors/pom.xml | 106 +++++ .../processors/hl7/ExtractHL7Attributes.java | 247 +++++++++++ .../apache/nifi/processors/hl7/RouteHL7.java | 217 ++++++++++ .../org.apache.nifi.processor.Processor | 16 + .../hl7/TestExtractHL7Attributes.java | 48 +++ .../src/test/resources/1.hl7 | 16 + .../src/test/resources/hypoglycemia.hl7 | 5 + nifi/nifi-nar-bundles/nifi-hl7-bundle/pom.xml | 33 ++ 66 files changed, 3862 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/.gitignore ---------------------------------------------------------------------- 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 0000000..e91d5c4 --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/.gitignore @@ -0,0 +1,3 @@ +/target/ +/target/ +/target/ http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/pom.xml ---------------------------------------------------------------------- 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 0000000..447a88b --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/pom.xml @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-commons</artifactId> + <version>0.1.0-incubating-SNAPSHOT</version> + </parent> + + <artifactId>nifi-hl7-query-language</artifactId> + <packaging>jar</packaging> + + <name>NiFi Health Level 7 (HL7) Query Language</name> + + <build> + <plugins> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>1.7</source> + <target>1.7</target> + </configuration> + </plugin> + <plugin> + <groupId>org.antlr</groupId> + <artifactId>antlr3-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>antlr</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.antlr</groupId> + <artifactId>antlr-runtime</artifactId> + <version>3.5.2</version> + </dependency> + + <!-- HAPI to parse v2 messages --> + <dependency> + <groupId>ca.uhn.hapi</groupId> + <artifactId>hapi-base</artifactId> + <version>2.2</version> + </dependency> + <dependency> + <groupId>ca.uhn.hapi</groupId> + <artifactId>hapi-structures-v21</artifactId> + <version>2.2</version> + </dependency> + <dependency> + <groupId>ca.uhn.hapi</groupId> + <artifactId>hapi-structures-v22</artifactId> + <version>2.2</version> + </dependency> + <dependency> + <groupId>ca.uhn.hapi</groupId> + <artifactId>hapi-structures-v23</artifactId> + <version>2.2</version> + </dependency> + <dependency> + <groupId>ca.uhn.hapi</groupId> + <artifactId>hapi-structures-v231</artifactId> + <version>2.2</version> + </dependency> + <dependency> + <groupId>ca.uhn.hapi</groupId> + <artifactId>hapi-structures-v24</artifactId> + <version>2.2</version> + </dependency> + <dependency> + <groupId>ca.uhn.hapi</groupId> + <artifactId>hapi-structures-v25</artifactId> + <version>2.2</version> + </dependency> + <dependency> + <groupId>ca.uhn.hapi</groupId> + <artifactId>hapi-structures-v251</artifactId> + <version>2.2</version> + </dependency> + <dependency> + <groupId>ca.uhn.hapi</groupId> + <artifactId>hapi-structures-v26</artifactId> + <version>2.2</version> + </dependency> + + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + </dependencies> +</project> http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/antlr3/org/apache/nifi/hl7/query/antlr/HL7QueryLexer.g ---------------------------------------------------------------------- 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 0000000..7fe3386 --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/antlr3/org/apache/nifi/hl7/query/antlr/HL7QueryLexer.g @@ -0,0 +1,156 @@ +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' | '.')* + ); http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/antlr3/org/apache/nifi/hl7/query/antlr/HL7QueryParser.g ---------------------------------------------------------------------- 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 0000000..4d8d13c --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/antlr3/org/apache/nifi/hl7/query/antlr/HL7QueryParser.g @@ -0,0 +1,91 @@ +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?); http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/EmptyField.java ---------------------------------------------------------------------- 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 0000000..be645e5 --- /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<HL7Component> getComponents() { + return Collections.emptyList(); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/HapiField.java ---------------------------------------------------------------------- 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 0000000..056b6b6 --- /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<HL7Component> components; + + public HapiField(final Type type) { + this.value = PipeParser.encode(type, EncodingCharacters.defaultInstance()); + + final List<HL7Component> 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<HL7Component> getComponents() { + return components; + } + + @Override + public String toString() { + return value; + } +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/HapiMessage.java ---------------------------------------------------------------------- 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 0000000..ddd28b2 --- /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<HL7Segment> allSegments; + private final Map<String, List<HL7Segment>> 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<HL7Segment> 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<HL7Segment> 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<HL7Segment> getSegments() { + return Collections.unmodifiableList(allSegments); + } + + @Override + public List<HL7Segment> getSegments(final String segmentType) { + final List<HL7Segment> segments = segmentMap.get(segmentType); + if ( segments == null ) { + return Collections.emptyList(); + } + + return Collections.unmodifiableList(segments); + } + + @Override + public String toString() { + return message.toString(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/HapiSegment.java ---------------------------------------------------------------------- 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 0000000..d50afdb --- /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<HL7Field> fields; + + public HapiSegment(final Segment segment) throws HL7Exception { + this.segment = segment; + + final List<HL7Field> 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<HL7Field> getFields() { + return fields; + } + + @Override + public String toString() { + return segment.toString(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/hapi/SingleValueField.java ---------------------------------------------------------------------- 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 0000000..ed99077 --- /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<HL7Component> getComponents() { + return Collections.emptyList(); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/io/HL7Reader.java ---------------------------------------------------------------------- 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 0000000..e7b31a4 --- /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; + +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/io/exception/InvalidHL7Exception.java ---------------------------------------------------------------------- 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 0000000..669f40c --- /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); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Component.java ---------------------------------------------------------------------- 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 0000000..cf35504 --- /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<HL7Component> getComponents(); +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Field.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Field.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Field.java new file mode 100644 index 0000000..4086e58 --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Field.java @@ -0,0 +1,21 @@ +/* + * 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; + + +public interface HL7Field extends HL7Component { +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Message.java ---------------------------------------------------------------------- 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 0000000..dd9c2a9 --- /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<HL7Segment> getSegments(); + + List<HL7Segment> getSegments(String segmentType); + +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/model/HL7Segment.java ---------------------------------------------------------------------- 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 0000000..de5aaa1 --- /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<HL7Field> getFields(); + +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/Declaration.java ---------------------------------------------------------------------- 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 0000000..0903cc8 --- /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); + +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/HL7Query.java ---------------------------------------------------------------------- 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 0000000..a036106 --- /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<Declaration> declarations = new HashSet<>(); + + private final List<Selection> selections; + private final BooleanEvaluator whereEvaluator; + + private HL7Query(final Tree tree, final String query) { + this.tree = tree; + this.query = query; + + List<Selection> 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<Selection> processSelect(final Tree select) { + final List<Selection> 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<Class<?>> getReturnTypes() { + final List<Class<?>> 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<String, List<Object>> 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<Object> possibleValues; + if ( value instanceof List ) { + possibleValues = (List<Object>) value; + } else if ( value instanceof Collection ) { + possibleValues = new ArrayList<Object>((Collection<Object>) value); + } else { + possibleValues = new ArrayList<>(1); + possibleValues.add(value); + } + + if ( possibleValues.isEmpty() ) { + return new MissedResult(selections); + } + + possibleValueMap.put(declaration.getAlias(), possibleValues); + totalIterations *= possibleValues.size(); + } + + final Set<Map<String, Object>> resultSet = new HashSet<>(); + for (int i=0; i < totalIterations; i++) { + final Map<String, Object> aliasValues = assignAliases(possibleValueMap, i); + + aliasValues.put(Evaluator.MESSAGE_KEY, message); + if (whereEvaluator == null || Boolean.TRUE.equals(whereEvaluator.evaluate(aliasValues))) { + final Map<String, Object> resultMap = new HashMap<>(); + + for ( final Selection selection : selections ) { + final Object value = selection.getEvaluator().evaluate(aliasValues); + resultMap.put(selection.getName(), value); + } + + resultSet.add(resultMap); + } + } + +// for ( final Declaration declaration : declarations ) { +// final Object value = declaration.getDeclaredValue(message); +// if ( value == null && declaration.isRequired() ) { +// return new MissedResult(selections); +// } +// objectMap.put(declaration.getAlias(), value); +// } +// +// if (whereEvaluator == null || Boolean.TRUE.equals(whereEvaluator.evaluate(objectMap))) { +// for ( final Selection selection : selections ) { +// final Object value = selection.getEvaluator().evaluate(objectMap); +// resultMap.put(selection.getName(), value); +// } +// } else { +// return new MissedResult(selections); +// } + + return new StandardQueryResult(selections, resultSet); + } + + + // assigns one of the possible values to each alias, based on which iteration this is. + // require LinkedHashMap just to be very clear and explicit that the order of the Map MUST be guaranteed + // between multiple invocations of this method. + // package protected for testing visibility +// static Map<String, Object> assignAliases(final LinkedHashMap<String, List<Object>> possibleValues, final int iteration) { +// final Map<String, Object> aliasMap = new HashMap<>(); +// +// int aliasIndex = possibleValues.size() - 1; +// for ( final Map.Entry<String, List<Object>> entry : possibleValues.entrySet() ) { +// final String alias = entry.getKey(); +// final List<Object> validValues = entry.getValue(); +// +// final int validValueIndex; +// if (aliasIndex > 0) { +// validValueIndex = iteration / aliasIndex; +// } else { +// validValueIndex = iteration; +// } +// +// final Object obj = validValues.get(validValueIndex % validValues.size()); +// aliasMap.put(alias, obj); +// +// aliasIndex--; +// } +// +// return aliasMap; +// } +// + + static Map<String, Object> assignAliases(final LinkedHashMap<String, List<Object>> possibleValues, final int iteration) { + final Map<String, Object> aliasMap = new HashMap<>(); + + int divisor = 1; + for ( final Map.Entry<String, List<Object>> entry : possibleValues.entrySet() ) { + final String alias = entry.getKey(); + final List<Object> validValues = entry.getValue(); + + final int idx = (iteration / divisor) % validValues.size(); + final Object obj = validValues.get(idx); + aliasMap.put(alias, obj); + + divisor *= validValues.size(); + } + + return aliasMap; + } + + public String toTreeString() { + final StringBuilder sb = new StringBuilder(); + toTreeString(tree, sb, 0); + return sb.toString(); + } + + private void toTreeString(final Tree tree, final StringBuilder sb, final int indentLevel) { + final String nodeName = tree.getText(); + for (int i=0; i < indentLevel; i++) { + sb.append(" "); + } + sb.append(nodeName); + sb.append("\n"); + + for (int i=0; i < tree.getChildCount(); i++) { + final Tree child = tree.getChild(i); + toTreeString(child, sb, indentLevel + 2); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/QueryResult.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/QueryResult.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/QueryResult.java new file mode 100644 index 0000000..b198bc7 --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/QueryResult.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 java.util.List; + +public interface QueryResult { + boolean isMatch(); + + List<String> getLabels(); + + int getHitCount(); + + ResultHit nextHit(); +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/ResultHit.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/ResultHit.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/ResultHit.java new file mode 100644 index 0000000..ee97e5d --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/ResultHit.java @@ -0,0 +1,25 @@ +/* + * 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 java.util.Map; + +public interface ResultHit { + Object getValue(String label); + + Map<String, Object> getSelectedValues(); +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/Selection.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/Selection.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/Selection.java new file mode 100644 index 0000000..36a181f --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/Selection.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.query; + +import org.apache.nifi.hl7.query.evaluator.Evaluator; + +public class Selection { + private final Evaluator<?> evaluator; + private final String name; + + public Selection(final Evaluator<?> evaluator, final String name) { + this.evaluator = evaluator; + this.name = name; + } + + public String getName() { + return name; + } + + public Evaluator<?> getEvaluator() { + return evaluator; + } +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/BooleanEvaluator.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/BooleanEvaluator.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/BooleanEvaluator.java new file mode 100644 index 0000000..fdd807e --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/BooleanEvaluator.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.query.evaluator; + +public abstract class BooleanEvaluator implements Evaluator<Boolean> { + + public Class<? extends Boolean> getType() { + return Boolean.class; + } +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/Evaluator.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/Evaluator.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/Evaluator.java new file mode 100644 index 0000000..d86c30e --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/Evaluator.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.query.evaluator; + +import java.util.Map; + +public interface Evaluator<T> { + public static final String MESSAGE_KEY = "message"; + + T evaluate(Map<String, Object> objectMap); + + Class<? extends T> getType(); +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/IntegerEvaluator.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/IntegerEvaluator.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/IntegerEvaluator.java new file mode 100644 index 0000000..6afa9ed --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/IntegerEvaluator.java @@ -0,0 +1,26 @@ +/* + * 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.evaluator; + + +public abstract class IntegerEvaluator implements Evaluator<Integer> { + + public Class<? extends Integer> getType() { + return Integer.class; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/StringEvaluator.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/StringEvaluator.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/StringEvaluator.java new file mode 100644 index 0000000..5f73649 --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/StringEvaluator.java @@ -0,0 +1,25 @@ +/* + * 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.evaluator; + +public abstract class StringEvaluator implements Evaluator<String> { + + public Class<? extends String> getType() { + return String.class; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/AbstractComparisonEvaluator.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/AbstractComparisonEvaluator.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/AbstractComparisonEvaluator.java new file mode 100644 index 0000000..a7fa1b7 --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/AbstractComparisonEvaluator.java @@ -0,0 +1,106 @@ +/* + * 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.evaluator.comparison; + +import java.util.Collection; +import java.util.Map; + +import org.apache.nifi.hl7.model.HL7Field; +import org.apache.nifi.hl7.query.evaluator.BooleanEvaluator; +import org.apache.nifi.hl7.query.evaluator.Evaluator; + +public abstract class AbstractComparisonEvaluator extends BooleanEvaluator { + private final Evaluator<?> lhs; + private final Evaluator<?> rhs; + + public AbstractComparisonEvaluator(final Evaluator<?> lhs, final Evaluator<?> rhs) { + this.lhs = lhs; + this.rhs = rhs; + } + + public final Boolean evaluate(final Map<String, Object> objectMap) { + final Object lhsValue = lhs.evaluate(objectMap); + if ( lhsValue == null ) { + return false; + } + + final Object rhsValue = rhs.evaluate(objectMap); + if ( rhsValue == null ) { + return false; + } + + return compareRaw(lhsValue, rhsValue); + } + + + private Boolean compareRaw(Object lhsValue, Object rhsValue) { + if ( lhsValue == null || rhsValue == null ) { + return false; + } + + if ( lhsValue instanceof HL7Field ) { + lhsValue = ((HL7Field) lhsValue).getValue(); + } + + if ( rhsValue instanceof HL7Field ) { + rhsValue = ((HL7Field) rhsValue).getValue(); + } + + if ( lhsValue == null || rhsValue == null ) { + return false; + } + + // both are collections, and compare(lhsValue, rhsValue) is false. + // this would be the case, for instance, if we compared field 1 of one segment to + // a field in another segment, and both fields had components. + if ( lhsValue instanceof Collection && rhsValue instanceof Collection ) { + return false; + } + + // if one side is a collection but the other is not, check if any element in that + // collection compares to the other element in a way that satisfies the condition. + // this would happen, for instance, if we check Segment1.Field5 = 'X' and field 5 repeats + // with a value "A~B~C~X~Y~Z"; in this case we do want to consider Field 5 = X as true. + if ( lhsValue instanceof Collection ) { + for ( final Object lhsObject : (Collection<?>) lhsValue ) { + if ( compareRaw(lhsObject, rhsValue) ) { + return true; + } + } + + return false; + } + + if ( rhsValue instanceof Collection ) { + for ( final Object rhsObject : (Collection<?>) rhsValue ) { + if ( compareRaw(rhsObject, lhsValue) ) { + return true; + } + } + + return false; + } + + if ( lhsValue != null && rhsValue != null && compare(lhsValue, rhsValue) ) { + return true; + } + + return false; + } + + protected abstract boolean compare(Object lhs, Object rhs); +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/AbstractNumericComparison.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/AbstractNumericComparison.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/AbstractNumericComparison.java new file mode 100644 index 0000000..2529c49 --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/AbstractNumericComparison.java @@ -0,0 +1,67 @@ +/* + * 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.evaluator.comparison; + +import java.util.regex.Pattern; + +import org.apache.nifi.hl7.query.evaluator.Evaluator; + +public abstract class AbstractNumericComparison extends AbstractComparisonEvaluator { + private static final Pattern NUMERIC_PATTERN = Pattern.compile("\\d+(\\.\\d+)?"); + + public AbstractNumericComparison(final Evaluator<?> lhs, final Evaluator<?> rhs) { + super(lhs, rhs); + } + + @Override + protected final boolean compare(final Object lhs, final Object rhs) { + final Double lhsDouble = toDouble(lhs); + if ( lhsDouble == null ) { + return false; + } + + final Double rhsDouble = toDouble(rhs); + if ( rhsDouble == null ) { + return false; + } + + return compareNumbers(lhsDouble, rhsDouble); + } + + private Double toDouble(final Object value) { + if ( value == null ) { + return null; + } + + if ( value instanceof Double ) { + return (Double) value; + } + if ( value instanceof Number ) { + return ((Number) value).doubleValue(); + } + + if ( value instanceof String ) { + if ( NUMERIC_PATTERN.matcher((String) value).matches() ) { + return Double.parseDouble((String) value); + } + } + + return null; + } + + protected abstract boolean compareNumbers(final Double lhs, final Double rhs); +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/EqualsEvaluator.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/EqualsEvaluator.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/EqualsEvaluator.java new file mode 100644 index 0000000..7ee2f87 --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/EqualsEvaluator.java @@ -0,0 +1,32 @@ +/* + * 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.evaluator.comparison; + +import org.apache.nifi.hl7.query.evaluator.Evaluator; + +public class EqualsEvaluator extends AbstractComparisonEvaluator { + + public EqualsEvaluator(final Evaluator<?> lhs, final Evaluator<?> rhs) { + super(lhs, rhs); + } + + @Override + protected boolean compare(final Object lhs, final Object rhs) { + return lhs != null && rhs != null && ((lhs == rhs) || (lhs.equals(rhs)) || lhs.toString().equals(rhs.toString())); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/GreaterThanEvaluator.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/GreaterThanEvaluator.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/GreaterThanEvaluator.java new file mode 100644 index 0000000..bf8596e --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/GreaterThanEvaluator.java @@ -0,0 +1,34 @@ +/* + * 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.evaluator.comparison; + +import org.apache.nifi.hl7.query.evaluator.Evaluator; + + +public class GreaterThanEvaluator extends AbstractNumericComparison { + + public GreaterThanEvaluator(final Evaluator<?> lhs, final Evaluator<?> rhs) { + super(lhs, rhs); + } + + @Override + protected boolean compareNumbers(final Double lhs, final Double rhs) { + return lhs > rhs; + } + + +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/GreaterThanOrEqualEvaluator.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/GreaterThanOrEqualEvaluator.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/GreaterThanOrEqualEvaluator.java new file mode 100644 index 0000000..69115a3 --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/GreaterThanOrEqualEvaluator.java @@ -0,0 +1,34 @@ +/* + * 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.evaluator.comparison; + +import org.apache.nifi.hl7.query.evaluator.Evaluator; + + +public class GreaterThanOrEqualEvaluator extends AbstractNumericComparison { + + public GreaterThanOrEqualEvaluator(final Evaluator<?> lhs, final Evaluator<?> rhs) { + super(lhs, rhs); + } + + @Override + protected boolean compareNumbers(final Double lhs, final Double rhs) { + return lhs >= rhs; + } + + +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/IsNullEvaluator.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/IsNullEvaluator.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/IsNullEvaluator.java new file mode 100644 index 0000000..69d481e --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/IsNullEvaluator.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.query.evaluator.comparison; + +import java.util.Collection; +import java.util.Map; + +import org.apache.nifi.hl7.model.HL7Component; +import org.apache.nifi.hl7.query.evaluator.BooleanEvaluator; +import org.apache.nifi.hl7.query.evaluator.Evaluator; + +public class IsNullEvaluator extends BooleanEvaluator { + private final Evaluator<?> subjectEvaluator; + + public IsNullEvaluator(final Evaluator<?> subjectEvaluator) { + this.subjectEvaluator = subjectEvaluator; + } + + @Override + public Boolean evaluate(final Map<String, Object> objectMap) { + Object subjectValue = subjectEvaluator.evaluate(objectMap); + if ( subjectValue == null ) { + return true; + } + + return isNull(subjectValue); + } + + private boolean isNull(Object subjectValue) { + if ( subjectValue == null ) { + return true; + } + + if ( subjectValue instanceof HL7Component ) { + subjectValue = ((HL7Component) subjectValue).getValue(); + } + + if ( subjectValue instanceof Collection ) { + final Collection<?> collection = (Collection<?>) subjectValue; + if ( collection.isEmpty() ) { + return true; + } + + for ( final Object obj : collection ) { + if ( !isNull(obj) ) { + return false; + } + } + + return true; + } + + return subjectValue == null; + } +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/LessThanEvaluator.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/LessThanEvaluator.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/LessThanEvaluator.java new file mode 100644 index 0000000..891d5e4 --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/LessThanEvaluator.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.hl7.query.evaluator.comparison; + +import org.apache.nifi.hl7.query.evaluator.Evaluator; + +public class LessThanEvaluator extends AbstractNumericComparison { + public LessThanEvaluator(final Evaluator<?> lhs, final Evaluator<?> rhs) { + super(lhs, rhs); + } + + @Override + protected boolean compareNumbers(final Double lhs, final Double rhs) { + return lhs < rhs; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/45416dc6/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/LessThanOrEqualEvaluator.java ---------------------------------------------------------------------- diff --git a/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/LessThanOrEqualEvaluator.java b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/LessThanOrEqualEvaluator.java new file mode 100644 index 0000000..c6fb097 --- /dev/null +++ b/nifi/nifi-commons/nifi-hl7-query-language/src/main/java/org/apache/nifi/hl7/query/evaluator/comparison/LessThanOrEqualEvaluator.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.hl7.query.evaluator.comparison; + +import org.apache.nifi.hl7.query.evaluator.Evaluator; + +public class LessThanOrEqualEvaluator extends AbstractNumericComparison { + public LessThanOrEqualEvaluator(final Evaluator<?> lhs, final Evaluator<?> rhs) { + super(lhs, rhs); + } + + @Override + protected boolean compareNumbers(final Double lhs, final Double rhs) { + return lhs <= rhs; + } + +}