Initial Commit

This commit is contained in:
Travis Burtrum 2016-06-23 11:11:03 -04:00
commit b7c84d0f95
12 changed files with 1237 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.idea/
*.iml
*/target/
target/

118
pom.xml Normal file
View File

@ -0,0 +1,118 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ The contents of this file are subject to the Mozilla Public License Version 1.1
~ (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.mozilla.org/MPL/
~ Software distributed under the License is distributed on an "AS IS" basis,
~ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
~ specific language governing rights and limitations under the License.
~
~ Copyright (c) 2016 Travis Burtrum.
~
~ Alternatively, the contents of this file may be used under the terms of the
~ GNU General Public License (the "GPL"), in which case the provisions of the GPL are
~ applicable instead of those above. If you wish to allow use of your version of this
~ file only under the terms of the GPL and not to allow others to use your version
~ of this file under the MPL, indicate your decision by deleting the provisions above
~ and replace them with the notice and other provisions required by the GPL License.
~ If you do not delete the provisions above, a recipient may use your version of
~ this file under either the MPL or the GPL.
-->
<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/maven-v4_0_0.xsd">
<parent>
<groupId>org.sonatype.oss</groupId>
<artifactId>oss-parent</artifactId>
<version>9</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.moparisthebest.hl7</groupId>
<artifactId>SimpleHL7</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>${project.artifactId}</name>
<description>
This project makes creating, parsing, sending and recieving HL7 messages simple.
</description>
<url>https://github.com/moparisthebest/SimpleHL7</url>
<organization>
<name>moparisthebest.com</name>
<url>https://www.moparisthebest.com</url>
</organization>
<developers>
<developer>
<id>moparisthebest</id>
<name>Travis Burtrum</name>
<email>admin@moparisthebest.com</email>
<url>https://www.moparisthebest.com/</url>
</developer>
</developers>
<scm>
<connection>scm:git:https://github.com/moparisthebest/SimpleHL7.git</connection>
<developerConnection>scm:git:https://github.com/moparisthebest/SimpleHL7.git</developerConnection>
<url>https://github.com/moparisthebest/SimpleHL7</url>
</scm>
<licenses>
<license>
<name>Mozilla Public License Version 1.1</name>
<url>https://www.mozilla.org/en-US/MPL/1.1/</url>
</license>
<license>
<name>GNU General Public License, Version 3</name>
<url>https://www.gnu.org/licenses/gpl-3.0.html</url>
</license>
</licenses>
<properties>
<maven.test.skip>true</maven.test.skip>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<pushChanges>false</pushChanges>
<localCheckout>true</localCheckout>
</properties>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<debug>true</debug>
</configuration>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.2</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
</configuration>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.7</version>
<configuration>
<additionalparam>-Xdoclint:none</additionalparam>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<profiles>
<profile>
<id>run-tests</id>
<activation>
<property>
<name>maven.test.skip</name>
<value>false</value>
</property>
</activation>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,70 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (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.mozilla.org/MPL/
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
* specific language governing rights and limitations under the License.
*
* Copyright (c) 2016 Travis Burtrum.
*
* Alternatively, the contents of this file may be used under the terms of the
* GNU General Public License (the "GPL"), in which case the provisions of the GPL are
* applicable instead of those above. If you wish to allow use of your version of this
* file only under the terms of the GPL and not to allow others to use your version
* of this file under the MPL, indicate your decision by deleting the provisions above
* and replace them with the notice and other provisions required by the GPL License.
* If you do not delete the provisions above, a recipient may use your version of
* this file under either the MPL or the GPL.
*/
package com.moparisthebest.hl7;
public class Component extends SubComponentContainer<SubComponent> {
Component() {
super();
}
Component(final String s) {
super(s);
}
Component(final String s, final Encoding enc) {
super(s, enc, enc.subComponentDelimiter);
}
@Override
SubComponent newSubComponent() {
return new SubComponentImpl();
}
@Override
SubComponent newSubComponent(final String s) {
return new SubComponentImpl(s);
}
@Override
SubComponent newSubComponent(final String s, final Encoding enc) {
return new SubComponentImpl(s, enc);
}
public void encode(final StringBuilder sb, final Encoding enc) {
super.encode(sb, enc, enc.subComponentDelimiter, enc.componentDelimiter);
}
public SubComponent subComponent(final int index) {
return super.subComponent1Based(index);
}
// shorter aliases
public SubComponent sc(final int index) {
return this.subComponent(index);
}
@Override
public String toString() {
return super.toString("SubComponent");
}
}

View File

@ -0,0 +1,178 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (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.mozilla.org/MPL/
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
* specific language governing rights and limitations under the License.
*
* Copyright (c) 2016 Travis Burtrum.
*
* Alternatively, the contents of this file may be used under the terms of the
* GNU General Public License (the "GPL"), in which case the provisions of the GPL are
* applicable instead of those above. If you wish to allow use of your version of this
* file only under the terms of the GPL and not to allow others to use your version
* of this file under the MPL, indicate your decision by deleting the provisions above
* and replace them with the notice and other provisions required by the GPL License.
* If you do not delete the provisions above, a recipient may use your version of
* this file under either the MPL or the GPL.
*/
package com.moparisthebest.hl7;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class Encoding extends Field {
public final char segmentDelimiter, repetitionDelimiter, fieldDelimiter, componentDelimiter, subComponentDelimiter, escapeCharacter, verticalTab, fileSeperator;
public final String repetitionEscape, fieldEscape, componentEscape, subComponentEscape, escapeEscape;
private final String repetitionDelimiterString, fieldDelimiterString, componentDelimiterString, subComponentDelimiterString, escapeCharacterString, value;
public final MSH1 msh1;
// '\r', '~', '|', '^', '&', '\\'
public Encoding(final char segmentDelimiter, final char repetitionDelimiter, final char fieldDelimiter, final char componentDelimiter, final char subComponentDelimiter, final char escapeCharacter) {
this(segmentDelimiter, repetitionDelimiter, fieldDelimiter, componentDelimiter, subComponentDelimiter, escapeCharacter, (char) 11, (char) 28);
}
public Encoding(final char segmentDelimiter, final char repetitionDelimiter, final char fieldDelimiter, final char componentDelimiter, final char subComponentDelimiter, final char escapeCharacter, final char verticalTab, final char fileSeperator) {
this.segmentDelimiter = segmentDelimiter;
this.repetitionDelimiter = repetitionDelimiter;
this.fieldDelimiter = fieldDelimiter;
this.componentDelimiter = componentDelimiter;
this.subComponentDelimiter = subComponentDelimiter;
this.escapeCharacter = escapeCharacter;
this.verticalTab = verticalTab;
this.fileSeperator = fileSeperator;
this.repetitionEscape = escapeCharacter + "R" + escapeCharacter;
this.fieldEscape = escapeCharacter + "F" + escapeCharacter;
this.componentEscape = escapeCharacter + "S" + escapeCharacter;
this.subComponentEscape = escapeCharacter + "T" + escapeCharacter;
this.escapeEscape = escapeCharacter + "E" + escapeCharacter;
this.repetitionDelimiterString = "" + repetitionDelimiter;
this.fieldDelimiterString = "" + fieldDelimiter;
this.componentDelimiterString = "" + componentDelimiter;
this.subComponentDelimiterString = "" + subComponentDelimiter;
this.escapeCharacterString = "" + escapeCharacter;
this.value = componentDelimiterString + repetitionDelimiter + escapeCharacter + subComponentDelimiter;
this.msh1 = new MSH1(this.fieldDelimiterString);
}
public String decode(final String s) {
return s.replace(repetitionEscape, repetitionDelimiterString)
.replace(fieldEscape, fieldDelimiterString)
.replace(componentEscape, componentDelimiterString)
.replace(subComponentEscape, subComponentDelimiterString)
.replace(escapeEscape, escapeCharacterString);
}
public String encode(final String s) {
return s.replace(escapeCharacterString, escapeEscape)
.replace(repetitionDelimiterString, repetitionEscape)
.replace(fieldDelimiterString, fieldEscape)
.replace(componentDelimiterString, componentEscape)
.replace(subComponentDelimiterString, subComponentEscape);
}
public Collection<String> splitSegment(final String s) {
return split(s, segmentDelimiter);
}
public Collection<String> splitRepetition(final String s) {
return split(s, repetitionDelimiter);
}
public Collection<String> splitField(final String s) {
return split(s, fieldDelimiter);
}
public Collection<String> splitComponent(final String s) {
return split(s, componentDelimiter);
}
public Collection<String> splitSubComponent(final String s) {
return split(s, subComponentDelimiter);
}
public Collection<String> split(final String s, final char ch) {
int off = 0;
int next = 0;
final List<String> list = new ArrayList<>();
while ((next = s.indexOf(ch, off)) != -1) {
list.add(s.substring(off, next));
off = next + 1;
}
// Add remaining segment
list.add(s.substring(off, s.length()));
return list;
}
@Override
public void encode(final StringBuilder sb, final Encoding enc) {
sb.append(this.value);
sb.append(enc.fieldDelimiter);
}
@Override
public String value() {
return value;
}
@Override
public SubComponent value(final String value) {
// do nothing
return this;
}
@Override
public boolean equals(final String s) {
return value.equals(s);
}
@Override
public String toString() {
return value;
}
static class MSH1 extends Field {
private final String value;
private MSH1(final String fieldDelimiter) {
this.value = fieldDelimiter;
}
@Override
public void encode(final StringBuilder sb, final Encoding enc) {
// do nothing
}
@Override
public String value() {
return value;
}
@Override
public SubComponent value(final String value) {
// do nothing
return this;
}
@Override
public boolean equals(final String s) {
return value.equals(s);
}
@Override
public String toString() {
return value;
}
}
}

View File

@ -0,0 +1,118 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (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.mozilla.org/MPL/
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
* specific language governing rights and limitations under the License.
*
* Copyright (c) 2016 Travis Burtrum.
*
* Alternatively, the contents of this file may be used under the terms of the
* GNU General Public License (the "GPL"), in which case the provisions of the GPL are
* applicable instead of those above. If you wish to allow use of your version of this
* file only under the terms of the GPL and not to allow others to use your version
* of this file under the MPL, indicate your decision by deleting the provisions above
* and replace them with the notice and other provisions required by the GPL License.
* If you do not delete the provisions above, a recipient may use your version of
* this file under either the MPL or the GPL.
*/
package com.moparisthebest.hl7;
public class Field extends SubComponentContainer<Repetition> {
Field() {
super();
}
Field(final String s) {
super(s);
}
Field(final String s, final Encoding enc) {
super(s, enc, enc.repetitionDelimiter);
}
@Override
Repetition newSubComponent() {
return new Repetition();
}
@Override
Repetition newSubComponent(final String s) {
return new Repetition(s);
}
@Override
Repetition newSubComponent(final String s, final Encoding enc) {
return new Repetition(s, enc);
}
public void encode(final StringBuilder sb, final Encoding enc) {
super.encode(sb, enc, enc.repetitionDelimiter, enc.fieldDelimiter);
}
public RepetitionCounter repetitionCounter() {
return new RepetitionCounter(this, 1);
}
public RepetitionCounter repetitionCounter(final int startIndex) {
return new RepetitionCounter(this, startIndex);
}
public Repetition repetition(final int index) {
return super.subComponent1Based(index);
}
public Component component(final int repetitionIndex, final int componentIndex) {
return this.repetition(repetitionIndex).component(componentIndex);
}
public Component component(final int index) {
return this.repetition(1).component(index);
}
public SubComponent subComponent(final int repetitionIndex, final int componentIndex, final int subComponentIndex) {
return this.repetition(repetitionIndex).component(componentIndex).subComponent(subComponentIndex);
}
public SubComponent subComponent(final int componentIndex, final int subComponentIndex) {
return this.component(componentIndex).subComponent(subComponentIndex);
}
// shorter aliases
public RepetitionCounter rc() {
return this.repetitionCounter();
}
public RepetitionCounter rc(final int startIndex) {
return this.repetitionCounter(startIndex);
}
public Repetition r(final int repetitionIndex) {
return this.repetition(repetitionIndex);
}
public Component c(final int repetitionIndex, final int componentIndex) {
return this.component(repetitionIndex, componentIndex);
}
public Component c(final int componentIndex) {
return this.component(componentIndex);
}
public SubComponent sc(final int repetitionIndex, final int componentIndex, final int subComponentIndex) {
return this.subComponent(repetitionIndex, componentIndex, subComponentIndex);
}
public SubComponent sc(final int componentIndex, final int subComponentIndex) {
return this.subComponent(componentIndex, subComponentIndex);
}
@Override
public String toString() {
return super.toString("Repetition");
}
}

View File

@ -0,0 +1,106 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (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.mozilla.org/MPL/
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
* specific language governing rights and limitations under the License.
*
* Copyright (c) 2016 Travis Burtrum.
*
* Alternatively, the contents of this file may be used under the terms of the
* GNU General Public License (the "GPL"), in which case the provisions of the GPL are
* applicable instead of those above. If you wish to allow use of your version of this
* file only under the terms of the GPL and not to allow others to use your version
* of this file under the MPL, indicate your decision by deleting the provisions above
* and replace them with the notice and other provisions required by the GPL License.
* If you do not delete the provisions above, a recipient may use your version of
* this file under either the MPL or the GPL.
*/
package com.moparisthebest.hl7;
public class Line extends SubComponentContainer<Field> {
public Line(final String s) {
super(s);
}
Line(final String s, final Encoding enc) {
super(s, enc, enc.fieldDelimiter);
}
@Override
Field newSubComponent() {
return new Field();
}
@Override
Field newSubComponent(final String s) {
return new Field(s);
}
@Override
Field newSubComponent(final String s, final Encoding enc) {
return new Field(s, enc);
}
public void encode(final StringBuilder sb, final Encoding enc) {
super.encode(sb, enc, enc.fieldDelimiter, enc.segmentDelimiter);
}
public Field field(final int index) {
return super.subComponent0Based(index);
}
public Repetition repetition(final int fieldIndex, final int repetitionIndex) {
return this.field(fieldIndex).repetition(repetitionIndex);
}
public Component component(final int fieldIndex, final int repetitionIndex, final int componentIndex) {
return this.field(fieldIndex).repetition(repetitionIndex).component(componentIndex);
}
public Component component(final int fieldIndex, final int componentIndex) {
return this.field(fieldIndex).component(componentIndex);
}
public SubComponent subComponent(final int fieldIndex, final int repetitionIndex, final int componentIndex, final int subComponentIndex) {
return this.field(fieldIndex).repetition(repetitionIndex).component(componentIndex).subComponent(subComponentIndex);
}
public SubComponent subComponent(final int fieldIndex, final int componentIndex, final int subComponentIndex) {
return this.field(fieldIndex).component(componentIndex).subComponent(subComponentIndex);
}
// shorter aliases
public Field f(final int index) {
return this.field(index);
}
public Repetition r(final int fieldIndex, final int repetitionIndex) {
return this.repetition(fieldIndex, repetitionIndex);
}
public Component c(final int fieldIndex, final int repetitionIndex, final int componentIndex) {
return this.component(fieldIndex, repetitionIndex, componentIndex);
}
public Component c(final int fieldIndex, final int componentIndex) {
return this.component(fieldIndex, componentIndex);
}
public SubComponent sc(final int fieldIndex, final int repetitionIndex, final int componentIndex, final int subComponentIndex) {
return this.subComponent(fieldIndex, repetitionIndex, componentIndex, subComponentIndex);
}
public SubComponent sc(final int fieldIndex, final int componentIndex, final int subComponentIndex) {
return this.subComponent(fieldIndex, componentIndex, subComponentIndex);
}
@Override
public String toString() {
return super.toString("Line");
}
}

View File

@ -0,0 +1,213 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (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.mozilla.org/MPL/
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
* specific language governing rights and limitations under the License.
*
* Copyright (c) 2016 Travis Burtrum.
*
* Alternatively, the contents of this file may be used under the terms of the
* GNU General Public License (the "GPL"), in which case the provisions of the GPL are
* applicable instead of those above. If you wish to allow use of your version of this
* file only under the terms of the GPL and not to allow others to use your version
* of this file under the MPL, indicate your decision by deleting the provisions above
* and replace them with the notice and other provisions required by the GPL License.
* If you do not delete the provisions above, a recipient may use your version of
* this file under either the MPL or the GPL.
*/
package com.moparisthebest.hl7;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class Message {
public static final Encoding DEFAULT_ENCODING = new Encoding('\r', '~', '|', '^', '&', '\\'); // http://healthstandards.com/blog/2006/11/02/hl7-escape-sequences/
public static final Encoding NEWLINE_ENCODING = new Encoding('\n', '~', '|', '^', '&', '\\');
private final List<Line> lines = new ArrayList<>();
public Message() {
line("MSH");
}
public Message(final String sendingApplication, final String sendingFacility, final String receivingApplication, final String receivingFacility, final String messageCode, final String messageTriggerEvent, final String messageControlId, final String processingId, final String version) {
final Line msh = line("MSH");
msh.field(3).value(sendingApplication);
msh.field(4).value(sendingFacility);
msh.field(5).value(receivingApplication);
msh.field(6).value(receivingFacility);
msh.field(7).date(Instant.now());
final Field messageType = msh.field(9);
messageType.component(1).value(messageCode);
messageType.component(2).value(messageTriggerEvent);
messageType.component(3).value(messageCode + "_" + messageTriggerEvent);
msh.field(10).value(messageControlId);
msh.field(11).value(processingId);
msh.field(12).value(version);
}
public Message(final String s) throws ParseException {
final int mshIdx = s.indexOf("MSH");
if(mshIdx == -1 || s.length() < (mshIdx + 8))
throw new ParseException("HL7 messages must start with an MSH segment", 0);
// detect segmentDelimiter
char segmentDelimiter = DEFAULT_ENCODING.segmentDelimiter;
final char fieldDelimiter = s.charAt(mshIdx + 3);
byte fieldDelimiterCount = 0;
// 11 fields in is the version, next non-number or . is segmentDelimiter
for(int i = mshIdx; i < s.length(); ++i) {
if(fieldDelimiterCount < 11) {
if(s.charAt(i) == fieldDelimiter)
++fieldDelimiterCount;
} else {
final char c = s.charAt(i);
if(c != '.' && !Character.isDigit(c)) {
segmentDelimiter = c;
break;
}
}
}
final Encoding enc = new Encoding(segmentDelimiter, s.charAt(mshIdx + 5), fieldDelimiter, s.charAt(mshIdx + 4), s.charAt(mshIdx + 7), s.charAt(mshIdx + 6));
for(final String line : enc.splitSegment("MSH" + fieldDelimiter + s.substring(mshIdx + 8)))
if(!line.isEmpty())
lines.add(new Line(line, enc));
// shift MSH one to account for brain-dead 1st field while setting encoding
final Line msh = this.lines.get(0);
msh.field(2); // expand array sufficiently
msh.subComponents.add(1, enc.msh1);
msh.subComponents.set(2, enc);
}
public String encode() {
return this.encode(DEFAULT_ENCODING);
}
public String encode(final Encoding enc) {
// set encoding
final Line msh = this.lines.get(0);
msh.field(2); // expand array sufficiently
msh.subComponents.set(1, enc.msh1);
msh.subComponents.set(2, enc);
final StringBuilder sb = new StringBuilder();
for(final Line line : lines)
line.encode(sb, enc);
if(!lines.isEmpty()){
int index = 1;
while (index > 0 && sb.charAt(index = sb.length() - 1) == enc.segmentDelimiter)
sb.setLength(index);
}
return sb.toString();
}
public Line optionalLine(final String type) {
for(final Line line : lines)
if(line.field(0).equals(type))
return line;
return null;
}
public Line line(final String type) {
Line line = optionalLine(type);
if(line == null)
lines.add(line = new Line(type));
return line;
}
public Line line(final int index) {
return lines.get(index);
}
public List<Line> getLines() {
return lines;
}
public List<Line> lines(final String type) {
return lines.stream().filter(l -> l.field(0).equals(type)).collect(Collectors.toList());
}
public Line add(final String line) {
final Line ret = new Line(line);
lines.add(ret);
return ret;
}
public Message add(final Line line) {
lines.add(line);
return this;
}
public Message writeAndRead(final Socket sock, final Encoding enc) throws IOException, ParseException {
return this.writeAndRead(sock.getOutputStream(), sock.getInputStream(), enc);
}
public Message writeAndRead(final OutputStream os, final InputStream is, final Encoding enc) throws IOException, ParseException {
this.writeTo(os, enc);
os.flush();
return readFrom(is, enc);
}
public void writeTo(final OutputStream os, final Encoding enc) throws IOException {
os.write(enc.verticalTab);
// todo: this can be made dramatically faster by writing to this directly instead of a StringBuilder
os.write(this.encode(enc).getBytes(StandardCharsets.US_ASCII));
os.write(enc.fileSeperator);
os.write(enc.segmentDelimiter);
}
public static Message readFrom(final InputStream is, final Encoding enc) throws IOException, ParseException {
final StringBuilder sb = new StringBuilder();
for (int i = -1; (i = is.read()) != -1; ) {
//System.out.println("i: "+i);
final char c = (char) i;
//System.out.println("c: "+c);
if (c == enc.fileSeperator) { // end of line/message
// next char should be segmentDelimiter
i = is.read();
if (((char) i) != enc.segmentDelimiter)
throw new ParseException("HL7 messages have a segmentDelimiter directly following a fileSeperator", sb.length());
return new Message(sb.toString());
} else {
sb.append(c);
}
}
return null; // no complete message received
}
public Message writeAndRead(final Socket sock) throws IOException, ParseException {
return this.writeAndRead(sock, DEFAULT_ENCODING);
}
public Message writeAndRead(final OutputStream os, final InputStream is) throws IOException, ParseException {
return this.writeAndRead(os, is, DEFAULT_ENCODING);
}
public void writeTo(final OutputStream os) throws IOException {
this.writeTo(os, DEFAULT_ENCODING);
}
public static Message readFrom(final InputStream is) throws IOException, ParseException {
return readFrom(is, DEFAULT_ENCODING);
}
@Override
public String toString() {
return "Message" + lines;
}
}

View File

@ -0,0 +1,78 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (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.mozilla.org/MPL/
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
* specific language governing rights and limitations under the License.
*
* Copyright (c) 2016 Travis Burtrum.
*
* Alternatively, the contents of this file may be used under the terms of the
* GNU General Public License (the "GPL"), in which case the provisions of the GPL are
* applicable instead of those above. If you wish to allow use of your version of this
* file only under the terms of the GPL and not to allow others to use your version
* of this file under the MPL, indicate your decision by deleting the provisions above
* and replace them with the notice and other provisions required by the GPL License.
* If you do not delete the provisions above, a recipient may use your version of
* this file under either the MPL or the GPL.
*/
package com.moparisthebest.hl7;
public class Repetition extends SubComponentContainer<Component> {
Repetition() {
super();
}
Repetition(final String s) {
super(s);
}
Repetition(final String s, final Encoding enc) {
super(s, enc, enc.componentDelimiter);
}
@Override
Component newSubComponent() {
return new Component();
}
@Override
Component newSubComponent(final String s) {
return new Component(s);
}
@Override
Component newSubComponent(final String s, final Encoding enc) {
return new Component(s, enc);
}
public void encode(final StringBuilder sb, final Encoding enc) {
super.encode(sb, enc, enc.componentDelimiter, enc.repetitionDelimiter);
}
public Component component(final int index) {
return super.subComponent1Based(index);
}
public SubComponent subComponent(final int componentIndex, final int subComponentIndex) {
return this.component(componentIndex).subComponent(subComponentIndex);
}
// shorter aliases
public Component c(final int componentIndex) {
return this.component(componentIndex);
}
public SubComponent sc(final int componentIndex, final int subComponentIndex) {
return this.subComponent(componentIndex, subComponentIndex);
}
@Override
public String toString() {
return super.toString("Component");
}
}

View File

@ -0,0 +1,50 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (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.mozilla.org/MPL/
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
* specific language governing rights and limitations under the License.
*
* Copyright (c) 2016 Travis Burtrum.
*
* Alternatively, the contents of this file may be used under the terms of the
* GNU General Public License (the "GPL"), in which case the provisions of the GPL are
* applicable instead of those above. If you wish to allow use of your version of this
* file only under the terms of the GPL and not to allow others to use your version
* of this file under the MPL, indicate your decision by deleting the provisions above
* and replace them with the notice and other provisions required by the GPL License.
* If you do not delete the provisions above, a recipient may use your version of
* this file under either the MPL or the GPL.
*/
package com.moparisthebest.hl7;
public class RepetitionCounter {
private final Field field;
private int index;
RepetitionCounter(final Field field, final int index) {
this.field = field;
this.index = index - 1;
}
public Repetition nextRepetition() {
return field.r(++index);
}
public Repetition currentRepetition() {
return field.r(index);
}
// shorter aliases
public Repetition nr() {
return nextRepetition();
}
public Repetition cr() {
return currentRepetition();
}
}

View File

@ -0,0 +1,115 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (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.mozilla.org/MPL/
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
* specific language governing rights and limitations under the License.
*
* Copyright (c) 2016 Travis Burtrum.
*
* Alternatively, the contents of this file may be used under the terms of the
* GNU General Public License (the "GPL"), in which case the provisions of the GPL are
* applicable instead of those above. If you wish to allow use of your version of this
* file only under the terms of the GPL and not to allow others to use your version
* of this file under the MPL, indicate your decision by deleting the provisions above
* and replace them with the notice and other provisions required by the GPL License.
* If you do not delete the provisions above, a recipient may use your version of
* this file under either the MPL or the GPL.
*/
package com.moparisthebest.hl7;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.ResolverStyle;
import java.time.format.SignStyle;
import java.util.Locale;
import static java.time.temporal.ChronoField.*;
public interface SubComponent {
DateTimeFormatter LOCAL_DATE = new DateTimeFormatterBuilder()
.appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
.appendValue(MONTH_OF_YEAR, 2)
.appendValue(DAY_OF_MONTH, 2)
.parseStrict()
.toFormatter(Locale.US)
.withResolverStyle(ResolverStyle.STRICT);
DateTimeFormatter LOCAL_DATE_TIME = new DateTimeFormatterBuilder()
.appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
.appendValue(MONTH_OF_YEAR, 2)
.appendValue(DAY_OF_MONTH, 2)
.appendValue(HOUR_OF_DAY, 2)
.appendValue(MINUTE_OF_HOUR, 2)
.parseStrict()
.toFormatter(Locale.US)
.withResolverStyle(ResolverStyle.STRICT);
DateTimeFormatter INSTANT = new DateTimeFormatterBuilder()
.appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
.appendValue(MONTH_OF_YEAR, 2)
.appendValue(DAY_OF_MONTH, 2)
.appendValue(HOUR_OF_DAY, 2)
.appendValue(MINUTE_OF_HOUR, 2)
.appendValue(SECOND_OF_MINUTE, 2)
.appendLiteral('.')
.appendValue(MILLI_OF_SECOND, 3)
.appendOffset("+HHMM", "0000")
.parseStrict()
.toFormatter(Locale.US)
.withZone(ZoneId.systemDefault())
.withResolverStyle(ResolverStyle.STRICT);
SubComponent value(final String value);
String value();
boolean equals(final String s);
void encode(final StringBuilder sb, final Encoding enc);
default boolean isEmpty() {
return this.equals("");
}
default void date(final LocalDate date) {
this.value(LOCAL_DATE.format(date));
}
default void date(final LocalDateTime date) {
this.value(LOCAL_DATE_TIME.format(date));
}
default void date(final Instant date) {
this.value(INSTANT.format(date));
}
// shorter aliases
default SubComponent v(final String value) {
return this.value(value);
}
default String v() {
return this.value();
}
default void d(final LocalDate date) {
this.date(date);
}
default void d(final LocalDateTime date) {
this.date(date);
}
default void d(final Instant date) {
this.date(date);
}
}

View File

@ -0,0 +1,117 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (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.mozilla.org/MPL/
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
* specific language governing rights and limitations under the License.
*
* Copyright (c) 2016 Travis Burtrum.
*
* Alternatively, the contents of this file may be used under the terms of the
* GNU General Public License (the "GPL"), in which case the provisions of the GPL are
* applicable instead of those above. If you wish to allow use of your version of this
* file only under the terms of the GPL and not to allow others to use your version
* of this file under the MPL, indicate your decision by deleting the provisions above
* and replace them with the notice and other provisions required by the GPL License.
* If you do not delete the provisions above, a recipient may use your version of
* this file under either the MPL or the GPL.
*/
package com.moparisthebest.hl7;
import java.util.ArrayList;
import java.util.List;
abstract class SubComponentContainer<T extends SubComponent> implements SubComponent {
protected final List<T> subComponents = new ArrayList<>();
protected SubComponentContainer() {
subComponents.add(newSubComponent());
}
protected SubComponentContainer(final String s) {
subComponents.add(newSubComponent(s));
}
protected SubComponentContainer(final String s, final Encoding enc, final char thisDelimiter) {
for(final String line : enc.split(s, thisDelimiter))
subComponents.add(newSubComponent(line, enc));
if(subComponents.isEmpty())
subComponents.add(newSubComponent());
}
abstract T newSubComponent();
abstract T newSubComponent(final String s);
abstract T newSubComponent(final String s, final Encoding enc);
protected final void encode(final StringBuilder sb, final Encoding enc, final char thisDelimiter, final char parentDelimiter) {
for(final SubComponent e : subComponents)
e.encode(sb, enc);
if(!subComponents.isEmpty()){
int index = 1, count = -1;
while (++count < subComponents.size() && index > 0 && sb.charAt(index = sb.length() - 1) == thisDelimiter)
sb.setLength(index);
}
sb.append(parentDelimiter);
}
protected T subComponent0Based(final int index) {
while(subComponents.size() <= index)
subComponents.add(newSubComponent());
return subComponents.get(index);
}
protected T subComponent1Based(final int index) {
while(subComponents.size() < index)
subComponents.add(newSubComponent());
return subComponents.get(index - 1);
}
@Override
public SubComponent value(final String value) {
if(subComponents.size() == 1) {
subComponents.get(0).value(value);
} else {
subComponents.clear();
subComponents.add(newSubComponent(value));
}
return this;
}
@Override
public String value() {
// todo: this isn't ALWAYS correct, it just returns the first, ignoring any other field/repetition/component/subcomponent/whatever
return subComponents.isEmpty() ? "" : subComponents.get(0).value();
}
@Override
public boolean equals(final String s) {
// more complicated than you'd think
if("".equals(s)) {
// special case for empty string
if(subComponents.isEmpty())
return true;
// otherwise every one needs to be empty
for(final SubComponent sc : subComponents)
if(!sc.isEmpty())
return false;
} else {
if(subComponents.isEmpty())
return false;
boolean first = true;
// first has to match, and every OTHER one needs to be empty now...
for(final SubComponent sc : subComponents) {
if (!(first ? sc.equals(s) : sc.isEmpty()))
return false;
first = false;
}
}
return true;
}
protected final String toString(final String name) {
return subComponents.size() == 1 ? subComponents.get(0).toString() : name + subComponents;
}
}

View File

@ -0,0 +1,70 @@
/*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (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.mozilla.org/MPL/
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
* specific language governing rights and limitations under the License.
*
* Copyright (c) 2016 Travis Burtrum.
*
* Alternatively, the contents of this file may be used under the terms of the
* GNU General Public License (the "GPL"), in which case the provisions of the GPL are
* applicable instead of those above. If you wish to allow use of your version of this
* file only under the terms of the GPL and not to allow others to use your version
* of this file under the MPL, indicate your decision by deleting the provisions above
* and replace them with the notice and other provisions required by the GPL License.
* If you do not delete the provisions above, a recipient may use your version of
* this file under either the MPL or the GPL.
*/
package com.moparisthebest.hl7;
import java.util.Objects;
class SubComponentImpl implements SubComponent {
protected String value;
SubComponentImpl() {
this("");
}
SubComponentImpl(final String value) {
value(value);
}
SubComponentImpl(final String s, final Encoding enc) {
this.value = enc.decode(s);
}
public void encode(final StringBuilder sb, final Encoding enc) {
sb.append(enc.encode(this.value));
sb.append(enc.subComponentDelimiter);
}
String encode(final Encoding enc) {
return enc.encode(this.value);
}
@Override
public SubComponent value(final String value) {
this.value = value == null ? "" : value;
return this;
}
@Override
public boolean equals(final String s) {
return Objects.equals(value, s);
}
@Override
public String value() {
return value;
}
@Override
public String toString() {
return value;
}
}