How to create HL7 message ORU_R01 type using HAPI 2.4 - hl7

I am newbie to HL7. I am trying to construct HL7 message ORU_R01 type using HAPI 2.4. I got incorrect message format when I add patient details in the below code; otherwise the format is ok. How to fix this issue? is there any example to construct HL7 ORU message with PID,ORC,OBR and OBX?
Output without patient
MSH|^~\&|IM|ABC-ClinPath|ABC-vet|ABC-VetMed|20180412124041||ORU^R01
Output with patient (If I comment the patient details in the code)
PID||TEST|||^TESTlinPath|ABC-vet|ABC-VetMed|20180412124041||ORU^R01
import ca.uhn.hl7v2.model.v24.message.ORM_O01;
import ca.uhn.hl7v2.HapiContext;
import ca.uhn.hl7v2.DefaultHapiContext;
import ca.uhn.hl7v2.parser.Parser;
import ca.uhn.hl7v2.model.v24.segment.MSH;
import ca.uhn.hl7v2.model.v24.group.ORM_O01_PATIENT;
public class CreateORUMessage {
private String sendingApplication = "IM";
private String sendingFacility = "ABC-ClinPath";
private String receivingApplication = "ABC-vet";
private String receivingFacility = "ABC-VetMed";
private void createHL7Message(){
try{
ORM_O01 order = new ORM_O01();
//ORU_R01 oru = new ORU_R01();
// Populate the MSH Segment
// Example - MSH|^~\&|HISA_8592|HISF_2603|||200706081131||ADT^A04|HL7O.1.11379|D|2.1
MSH mshSegment = order.getMSH();
mshSegment.getFieldSeparator().setValue("|");
mshSegment.getEncodingCharacters().setValue("^~\\&");
mshSegment.getSendingApplication().getNamespaceID().setValue(sendingApplication);
mshSegment.getSendingFacility().getNamespaceID().setValue(sendingFacility);
mshSegment.getReceivingApplication().getNamespaceID().setValue(receivingApplication);
mshSegment.getReceivingFacility().getNamespaceID().setValue(receivingFacility);
mshSegment.getDateTimeOfMessage().getTimeOfAnEvent().setValue("20180412124041");
mshSegment.getMessageType().getMessageType().setValue("ORU");
mshSegment.getMessageType().getTriggerEvent().setValue("R01");
//PID - patient details
ORM_O01_PATIENT orm_pid = order.getPATIENT();
orm_pid.getPID().getPid5_PatientName(0).getGivenName().setValue("TEST");
orm_pid.getPID().getPid2_PatientID().getCx1_ID().setValue("TEST");
// Now, let's encode the message and look at the output
HapiContext context = new DefaultHapiContext();
Parser parser = context.getPipeParser();
String encodedMessage = parser.encode(order);
System.out.println("Printing ER7 Encoded Message:");
System.out.println(encodedMessage);
//String msg = order.encode();
//System.out.println(msg);
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String args[]){
new CreateORUMessage().createHL7Message();
}
}
I tried other way too, but it's not worked :(
String msg = order.encode();
System.out.println(msg);

Your problem most likely is, that the segment separator character in HL7 is CR, which just resets the cursor to the start of the line and the next line overwrites the previous one. This only affects writing the message to the console. Writing to file or sending over TCP should be fine without any further conversions.
I had the same problem in an application once, this is my solution below.
ORU_R01 outMessage = new ORU_R01();
outMessage.setParser(hapiContext.getPipeParser());
outMessage.initQuickstart("ORU", "R01", "T");
MSH mshSegment = outMessage.getMSH();
mshSegment.getMsh3_SendingApplication().getHd1_NamespaceID().setValue("MIG-TOOL");
/* some code removed */
PID pidSegment = outMessage.getRESPONSE().getPATIENT().getPID();
pidSegment.getPid3_PatientIDInternalID(0).parse(reportData.getPatientId());
/* some more code removed */
LOGGER.trace("Generated message contents:\n" + replaceNewlines(outMessage.encode()));
And the code for replaceNewLines() is quite simple
private static String replaceNewlines(String input) {
return input.replaceAll("\\r", "\n");
}

Related

Mapping the Microsoft Graph response to Java POJO - API returned value do not match MSGraph Models Enum values

I'm trying to map the response from the MSGraph API call to retrieve a list of email messages.
I'm using jackson fasterxml and mapping into the API provided classes - MessageCollectionResponse which contains a list of Message pojos
However, the Message class itself has four enums that will not map because the values returned from the API are lowercase, and the ENUM values are only UPPERCASE
(and in one instance (flagStatus) spelled differently).
The API's reponse that won't map are key/value pairs - "importance":"normal", "contentType":"html", "flagStatus": "notFlagged", "inferenceClassification":"focused"
which appear to correspond to package com.microsoft.graph.models enum classes Importance.class, , ItemBody.class/BodyType.class, FollowupFlag.class, InferenceClassificationType.class
My code...
String userPrincipleName = URLEncoder.encode("myemailaddress#domain.com",
java.nio.charset.StandardCharsets.UTF_8.toString());
URL url = new URL("https://graph.microsoft.com/v1.0/users/" + userPrincipleName +
"/messages");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Authorization", "Bearer " + accessToken);
conn.setRequestProperty("Accept","application/json");
conn.setRequestProperty("Request","application/json");
int httpResponseCode = conn.getResponseCode();
if(httpResponseCode == HTTPResponse.SC_OK) {
StringBuilder response;
try(BufferedReader in = new BufferedReader(
new InputStreamReader(conn.getInputStream()))){
String inputLine;
response = new StringBuilder();
while (( inputLine = in.readLine()) != null) {
response.append(inputLine);
}
}
String responseString = response.toString();
ObjectMapper objectMapper = new
ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.findAndRegisterModules();
MessageCollectionResponse responseX = objectMapper.readValue(responseString,
MessageCollectionResponse.class);
Here's the exception...
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type
`com.microsoft.graph.models.Importance` from String "normal": not one of the values accepted for Enum class: [HIGH, UNEXPECTED_VALUE, LOW, NORMAL]
at [Source: (StringReader); line: 1, column: 750] (through reference chain:
com.microsoft.graph.requests.MessageCollectionResponse["value"]->java.util.ArrayList[0]->com.microsoft.graph.models.Message["importance"])
Here's the field on the API Message model for example...
/**
* The Importance.
* The importance of the message. The possible values are: low, normal, and high.
*/
#SerializedName(value = "importance", alternate = {"Importance"})
#Expose
#Nullable
public Importance importance;
**Here's the API Emum class for example..**
// Template Source: Enum.java.tt
// ------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.
// ------------------------------------------------------------------------------
package com.microsoft.graph.models;
/**
* The Enum Importance.
*/
public enum Importance
{
/**
* low
*/
LOW,
/**
* normal
*/
NORMAL,
/**
* high
*/
HIGH,
/**
* For Importance values that were not expected from the service
*/
UNEXPECTED_VALUE
}
I could use Jackson to ignore these fields from mapping, but thought maybe others might have experienced this. Reviewing the Microsoft Graph models from version to version, I don't see that
these ENUMS ever changed, they appear to always be UPPERCASE. So, maybe there is a better way to map the response that I'm just not seeing or finding in the Microsoft Documentation. I'm using version 3.9.0 of microsoft-graph.
You have to use the Graph deserializer
DefaultSerializer serializer = new DefaultSerializer(new DefaultLogger());
MessageCollectionResponse responseObject = serializer.deserializeObject(responseString, MessageCollectionResponse .class);
The Importance is an Enum and you have to use the Serializer from MS who handle it.

Parse Stackdriver LogEntry JSON in Dataflow pipeline

I'm building a Dataflow pipeline to process Stackdriver logs, the data are read from Pub/Sub and results written into BigQuery.
When I read from Pub/Sub I get JSON strings of LogEntry objects but what I'm really interested in is protoPayload.line records which contain user log messages. To get those I need to parse LogEntry JSON object and I found a two years old Google example how to do it:
import com.google.api.client.json.JsonParser;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.logging.model.LogEntry;
try {
JsonParser parser = new JacksonFactory().createJsonParser(entry);
LogEntry logEntry = parser.parse(LogEntry.class);
logString = logEntry.getTextPayload();
}
catch (IOException e) {
LOG.error("IOException parsing entry: " + e.getMessage());
}
catch(NullPointerException e) {
LOG.error("NullPointerException parsing entry: " + e.getMessage());
}
Unfortunately this doesn't work for me, the logEntry.getTextPayload() returns null. I'm not even sure if it's suppose to work as com.google.api.services.logging library is not mentioned anywhere in Google Cloud docs, the current logging library seems to be google-cloud-logging.
So if anyone could suggest what is the right or simplest way of parsing LogEntry objects?
I ended up with manually parsing LogEntry JSON with gson library, using the tree traversing approach in particular.
Here is a small snippet:
static class ProcessLogMessages extends DoFn<String, String> {
#ProcessElement
public void processElement(ProcessContext c) {
String entry = c.element();
JsonParser parser = new JsonParser();
JsonElement element = parser.parse(entry);
if (element.isJsonNull()) {
return;
}
JsonObject root = element.getAsJsonObject();
JsonArray lines = root.get("protoPayload").getAsJsonObject().get("line").getAsJsonArray();
for (int i = 0; i < lines.size(); i++) {
JsonObject line = lines.get(i).getAsJsonObject();
String logMessage = line.get("logMessage").getAsString();
// Do what you need with the logMessage here
c.output(logMessage);
}
}
}
This is simple enough and works fine for me since I'm interested in protoPayload.line.logMessage objects only. But I guess this is not ideal way of parsing LogEntry objects if you need to work with many attributes.

StringTokenizer and token 'space'

I have a question!
I am using StringTokenizer but I don't understand how i can take 'space' as a token!
this is an example of my method:
import java.util.*;
public class miaProva{
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("Write phrase");
String s=sc.next();
StringTokenizer st=new StringTokenizer(s, " ,.");
StringBuilder sb=new StringBuilder();
sb.append('>');
while(st.hasMoreTokens()){
sb.append(st.nextToken());
}
sb.append('<');
System.out.println(sb);
}
}
but when it finds 'space' it interrupts the execution of the method.
INPUT:
1) hi,how,are.you
2) hi,how are you
OUTPUT:
1) >hihowareyou<
2) >hihow<
thank you
Have you tried split method in the String class ?
In your sample, when you do sc.next(), it gives you the text separated by space.
So when you type "Hi,how you are" the sc.next() returns only "hi,how"
Its not a problem with StringTokenizer, use sc.nextLine() instead of sc.next(). That should give you the result you are epecting.
The scanner is using white space as its default delimiter. So when you call sc.next(), it only returns the first part of the input before the space. you can tell it to include the whole line like this:
Scanner sc = new Scanner(System.in);
sc.useDelimiter("\r\n");
where "\r\n" matches newline on a Windows OS.
edit: It is better to use the lineSeparator method, so that is will work on any operating system.
Scanner sc = new Scanner(System.in);
sc.useDelimiter(System.lineSeparator());
edit 2: Or better still (having read #Sathiesh's answer), use sc.nextLine().

Reading multiple inputs from Dart Console

I want to read different data from the console in a Dart server application, like:
forename : user inputs and enters
lastname : user inputs and enters
age : user inputs and enters
The following code works, but for 1 input item only:
var stream = new StringInputStream(stdin);
stream.onData = () {
voornaam = stream.readLine();
};
But I can't get it to work for multiple items.
Is there an easy way to do this in Dart ?
Thanks!
Since you're using a StringInputStream rather than just a standard InputStream, and because you're looking to read text. Unless there's a particular reason, I would recommend using the onLine handler over the onData. On data will basically try to 'stream' the information in that it's called immediately not on a new line itself. Try something like the following (note, not complete code, missing proper error handling etc.)
#import('dart:io');
main() {
var stream = new StringInputStream(stdin);
stream.onLine = () {
var str = stream.readLine().trim();
print(str.toUpperCase());
if(str == 'EXIT') exit(0);
};
}
One other note to point out, if you ever are data-streaming and using the onData handler, it is recommended that you then use the read method, as opposed to the readLine method to retrieve your content, again due to the nature of onData not waiting for a full line of text to be received before being called.
import 'dart:io';
void main() {
print('-----welcome-----');
print('what is your firstname');
var fname = stdin.readLineSync();
print('what is your lastname');
var lname = stdin.readLineSync();
print('what is your age');
int age = int.parse(stdin.readLineSync());
int left = 100 - age;
print('your name is $fname $lname and you are $age years');
}

In OpenRasta, how should you handle codec errors or exceptions?

My scenario is this:
A client application executes a HTTP POST against an endpoint exposed by OpenRasta.
The body of the request contains an error that causes a problem in the codec - which is a custom implementation of OpenRasta.Codecs.IMediaTypeReader. This converts a JSON payload to the POCO expected by the handler.
The codec throws an exception that describes the error in a useful way. For example: Newtonsoft.Json.JsonReaderException: After parsing a value an unexpected character was encountered: ". Line 4, position 5.
The client application receives a HTTP 405 - MethodNotAllowed. The client doesn't see any of the exception details.
If the codec is modified to catch a JsonReaderException and return Missing.Value, similar to the Implementing a codec wiki, then the client receives a HTTP 500 - Internal Server Error. The body of the response also describes the following exception:
System.InvalidOperationException: The operation is not ready for invocation.
at OpenRasta.OperationModel.MethodBased.MethodBasedOperation.Invoke()
at OpenRasta.OperationModel.Interceptors.OperationWithInterceptors.<Invoke>b__0()
at OpenRasta.OperationModel.Interceptors.OperationWithInterceptors.Invoke()
at OpenRasta.OperationModel.OperationExecutor.Execute(IEnumerable`1 operations)
at OpenRasta.Pipeline.Contributors.OperationInvokerContributor.ExecuteOperations(ICommunicationContext context)
at OpenRasta.Pipeline.PipelineRunner.ExecuteContributor(ICommunicationContext context, ContributorCall call)
How should I modify my application so that:
The client receives a HTTP 400 Bad Request.
The client receives a string containing the details of the exception encountered in the codec.
Here is a minor variation of the answer above - this time with codec selection based on the operation result data.
Within IConfigurationSource:
using (OpenRastaConfiguration.Manual)
{
ResourceSpace.Uses.PipelineContributor<ErrorCheckingContributor>();
ResourceSpace.Has.ResourcesOfType<ApplicationError>()
.WithoutUri
.TranscodedBy<ApplicationErrorCodec>();
// Or use a generic JSON serializer like this:
// .AsJsonDataContract();
// Other configuration here
}
Now ErrorCheckingContributor looks like this:
public class ErrorCheckingContributor : IPipelineContributor
{
public void Initialize(IPipeline pipelineRunner)
{
pipelineRunner
.Notify(CheckRequestDecoding)
.After<KnownStages.IOperationResultInvocation>()
.And.Before<KnownStages.ICodecResponseSelection>();
}
private static PipelineContinuation CheckRequestDecoding(ICommunicationContext context)
{
if (context.ServerErrors.Count == 0)
{
return PipelineContinuation.Continue;
}
Error err = context.ServerErrors[0];
// Get a suitable message (err.Message contains stack traces, so try to avoid that)
string msg = err.Title;
if (msg == null && err.Exception != null)
msg = err.Exception.Message;
if (msg == null)
msg = err.Message;
// Create instance of an error information resource which is specific for the application
// - This one is rather simple and only contains a copy of the message
ApplicationError error = new ApplicationError(msg);
// Set operation result to be "400 Bad Request" and remove errors
context.OperationResult = new OperationResult.BadRequest { ResponseResource = error };
context.ServerErrors.Clear();
// Render immediately without starting any handlers
return PipelineContinuation.RenderNow;
}
}
The class ApplicationError is:
public class ApplicationError
{
public string Message { get; set; }
public ApplicationError(string message)
{
Message = message;
}
}
At last we need a codec ApplicationErrorCodec for ApplicationError. This is not different from any other IMediaTypeWriter codec but depends a lot on your expected response media type. See https://github.com/openrasta/openrasta/wiki/Implementing-a-Codec for one example.
Having found this thread on Google Groups which contains all the answers, my current implementation looks something like this.
Within my implementation of IConfigurationSource:
using (OpenRastaConfiguration.Manual)
{
ResourceSpace.Uses.PipelineContributor<ErrorCheckingContributor>();
// Other configuration here
}
Then ErrorCheckingContributor looks something like this:
public class ErrorCheckingContributor : IPipelineContributor
{
public void Initialize(IPipeline pipelineRunner)
{
pipelineRunner
.Notify(CheckRequestDecoding)
.After<KnownStages.IOperationResultInvocation>()
.And.Before<KnownStages.ICodecResponseSelection>();
}
private static PipelineContinuation CheckRequestDecoding(ICommunicationContext context)
{
if (context.ServerErrors.Count == 0)
{
return PipelineContinuation.Continue;
}
var first = context.ServerErrors[0];
if (first.Exception is Newtonsoft.Json.JsonReaderException)
{
context.Response.Entity.ContentType = MediaType.TextPlain;
context.Response.Entity.ContentLength = first.Exception.Message.Length;
using (var sw = new StreamWriter(context.Response.Entity.Stream))
{
sw.Write(first.Exception.Message);
}
}
return PipelineContinuation.Continue;
}
}
There's some things to be aware of with the above:
If a handler were to throw a JsonReaderException, it would also be processed here.
It doesn't check what media types the client accepts. This is different from exceptions thrown by Handlers that do go through codec selection.
Tried setting context.OperationResult to context.ServerErrors - but it doesn't go through the codec.

Resources