[ 
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)

Reply via email to