[
https://issues.apache.org/jira/browse/NIFI-3147?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15899540#comment-15899540
]
ASF GitHub Bot commented on NIFI-3147:
--------------------------------------
Github user jfrazee commented on a diff in the pull request:
https://github.com/apache/nifi/pull/1312#discussion_r104681755
--- Diff:
nifi-nar-bundles/nifi-ccda-bundle/nifi-ccda-processors/src/main/java/org/apache/nifi/processors/ccda/ExtractCCDAAttributes.java
---
@@ -0,0 +1,329 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.processors.ccda;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.jexl3.JexlBuilder;
+import org.apache.commons.jexl3.JexlContext;
+import org.apache.commons.jexl3.JexlEngine;
+import org.apache.commons.jexl3.JexlExpression;
+import org.apache.commons.jexl3.MapContext;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.annotation.behavior.InputRequirement;
+import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
+import org.apache.nifi.annotation.behavior.SideEffectFree;
+import org.apache.nifi.annotation.behavior.SupportsBatching;
+import org.apache.nifi.annotation.documentation.CapabilityDescription;
+import org.apache.nifi.annotation.documentation.Tags;
+import org.apache.nifi.annotation.lifecycle.OnScheduled;
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.flowfile.FlowFile;
+import org.apache.nifi.processor.AbstractProcessor;
+import org.apache.nifi.processor.ProcessContext;
+import org.apache.nifi.processor.ProcessSession;
+import org.apache.nifi.processor.ProcessorInitializationContext;
+import org.apache.nifi.processor.Relationship;
+import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.processor.util.StandardValidators;
+import org.apache.nifi.util.StopWatch;
+import org.eclipse.emf.common.util.Diagnostic;
+import org.openhealthtools.mdht.uml.cda.CDAPackage;
+import org.openhealthtools.mdht.uml.cda.ClinicalDocument;
+import org.openhealthtools.mdht.uml.cda.ccd.CCDPackage;
+import org.openhealthtools.mdht.uml.cda.consol.ConsolPackage;
+import org.openhealthtools.mdht.uml.cda.hitsp.HITSPPackage;
+import org.openhealthtools.mdht.uml.cda.ihe.IHEPackage;
+import org.openhealthtools.mdht.uml.cda.util.CDAUtil;
+import org.openhealthtools.mdht.uml.cda.util.CDAUtil.ValidationHandler;
+
+@SideEffectFree
+@SupportsBatching
+@InputRequirement(Requirement.INPUT_REQUIRED)
+@Tags({"CCDA", "healthcare", "extract", "attributes"})
+@CapabilityDescription("Extracts information from an Consolidated CDA
formatted FlowFile and provides individual attributes "
+ + "as FlowFile attributes. The attributes are named as <Parent>
<dot> <Key>. "
+ + "If the Parent is repeating, the naming will be <Parent>
<underscore> <Parent Index> <dot> <Key>. "
+ + "For example, section.act_07.observation.name=Essential
hypertension")
+public class ExtractCCDAAttributes extends AbstractProcessor {
+
+ private static final char FIELD_SEPARATOR = '@';
+ private static final char KEY_VALUE_SEPARATOR = '#';
+
+ private Map<String, Map<String, String>> processMap = new
LinkedHashMap<String, Map<String, String>>(); // stores mapping data for Parser
+ private JexlEngine jexl = null; // JEXL Engine to execute code for
mapping
+ private JexlContext jexlCtx = null; // JEXL Context to hold element
being processed
+
+ private List<PropertyDescriptor> properties;
+ private Set<Relationship> relationships;
+
+ /**
+ * SKIP_VALIDATION - Indicates whether to validate the CDA document
after loading.
+ * if true and the document is not valid, then ProcessException will
be thrown
+ */
+ public static final PropertyDescriptor SKIP_VALIDATION = new
PropertyDescriptor.Builder().name("skip-validation")
+ .displayName("Skip Validation").description("Whether or not to
validate CDA message values").required(true)
+ .allowableValues("true",
"false").defaultValue("true").addValidator(StandardValidators.BOOLEAN_VALIDATOR)
+ .build();
+
+ /**
+ * REL_SUCCESS - Value to be returned in case the processor succeeds
+ */
+ public static final Relationship REL_SUCCESS = new
Relationship.Builder()
+ .name("success")
+ .description("A FlowFile is routed to this relationship if it
is properly parsed as CDA and its content stored in FlowFile")
+ .build();
+
+ /**
+ * REL_FAILURE - Value to be returned in case the processor fails
+ */
+ public static final Relationship REL_FAILURE = new
Relationship.Builder()
+ .name("failure")
+ .description("A FlowFile is routed to this relationship if it
cannot be parse CDA and store content to FlowFile.")
+ .build();
+
+ @Override
+ protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
+ return properties;
+ }
+
+ @Override
+ public Set<Relationship> getRelationships() {
+ return relationships;
+ }
+
+ @Override
+ protected void init(final ProcessorInitializationContext context) {
+
+ relationships = new HashSet<>();
+ relationships.add(REL_SUCCESS);
+ relationships.add(REL_FAILURE);
+
+ properties = new ArrayList<>();
+ properties.add(SKIP_VALIDATION);
+ }
+
+ @OnScheduled
+ public void onScheduled(final ProcessContext context) throws
IOException {
+ getLogger().debug("Loading packages");
+ final StopWatch stopWatch = new StopWatch(true);
+
+ // Load required MDHT packages
+ System.setProperty(
"org.eclipse.emf.ecore.EPackage.Registry.INSTANCE",
+ "org.eclipse.emf.ecore.impl.EPackageRegistryImpl" );
+ CDAPackage.eINSTANCE.eClass();
+ HITSPPackage.eINSTANCE.eClass();
+ CCDPackage.eINSTANCE.eClass();
+ ConsolPackage.eINSTANCE.eClass();
+ IHEPackage.eINSTANCE.eClass();
+ stopWatch.stop();
+ getLogger().debug("Loaded packages in {}", new Object[]
{stopWatch.getDuration(TimeUnit.MILLISECONDS)});
+
+ // Initialize JEXL
+ jexl = new
JexlBuilder().cache(1024).debug(false).silent(true).strict(false).create();
+ jexlCtx = new MapContext();
+
+ getLogger().debug("Loading mappings");
+ loadMappings(); // Load CDA mappings for parser
+
+ }
+
+ @Override
+ public void onTrigger(final ProcessContext context, final
ProcessSession session) {
+ Map<String, String> attributes = new TreeMap<String, String>(); //
stores CDA attributes
+ getLogger().info("Processing CCDA");
+
+ FlowFile flowFile = session.get();
+ if ( flowFile == null ) {
+ return;
+ }
+
+ if(processMap.isEmpty()) {
+ getLogger().error("Process Mapping is not loaded");
+ session.transfer(flowFile, REL_FAILURE);
+ return;
+ }
+
+ final Boolean skipValidation =
context.getProperty(SKIP_VALIDATION).asBoolean();
+
+ final StopWatch stopWatch = new StopWatch(true);
+
+ ClinicalDocument cd = loadDocument(session.read(flowFile),
skipValidation); // Load and optionally validate CDA document
+
+ getLogger().debug("Loaded document for {} in {}", new Object[]
{flowFile, stopWatch.getElapsed(TimeUnit.MILLISECONDS)});
+
+ getLogger().debug("Processing elements");
+ processElement(null, cd, attributes); // Process CDA element using
mapping data
+
+ flowFile = session.putAllAttributes(flowFile, attributes);
+
+ stopWatch.stop();
+ getLogger().info("Successfully processed {} in {}", new Object[]
{flowFile, stopWatch.getDuration(TimeUnit.MILLISECONDS)});
+ if(getLogger().isDebugEnabled()){
+ for (Entry<String, String> entry : attributes.entrySet()) {
+ getLogger().debug("Attribute: {}={}", new Object[]
{entry.getKey(), entry.getValue()});
+ }
+ }
+
+ session.transfer(flowFile, REL_SUCCESS);
+
+ }
+
+ /**
+ * Process elements children based on the parser mapping.
+ * Any String values are added to attributes
+ * For List, the processList method is called to iterate and process
+ * For an Object this method is called recursively
+ * While adding to the attributes the key is prefixed by parent
+ * @param parent Parent key for this element, used as a prefix for
attribute key
+ * @param element Element to be processed
--- End diff --
After the most recent changes looks like the javadoc is out of date because
the attributes map isn't mentioned.
> Build processor to parse CCDA into attributes and JSON
> ------------------------------------------------------
>
> Key: NIFI-3147
> URL: https://issues.apache.org/jira/browse/NIFI-3147
> Project: Apache NiFi
> Issue Type: New Feature
> Components: Extensions
> Reporter: Kedar Chitale
> Assignee: Joseph Witt
> Labels: attributes, ccda, healthcare, parser
> Fix For: 1.2.0
>
> Original Estimate: 336h
> Remaining Estimate: 336h
>
> Accept a CCDA document, Parse the document to create individual attributes
> for example code.codeSystemName=LOINC
--
This message was sent by Atlassian JIRA
(v6.3.15#6346)