I am working on a Java endpoint that I intend to use for HL7 message validation. I have a basic app running that uses a variation of the standard HAPI HL7 validation example. If I pass in a valid message I get the "Success" response. If I pass in a invalid message I still get a "Success" response.
The only way I get an error response is if the HL7 is badly formatted and the PipeParser throws an exception. In that case it gets caught in the catch block.
What I want to see is if I pass in an invalid message that it actually gets validated and returns all the validation errors. But I don't ever actually see any validation. It either parses or crashes trying to parse.
What am I missing here?
HapiContext context = new DefaultHapiContext();
ValidationContext validationContext = ValidationContextFactory.defaultValidation();
context.setValidationContext(validationContext);
try
{
context.getParserConfiguration().setUnexpectedSegmentBehaviour(UnexpectedSegmentBehaviourEnum.THROW_HL7_EXCEPTION);
Message messageValidationResults = context.getPipeParser().parse(hl7Message);
SimpleValidationExceptionHandler handler = new SimpleValidationExceptionHandler(context);
handler.setMinimumSeverityToCollect(Severity.INFO);
Validator<Boolean> validator = context.getMessageValidator();
if (!validator.validate(messageValidationResults, handler))
{
if (handler.getExceptions().size() == 0)
{
hl7ValidationResult = "SUCCESS - Message Validated Successfully";
}
else
{
hl7ValidationResult = "ERROR - Found " + handler.getExceptions().size() + " problems\n\n";
for (Exception e : handler.getExceptions())
{
hl7ValidationResult += (e.getClass().getSimpleName() + " - " + e.getMessage()) + "\n";
}
}
}
}
catch (Exception e)
{
hl7ValidationResult = "ERROR - " + e.getMessage();
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
String sStackTrace = sw.toString();
hl7ValidationResult += "\n\n" + sStackTrace;
}
Please ignore the answer if do you think is not correct, I stopped to work with HL7 but, looking at my old project I have found this and maybe it can help you to find the solution of your problem:
{
DefaultValidationBuilder builder = new DefaultValidationBuilder() {
private static final long serialVersionUID = 1L;
#Override
protected void configure() {
super.configure();
forVersion(Version.V26);
}
};
HapiContext context = new DefaultHapiContext();
context.setValidationRuleBuilder(builder);
PipeParser hapiParser = context.getPipeParser();
try {
hapiParser.parse(hl7Message);
} catch (ca.uhn.hl7v2.HL7Exception e) {
// String error, String language, String requisitionNumber, String controlId, String processinId, String senderApplication, String senderFacility
errors.add(new HL7ValidationError(
"HAPI Validator error found: " + e.getMessage(),
extractor.accessPatientDirectly().getLanguage(),
extractor.accessPatientDirectly().getRequisitionNumber(),
extractor.accessPatientDirectly().getControlID(),
"",
extractor.accessPatientDirectly().getSenderApplication(),
extractor.accessPatientDirectly().getSenderFacility())
);
log.debug("HAPI Validator error found: " + e.getMessage());
}
try {
context.close();
}
catch (Exception ex) {
log.debug("Unable to close HapiContext(): " + ex.getMessage());
}
}
Basically I used hapiParser.parse(hl7Message); and catch the HL7Exception
Related
I have wsdl service. All request and response saving in minio bucket. But when content too big, in minio saved only part of this content.
My Interceptor
#Slf4j
#Component
public class LogResponseInterceptor extends AbstractPhaseInterceptor<Message> {
private final MinioService minioService;
private final AdministrationWebClient administrationWebClient;
public LogResponseInterceptor(MinioService minioService, AdministrationWebClient administrationWebClient) {
super(Phase.PRE_PROTOCOL_ENDING);
this.minioService = minioService;
this.administrationWebClient = administrationWebClient;
}
#Override
public void handleMessage(Message message) throws Fault {
try (CachedOutputStream outputStream = ((CachedOutputStream) message.getContent(OutputStream.class));
InputStream inputStream = outputStream.getInputStream()) {
UUID uuid = UUID.randomUUID();
minioService.uploadFile(
inputStream, Constantas.MinioConst.MINIO_SPV_OUT_PATH, uuid.toString(), "application/xml"
);
SpvRecord spvRecord = SpvRequestContext.getSpvRequest();
spvRecord.setRequestState(RequestState.COMPLETED);
spvRecord.setResponseXmlUrl(Constantas.MinioConst.MINIO_SPV_OUT_PATH + uuid);
spvRecord.setFinishDate(ZonedDateTime.now());
log.info("End spv action with {}", spvRecord);
spvRecord.setRequestNumber(administrationWebClient.getSpvLastRequestNumber() + 1);
administrationWebClient.createSpvRecord(spvRecord);
} catch (IOException e) {
log.error("### Error while get response xml");
throw new RuntimeException(e);
} finally {
SpvRequestContext.clear();
}
}
}
CachedOutputStream contains only part of response body. How i can get full response body?
You can try lowering the level of the phase.The attachment interceptor is at the receive level (version 3.3.7).
To get the request you can try this, copy the original content to be able to flush it.
// now get the request xml
InputStream is = message.getContent ( InputStream.class );
CachedOutputStream os = new CachedOutputStream ( );
IOUtils.copy ( is, os );
os.flush ( );
message.setContent ( InputStream.class, os.getInputStream ( ) );
is.close ( );
System.out.println ("The request is: " + IOUtils.toString ( os.getInputStream ( ) ));
os.close ( );
To get the response, you need made custom implementation del original
https://github.com/apache/cxf/blob/main/rt/features/logging/src/main/java/org/apache/cxf/ext/logging/LoggingOutInterceptor.java
and modify the method onClose(CachedOutputStream cos) with this
public void onClose(CachedOutputStream cos) {
final LogEvent event = eventMapper.map(message);
if (shouldLogContent(event)) {
copyPayload(cos, event);
} else {
event.setPayload(CONTENT_SUPPRESSED);
}
StringBuilder sb = new StringBuilder("\nOutbound Message\n---------------------------\n");
sb.append("ID: " + event.getExchangeId() + " \n");
sb.append("Address: " + event.getAddress() + " \n");
sb.append("Encoding: " + event.getEncoding() + " \n");
sb.append("Content-Type: " + event.getContentType() + " \n");
sb.append("Headers: " + event.getHeaders() + " \n");
if(event.isTruncated()) {
sb.append("Payload (truncated) : " + event.getPayload() + " \n");
} else {
sb.append("Payload: " + event.getPayload() + " \n");
}
sb.append("---------------------------");
this.logger.trace(sb.toString());
try {
// empty out the cache
cos.lockOutputStream();
cos.resetOut(null, false);
} catch (Exception ex) {
// ignore
}
message.setContent(OutputStream.class, origStream);
}
IMPORTANT: the limit truncate the response, set limit to max for read the entire response
I am trying to get the list of files from remote FTP server. The ftpClient.listFiles() returned null and I had to set setUnparseableEntries to true to get the list of files. Even then the list of files do not have any information like name and only information it has is rawlisting and others are null. So I cannot do ftpFile.getName. Here is the code
public FTPFile[] process() throws Exception {
String message = null;
FTPFile[] files = null;
FTPClient ftpClient = new FTPClient();
FTPClientConfig config = new FTPClientConfig();
config.setServerTimeZoneId("America/Chicago");
config.setUnparseableEntries(true);
ftpClient.configure(config);
if ( !connectToServer() ) return null;
if ( !changeDirectory() ) {
disconnectFromServer();
return null;
}
files = getListofFiles();
disconnectFromServer();
return files;
}
private boolean connectToServer() {
boolean result = true;
String message = null, url = null;
// attempt to connect to the target server
try {
url = fo.getServerInfo().getConnectionURL();
LOGGER.debug("Connecting to: " + url);
ftpClient.connect(fo.getServerInfo().getHostName(),
fo.getServerInfo().getHostPort());
ftpClient.enterLocalPassiveMode();
} catch(SocketException e) {
result = false;
message = "Could not connect to server at " + url;
} catch(IOException e) {
result = false;
message = "Could not connect to server at " + url;
}
if ( !result ) return result;
// After connection attempt, you should check the reply code to verify success.
Integer replyCode = ftpClient.getReplyCode();
if ( !FTPReply.isPositiveCompletion(replyCode) ) {
message = "Reply Code - " + replyCode.toString() + " is negative.";
try {
ftpClient.disconnect();
} catch(Exception e) {
message = "Could not disconnect cleanly from server.";
LOGGER.error(message);
}
} else {
message = "Reply Code - " + replyCode.toString() + " is positive.";
}
Boolean logonOk = false;
try {
logonOk = ftpClient.login(fo.getServerInfo().getUserName(),
fo.getServerInfo().getUserPassword());
} catch(IOException e) {
message = "IOException during logon attempt.";
LOGGER.error(message);
}
if ( !logonOk ) {
result = false;
message = "Logon UNsuccessful.";
} else {
message = "Logon successful.";
LOGGER.error(message);
executionMessageLog.add(message);
}
if ( !result ) return result;
// attempt to log onto the target server
return result;
}
Following method is trying to get the list of files. I could see the file name using listNames and also listFiles shows list of files but name, modified date are empty and only has value in rawlisting in the format "04-01-20 11:31AM 8975 test.TXT". So how to get the name and modified date from the raw listing and why I could not get FTPFile name using getName
private FTPFile[] getListofFiles(){
String message = null;
FTPFile[] files = null;
try {
String[] filenames = ftpClient.listNames(fileListInfo.getFilePath());
files = ftpClient.listFiles(); /*Has only rawlisting and others are null*/
}
catch(IOException e) {
message = "IOException during getListofFiles attempt:";
LOGGER.error(message);
executionMessageLog.add(message);
message = e.getMessage();
LOGGER.error(message);
executionMessageLog.add(message);
}
return files;
}
04-01-20 11:31AM 8975 test.TXT
That's quite unusual format. So it's possible that Apache Commons Net library cannot parse it with the default configuration.
You might need to explicitly specify one of the available parsers. The available parsers are in src\main\java\org\apache\commons\net\ftp\parser. Or if there's no parser specifically compatible with your server, you might need to build your own (you can base it on ConfigurableFTPFileEntryParserImpl).
Though actually, for an ad-hoc solution, easier would be that you just parse the "rawlisting" you already have.
I'm writing an IRC bot that is supposed to grab the artist name from this webpage http://whatthefuckshouldilistentorightnow.com/artist.php?artist=e&x=36&y=30 if someone types in !music. This is part of the code:
public void onMessage(String channel, String sender, String login, String hostname, String message) {
if (messageIC.startsWith("!music ")) {
String musicy = "id=\"artist\">"
try {
Document doc = Jsoup.connect("http://whatthefuckshouldilistentorightnow.com/artist.php?artist=e&x=36&y=30").get();
}
catch (IOException e){
}
String texty = doc.body().text(); // "An example link"
if (texty.contains(musicy)) {
String artisty = texty.substring(musicy);
int artsy1 = artisty.indexOf(">") + 1;
int artsy2 = artisty.indexOf("</div>");
artisty = artisty.substring(artsy1, artsy2);
sendMessage(channel, "artisty: " + artisty); // */
}
else {
sendMessage(channel, "Something went wrong.");
}
}
}
However, I am receiving an error message at String texty = doc.body().text();. The message is:
"cannot find symbol
symbol: method body()"
Any ideas as to what is wrong or how to improve on the code would be appreciated.
This is because you are declaring your var inside the try catch. You should either use it inside the try-catch or declare it before. Try this for example...
Document doc = null;
try {
doc = Jsoup.connect("http://whatthefuckshouldilistentorightnow.com/artist.php?artist=e&x=36&y=30").get();
} catch (IOException e){}
// rest of code
Firstly, let me say I not a java programmer, I am a programmer on the IBM Iseries. However, I've been tasked with changing a current java application that currently sends a stream of data to one URL that will allow that same stream of data to be sent to multiple URLs based on a properties file. Our java app runs on the Iseries and we are using the org.apache.commons.httpclient.HttpClient class to send the data and the response is processed. Everything works great right now, but I wanted to see if anyone could point me in the right direction to complete this task.
Essentially, I need to send the same block of data to multiple URLs within the same thread or instance. I'm not sure if its possible or the best way to try to complete this. So, is there a way to create multiple instances within the same thread that will send the same data stream to multiple URLs? Before you start commenting I will say again that I am not a java programmer and I wasn't even sure how to phrase the question.
Added code sample:
public class Replication_CC implements TextProcessor {
public static String VERSION = "v2014.1.0";
static Logger log = Logger.getLogger(Replication_CC.class);
String url;
int retries = 1;
public Replication_CC(Properties p) {
super();
url = p.getProperty("url");
log.info("Service URL set to " + url);
retries = PropertiesUtil.getOptionalIntProperty(p, "retries", 1);
log.info("Retries set to " + retries);
}
public static void main(String[] args) throws Exception {
log.info("Replication " + VERSION);
log.info("Initializing...");
Properties p = PropertiesUtil.loadProperties(Replication_CC.class.getResource("/Replication_CC.properties"));
DQServer server = new DQServer(p, new Replication_CC(p));
server.run();
}
public String process(String request) throws Exception {
long processStart = System.currentTimeMillis();
String response = null;
for (int i=0; i<=retries; i++) {
try {
response = send(request, url);
if (response!=null) break;
}
catch (Exception e) {
log.warn("Error processing: " + e.getMessage());
if (i<retries) {
log.warn("Trying again (retry " + (i+1) + "...");
}
else {
log.error("Giving up on this transaction.");
break;
}
}
}
long processFinished = System.currentTimeMillis();
log.info("Request was processed in " + (processFinished-processStart) + "ms.");
return response;
}
public String send(String request, String url) throws Exception {
log.debug("Creating request...");
HttpClientParams params = new HttpClientParams();
params.setParameter("http.useragent", "http-api / Replication");
HttpClient client = new HttpClient(params);
PostMethod post = new PostMethod(url);
/*
List<NameValuePair> params = new ArrayList<NameValuePair>();
for (String key : globalRequest.keySet()) {
params.add(nvp(key, globalRequest.get(key)));
}
*/
post.setRequestBody(request);
// Log the request
if (log.isDebugEnabled()) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
post.getRequestEntity().writeRequest(baos);
baos.close();
log.debug("HTTP Request: \n" + StringUtils.repeat("*", 100) + "\n" + "Content Type: "
+ post.getRequestEntity().getContentType() + "\n" + "Content Length: "
+ post.getRequestEntity().getContentLength() + "\n" + "Request Headers: "
+ ArrayUtils.toString(post.getRequestHeaders()) + "\n" + "Request Params: " + baos.toString() + "\n" +
StringUtils.repeat("*", 100));
}
try {
log.info("Sending request...");
int responseCode = client.executeMethod(post);
//log.debug(String.format("Http Response Code [%s]", responseCode));
log.debug("Http Response Code [" + responseCode + "]");
if (responseCode == HttpStatus.SC_OK) {
String charset = post.getResponseCharSet();
log.debug("Response Character Set [" + charset + "]");
/*
byte[] body = post.getResponseBody();
String response = new String(body, charset);
*/
String response = IOUtils.toString(post.getResponseBodyAsStream());
log.debug("Response Body: \n" + response);
return response;
}
else {
throw new Exception(post.getStatusLine().toString());
}
}
catch (IOException ioe) {
log.error(ioe);
throw ioe;
}
finally {
post.releaseConnection();
}
}
One simple way is to include multiple URL's in the existing url property separated by a unique character. I chose "|" (pipe) in this example because it's highly unlikely to see a pipe in a normal url.
Java identifies methods by name and parameter signature. We can use that to our advantage by adding a String url parameter to the existing process method and creating a new process(String request) method that will split and iterate over the url's. The only downside is that it will only return the last response to the DQServer class.
public String process(String request) throws Exception {
String response;
for (String u : url.split("\\|")) {
response = process(request, u);
}
return response;
}
public String process(String request, String url) throws Exception {
long processStart = System.currentTimeMillis();
String response = null;
for (int i=0; i<=retries; i++) {
try {
response = send(request, url);
if (response!=null) break;
}
catch (Exception e) {
log.warn("Error processing: " + e.getMessage());
if (i<retries) {
log.warn("Trying again (retry " + (i+1) + "...");
}
else {
log.error("Giving up on this transaction.");
break;
}
}
}
long processFinished = System.currentTimeMillis();
log.info("Request was processed in " + (processFinished-processStart) + "ms.");
return response;
}
The complete sample is available on GitHub Gist.
After reading both
How can I pass a Class as parameter and return a generic collection in Java?
and
How do I pass a class as a parameter in Java?
I am unsure how I would pass a JibX generated class as a parameter to a method that serializes the object.
I would like to accomplish something like the following.
protected static String SerializeObject( Class clazz , Object request)
{
String message = null;
try
{
IBindingFactory lBindingFactory = BindingDirectory.getFactory(
clazz.class);
IMarshallingContext lContext = lBindingFactory.
createMarshallingContext();
ByteArrayOutputStream lOutputStream = new ByteArrayOutputStream();
lContext.marshalDocument(request, "UTF-8", null,
lOutputStream);
message = new String(lOutputStream.toByteArray(), "UTF-8");
}
catch (JiBXException lEx)
{
throw new RuntimeException("Problems generating XML, " +
"underlying problem is " + lEx.getMessage(), lEx);
}
catch (UnsupportedEncodingException lEx)
{
throw new RuntimeException("Problems generating XML in specified" +
"encoding, underlying problem is " + lEx.getMessage(), lEx);
}
return message;
}
Where the class is only used to define what the BindingDirectory is using to serialize the object into.
I might be better to avoid attempting to pass the class at all. I can achieve the same affect by passing the IBindingFactory and adding a bit of code to the caller.
The result would end up like this.
protected static String SerializeObject( IBindingFactory lBindingFactory,
Object request)
{
String message = null;
try
{
IMarshallingContext lContext = lBindingFactory.
createMarshallingContext();
ByteArrayOutputStream lOutputStream = new ByteArrayOutputStream();
lContext.marshalDocument(request, "UTF-8", null,
lOutputStream);
message = new String(lOutputStream.toByteArray(), "UTF-8");
}
catch (JiBXException lEx)
{
throw new RuntimeException("Problems generating XML, " +
"underlying problem is " + lEx.getMessage(), lEx);
}
catch (UnsupportedEncodingException lEx)
{
throw new RuntimeException("Problems generating XML in specified" +
"encoding, underlying problem is " + lEx.getMessage(), lEx);
}
return message;
}