Skip to content

Commit

Permalink
krasserm#54: added HL7DSL support on plain HAPI classes within the ip…
Browse files Browse the repository at this point in the history
…f-modules-hl7 module

use PreParser in MllpDispatcher to identify message metadata
  • Loading branch information
ohr committed Nov 7, 2014
1 parent c8dca84 commit 9ced0f2
Show file tree
Hide file tree
Showing 33 changed files with 2,419 additions and 38 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
moduleName=Hl7Extension
moduleVersion=2.5
moduleFactory=org.openehealth.ipf.commons.core.config.ExtensionModuleFactory
extensionClasses=org.openehealth.ipf.modules.hl7.extend.Hl7ExtensionModule
extensionClasses=org.openehealth.ipf.modules.hl7.extend.Hl7ExtensionModule,org.openehealth.ipf.modules.hl7.extend.Hl7Dsl2ExtensionModule
staticExtensionClasses=org.openehealth.ipf.modules.hl7.extend.Hl7StaticExtensionModule
5 changes: 5 additions & 0 deletions modules/hl7/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@
<artifactId>hapi-structures-v23</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi</groupId>
<artifactId>hapi-structures-v231</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi</groupId>
<artifactId>hapi-structures-v24</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Copyright 2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openehealth.ipf.modules.hl7.dsl

import ca.uhn.hl7v2.HL7Exception
import ca.uhn.hl7v2.model.AbstractGroup
import ca.uhn.hl7v2.model.Group;
import ca.uhn.hl7v2.model.Message
import ca.uhn.hl7v2.util.DeepCopy;
import ca.uhn.hl7v2.util.Terser

/**
* @author Martin Krasser
*/
class MessageCopy {

Message src
Message dst

Terser srcTerser
Terser dstTerser

MessageCopy(Message src, Message dst) {
this.src = src
this.dst = dst
this.srcTerser = new Terser(src)
this.dstTerser = new Terser(dst)
}

void execute() {
doExecute('/', src)
}

private void doExecute(String path, Group grp) {
if (grp instanceof AbstractGroup){
addNonStandardIfExists(path, grp)
}
grp.names.each { name ->
grp.getAll(name).eachWithIndex { structure, index ->
String spec = spec(path, name, index)
if (structure instanceof Group) {
doExecute(spec, structure) // recursion
} else {
copySegment(spec)
}
}
}
}

private void addNonStandardIfExists(String path, AbstractGroup grp){
if (grp.nonStandardNames.size() > 0){
grp.nonStandardNames.each { nonStandardName ->
doAddNonStandard(nonStandardName, '/', path, dst)
}
}
}

private void doAddNonStandard(String segmentName, String rootPath, String groupPath, Group grp) {
if (rootPath == groupPath){
grp.addNonstandardSegment(segmentName)
}
grp.names.each { name ->
grp.get(name)
grp.getAll(name).eachWithIndex { structure, index ->
String spec = spec(rootPath, name, index)
if (structure instanceof Group){
if (spec == groupPath) {
structure.addNonstandardSegment(segmentName)
} else {
doAddNonStandard(segmentName, spec, groupPath, structure)
}
}
}
}
dstTerser = new Terser(dst)
}

private copySegment(String spec) {
try {
DeepCopy.copy(
srcTerser.getSegment(spec),
dstTerser.getSegment(spec))
} catch (HL7Exception e) {
throw new RuntimeException("Either source or destination segment does not exist", e)
}
}

private static String spec(def path, def structureName, def idx) {
path + (path == '/' ? '' : '/') + structureName + '(' + idx + ')'
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openehealth.ipf.modules.hl7.dsl

import ca.uhn.hl7v2.model.Message;

/**
* @author Martin Krasser
*/
public class Messages {

static void copyMessage(Message src, Message dst) {
new MessageCopy(src, dst).execute()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright 2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openehealth.ipf.modules.hl7.dsl

import ca.uhn.hl7v2.HL7Exception
import ca.uhn.hl7v2.Location
import ca.uhn.hl7v2.model.AbstractType
import ca.uhn.hl7v2.model.DataTypeException
import ca.uhn.hl7v2.model.Message
import ca.uhn.hl7v2.model.MessageVisitor

/**
*
* NullAdapter helps to handle non-existing repeatable elements transparently
* without throwing an Exception.
*
* @author Christian Ohr
*
*/
class Null extends AbstractType {

Null(Message message) {
super(message)
}

def getAt(int idx) {
this
}

String getValue() {
null
}

String getValueOr(String defaultValue) {
defaultValue
}

public String toString() {
null
}

void setValue(String value) throws DataTypeException {
throw new DataTypeException("Cannot assign a value Null")
}

@Override
boolean accept(MessageVisitor visitor, Location currentLocation) throws HL7Exception {
return false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Copyright 2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openehealth.ipf.modules.hl7.dsl

import ca.uhn.hl7v2.model.Group
import ca.uhn.hl7v2.model.Segment
import ca.uhn.hl7v2.model.Structure
import ca.uhn.hl7v2.model.Visitable
import org.codehaus.groovy.runtime.InvokerHelper

import ca.uhn.hl7v2.model.DataTypeException

/**
* Special closure that helps in the cases of HL7 DSL to allow for a default
* repetition (0) and (sub-)component [1]. This is necessary for addressing
* respective fields that have different structures in different HL7 versions.
*
* @author Christian Ohr
*/
class Repeatable extends Closure implements Iterable<Visitable> {

Structure structure
def elements
def index

Repeatable(owner, elements, structure, index) {
super(owner)
this.elements = elements
this.structure = structure
this.index = index
}

@Override
Iterator<Visitable> iterator() {
return elements.iterator()
}

// Defining the value property with getValue() doesn't work
public Object getProperty(String property) {
InvokerHelper.getProperty(elementAt(0), property)
}

// Forward other method calls to the first object
def methodMissing(String name, args) {
InvokerHelper.invokeMethod(elementAt(0), name, args)
}

// Forward index access to the first object
def getAt(int index) {
elementAt(0)[index]
}

// Forward property access to the first object
def propertyMissing(String name) {
InvokerHelper.getProperty(elementAt(0), name)
}

// Forward property access to the first object
void from(Object value) {
elementAt(0).from(value)
}

protected Object doCall(Object argument) {
if (argument != null) {
return elementAt((int)argument)
} else {
return elements
}
}

def elementAt(int argument) {
def element
if (elements.size() <= argument) {
element = structure.nrp(index)
} else {
element = elements[argument]
}
element
}

int size() {
elements.size()
}

boolean isEmpty() {
boolean result = true;
for (int index = 0; index < elements.size(); index++) {
def element = elements[index];
if (element != null && !element.isEmpty()) {
result = false;
break;
}
}
return result;
}

String getPath() {
elementAt(index).path
}

}
Loading

0 comments on commit 9ced0f2

Please sign in to comment.