C-CDA validation fails because of "Unknown type" in my server but not in standalone project - hl7

I was checking how to use the MDHT libraries to validate C-CDA documents, reviewing the current implementations, to create a validation web service for my project. I firstly made a Eclipse local Java Project, added the JARs to the classpath, and implement the code. The execution was successful. But when I copy the same code to my web project (made with Spring Boot) and send a request that executes such code, the program fails.
To explain better, I made the following minimal method:
public void executeMDHTCode(byte[] fileContents) {
System.out.println(Arrays.toString(fileContents));
ValidationResult result = new ValidationResult();
ClinicalDocument doc = null;
try {
ConsolPackage.eINSTANCE.eClass();
doc = CDAUtil.load(new ByteArrayInputStream(fileContents), result);
} catch (ClassCastException|SAXParseException|Resource.IOWrappedException e) {
doc = null;
} catch (Exception e) {
throw new RuntimeException("Unknown error: " + e.getMessage(), e);
}
}
Then I used it in the following main method in my test project
public static void main(String[] args) throws IOException {
ByteArrayOutputStream outstr = new ByteArrayOutputStream();
int b = -1;
InputStream stream = AppTest.class.getResourceAsStream("xml_ccda_invalid.xml");
while((b = stream.read()) != -1) {
outstr.write(b);
}
executeMDHTCode(outstr.toByteArray()); // only added 'static'
}
And then used the same code in my server project (encapsulating it in a ccdaService)
#RequestMapping(/*POST endpoint properties*/)
public ResponseEntity<Object> validateCCDAFile(#RequestBody MultipartFile file) throws IOException {
ccdaService.executeMDHTCode(file.getBytes());
return null;
}
The document to be tested in both cases, xml_ccda_invalid.xml, contains the following:
<?xml version="1.0" encoding="UTF-8"?>
<ClinicalDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:hl7-org:v3" xsi:schemaLocation="urn:hl7-org:v3 CDA.xsd">
<realmCode code="US"/>
</ClinicalDocument>
As I said, the test project version terminates correctly. But the server version throws the following exception:
java.lang.UnsupportedOperationException: Unknown type ([vocab, ActClinicalDocument, DOCCLIN])
at org.eclipse.mdht.uml.cda.operations.ClinicalDocumentOperations.validateClassCode(ClinicalDocumentOperations.java:133) ~[org.eclipse.mdht.uml.cda-3.0.0.201706220503.jar:?]
at org.eclipse.mdht.uml.cda.impl.ClinicalDocumentImpl.validateClassCode(ClinicalDocumentImpl.java:1659) ~[org.eclipse.mdht.uml.cda-3.0.0.201706220503.jar:?]
at org.eclipse.mdht.uml.cda.util.CDAValidator.validateClinicalDocument_validateClassCode(CDAValidator.java:1769) ~[org.eclipse.mdht.uml.cda-3.0.0.201706220503.jar:?]
at org.eclipse.mdht.uml.cda.util.CDAValidator.validateClinicalDocument(CDAValidator.java:1753) ~[org.eclipse.mdht.uml.cda-3.0.0.201706220503.jar:?]
at org.eclipse.mdht.uml.cda.util.CDAValidator.validate(CDAValidator.java:1075) ~[org.eclipse.mdht.uml.cda-3.0.0.201706220503.jar:?]
at org.eclipse.emf.ecore.util.EObjectValidator.validate(EObjectValidator.java:324) ~[org.eclipse.emf.ecore-2.12.0.v20160420-0247.jar:?]
at org.eclipse.emf.ecore.util.Diagnostician.doValidate(Diagnostician.java:171) ~[org.eclipse.emf.ecore-2.12.0.v20160420-0247.jar:?]
at org.eclipse.emf.ecore.util.Diagnostician.validate(Diagnostician.java:158) ~[org.eclipse.emf.ecore-2.12.0.v20160420-0247.jar:?]
at org.eclipse.emf.ecore.util.Diagnostician.validate(Diagnostician.java:137) ~[org.eclipse.emf.ecore-2.12.0.v20160420-0247.jar:?]
at org.eclipse.emf.ecore.util.Diagnostician.validate(Diagnostician.java:108) ~[org.eclipse.emf.ecore-2.12.0.v20160420-0247.jar:?]
at org.eclipse.mdht.uml.cda.util.CDAUtil.validate(CDAUtil.java:707) ~[org.eclipse.mdht.uml.cda-3.0.0.201706220503.jar:?]
at org.eclipse.mdht.uml.cda.util.CDAUtil.validate(CDAUtil.java:696) ~[org.eclipse.mdht.uml.cda-3.0.0.201706220503.jar:?]
at org.eclipse.mdht.uml.cda.util.CDAUtil.performEMFValidation(CDAUtil.java:830) ~[org.eclipse.mdht.uml.cda-3.0.0.201706220503.jar:?]
at org.eclipse.mdht.uml.cda.util.CDAUtil.load(CDAUtil.java:277) ~[org.eclipse.mdht.uml.cda-3.0.0.201706220503.jar:?]
at org.eclipse.mdht.uml.cda.util.CDAUtil.load(CDAUtil.java:252) ~[org.eclipse.mdht.uml.cda-3.0.0.201706220503.jar:?]
at companypackage.service.impl.CCDAServiceImpl.executeMDHTCode(CCDAServiceImpl.java:109) ~[bin/:?]
at companypackage.controller.CCDAController.validateCCDAFile(CCDAController.java:32) ~[bin/:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_102]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_102]
at (other spring and apache calls...)
I used the println statement to check the contents of the input array, and they are in both cases identical, so it's not a matter of server processing of the file.
I have not idea why this happens. I put all the jars of the server project into the test project's classpath and it still worked, so it's not a class name clash. It seems to be only interfere when actually used.
What could I be missing?

The looks to be an issue with the war file deployment - the ActClinicalDocument is defined in the org.eclipse.mdht.uml.hl7.vocab jar; if you are using maven for the build you can look at the following maven example https://github.com/mdht/mdht-models/tree/develop/examples/org.openhealthtools.mdht.cda.maven.example
if not make sure in your eclipse project that the jars etc are included in the binary build

It sounds like you aren't applying a schema in your standalone project, or maybe not the same schema, so it is validating without reference to the validation process.

Related

Configuration of embedded Neo4j to run APOC procedures

I have cypher queries that make use of APOC functions. It works without problem if running the app directly but I would also like to test those queries. I tried to use following approach but getting an exception Unknown function 'apoc.coll.toSet'
My sample test class:
public class ApocTest {
private static Neo4j neo4j;
private static Driver driver;
#BeforeAll
static void initializeNeo4j() {
// Make sure that the plugins folder is listed in -cp
Path pluginDirContainingApocJar = Paths.get("src/main/resources/neo4j-plugins/");
if (!Files.exists(pluginDirContainingApocJar)) {
throw new IllegalArgumentException("Invalid path to plugins directory");
}
neo4j = Neo4jBuilders
.newInProcessBuilder()
.withDisabledServer()
.withFixture("CREATE (p1:Person)-[:knows]->(p2:Person)-[:knows]->(p3:Person)")
.withConfig(GraphDatabaseSettings.plugin_dir, pluginDirContainingApocJar)
.withConfig(GraphDatabaseSettings.procedure_unrestricted, List.of("apoc.*"))
.build();
driver = GraphDatabase.driver(neo4j.boltURI(), AuthTokens.none());
}
#AfterAll
static void stopNeo4j() {
driver.close();
neo4j.close();
}
#Test
public void testApoc(){
String query = "MATCH path=()-[:knows*2]->()\n" +
"RETURN apoc.coll.toSet(nodes(path)) AS nodesSet";
List<Object> nodesSet = driver.session()
.beginTransaction()
.run(query)
.single()
.get("nodesSet")
.asList();
assertEquals(3, nodesSet.size());
}
}
Any idea how to fix that?
This sample project on the github
Versions:
neo4j-java-driver: 4.1.1
neo4j-harness 4.1.6
org.neo4j.procedure: 4.1.0.5
Update:
So I tried to update:
Path pluginDirContainingApocJar = new File(
ApocConfig.class.getProtectionDomain().getCodeSource().getLocation().toURI())
.getParentFile().toPath();
That means that I don't need to manipulate with apoc jars, right?
But I'm still getting error:
Caused by: org.neo4j.kernel.lifecycle.LifecycleException: Component 'org.neo4j.procedure.impl.GlobalProceduresRegistry#27dc627a' was successfully initialized, but failed to start. Please see the attached cause exception "Unable to set up injection for procedure `CypherProcedures`, the field `cypherProceduresHandler` has type `class apoc.custom.CypherProceduresHandler` which is not a known injectable component.".
at org.neo4j.kernel.lifecycle.LifeSupport$LifecycleInstance.start(LifeSupport.java:463)
at org.neo4j.kernel.lifecycle.LifeSupport.start(LifeSupport.java:110)
at org.neo4j.graphdb.facade.DatabaseManagementServiceFactory.startDatabaseServer(DatabaseManagementServiceFactory.java:189)
... 58 more
Caused by: org.neo4j.kernel.api.exceptions.ComponentInjectionException: Unable to set up injection for procedure `CypherProcedures`, the field `cypherProceduresHandler` has type `class apoc.custom.CypherProceduresHandler` which is not a known injectable component.
at org.neo4j.procedure.impl.FieldInjections.createInjector(FieldInjections.java:98)
at org.neo4j.procedure.impl.FieldInjections.setters(FieldInjections.java:81)
at org.neo4j.procedure.impl.ProcedureCompiler.compileProcedure(ProcedureCompiler.java:264)
at org.neo4j.procedure.impl.ProcedureCompiler.compileProcedure(ProcedureCompiler.java:226)
at org.neo4j.procedure.impl.ProcedureJarLoader.loadProcedures(ProcedureJarLoader.java:114)
at org.neo4j.procedure.impl.ProcedureJarLoader.loadProceduresFromDir(ProcedureJarLoader.java:85)
at org.neo4j.procedure.impl.GlobalProceduresRegistry.start(GlobalProceduresRegistry.java:342)
at org.neo4j.kernel.lifecycle.LifeSupport$LifecycleInstance.start(LifeSupport.java:442)
... 60 more
Update 2 - working on 4.0:
For some reason downgrade to Neo4j 4.0, same version as in recommended, was enough to make it working. Now I won't spend more time to try to run it on Neo4j 4.1/4.2.
My code
Probably the way the path to the plugin directory was created. There's an example from Michael Simons here that explains using the neo4j classloader: https://github.com/michael-simons/neo4j-examples-and-tips/blob/master/examples/testing-ogm-against-embedded-with-apoc/src/test/java/org/neo4j/tips/testing/testing_ogm_against_embedded_with_apoc/ApplicationTests.java#L53

Run Checker Framework with Bazel

Consider this github repository. https://github.com/dfabulich/bazel-checker-framework-bug
It includes a sample X.java file that flagrantly violates the rules of the #Nonnull annotation.
import javax.annotation.Nonnull;
public class X {
public static void main(String[] args) {
new X().exec();
}
public void exec() {
System.out.println(this.method());
}
#Nonnull
private String method() {
return null;
}
}
The WORKSPACE file just includes checker.jar.
maven_jar(
name="checker",
artifact="org.checkerframework:checker:2.3.1"
)
The BUILD file invokes the compiler with the checker framework configured as a java_plugin.
java_library(
name='x',
srcs=['X.java'],
deps=['#checker//jar'],
plugins=['checker'],
)
java_plugin(
name='checker',
deps=['#checker//jar'],
processor_class='org.checkerframework.checker.nullness.NullnessChecker',
)
When I bazel build x, the build fails with this error:
error: InvocationTargetException when invoking constructor for class org.checkerframework.checker.nullness.KeyForAnnotatedTypeFactory; Underlying cause: java.lang.StackOverflowError; The Checker Framework crashed. Please report the crash. To see the full stack trace invoke the compiler with -AprintErrorStack
When I comment out the plugins line in the BUILD file, the build succeeds without error. (That makes sense, but I ultimately want the Checker Framework to fail this build with a return.type.incompatible error.)
Am I making a mistake here? Is this a bug in Bazel?
I got a good answer on the bazel-discuss mailing list, telling me to try NullAway, an Error Prone plugin that depends on the Checker Framework.
The github repo now includes a working example using NullAway, like this.
WORKSPACE:
maven_jar(
name='jsr305',
artifact='com.google.code.findbugs:jsr305:3.0.2',
)
maven_jar(
name="nullaway",
artifact="com.uber.nullaway:nullaway:0.3.2"
)
maven_jar(
name="guava",
artifact="com.google.guava:guava:22.0",
)
BUILD:
java_library(
name='x',
srcs=['X.java'],
deps=['#jsr305//jar'],
plugins=['nullaway'],
javacopts=[
'-Xep:NullAway:ERROR',
'-XepOpt:NullAway:AnnotatedPackages=com.example',
],
)
java_plugin(
name='nullaway',
deps=[
'#nullaway//jar',
'#guava//jar',
],
)
(The dependency on guava is unfortunate; it's required because without Guava, NullAway refuses to load.)

How to populate parameter "defaultValue" in Maven "AbstractMojoTestCase"?

I have a Maven plugin that I am attempting to test using a subclass of the AbstractMojoTestCase. The plugin Mojo defines an outputFolder parameter with a defaultValue. This parameter is not generally expected to be provided by the user in the POM.
#Parameter(defaultValue = "${project.build.directory}/someOutputFolder")
private File outputFolder;
And if I use the plugin in a real scenario then the outputFolder gets defaulted as expected.
But if I test the Mojo using the AbstractMojoTestCase then while parameters defined in the test POM are populated, parameters with a defaultValue that are not defined in the POM are not populated.
public class MyPluginTestCase extends AbstractMojoTestCase {
public void testAssembly() throws Exception {
final File pom = getTestFile( "src/test/resources/test-pom.xml");
assertNotNull(pom);
assertTrue(pom.exists());
final MyMojo myMojo = (BaselineAssemblyMojo) lookupMojo("assemble", pom);
assertNotNull(myMojo);
myMojo.execute(); // Dies due to NullPointerException on outputFolder.
}
}
Further: if I define the outputFolder parameter in the POM like so:
<outputFolder>${project.build.directory}/someOutputFolder</outputFolder>
then ${project.build.directory} is NOT resolved within the AbstractMojoTestCase.
So what do I need to do to get the defaultvalue populated when testing?
Or is this a fault in the AbstractMojoTestCase?
This is Maven-3.2.3, maven-plugin-plugin-3.2, JDK 8
You need to use lookupConfiguredMojo.
Here's what I ended up using:
public class MyPluginTest
{
#Rule
public MojoRule mojoRule = new MojoRule();
#Test
public void noSource() throws Exception
{
// Just give the location, where the pom.xml is located
MyPlugin plugin = (MyPlugin) mojoRule.lookupConfiguredMojo(getResourcesFile("basic-test"), "myGoal");
plugin.execute();
assertThat(plugin.getSomeInformation()).isEmpty();
}
public File getResourcesFile(String filename)
{
return new File("src/test/resources", filename);
}
}
Of course you need to replace myGoal with your plugin's goal. You also need to figure out how to assert that your plugin executed successfully.
For a more complete example, check out the tests I wrote for fmt-maven-plugin

Logback - do not create empty log files at startup

I have a project with a lot of 'tool' classes that have their own logging. Those logfiles are created at startup of the application, but remain empty, until used.
Is it possible to tell logback that empty files should not be created at startup? But only when they are being used?
Somehow I don't find information on this topic. Thanks!
There is no official support for lazy/on-demand creation of log files in Logback's FileAppender.
However there are some known configuration workarounds that may achieve the same result. For more details see the Logback feature request 202 "FileAppender should permit lazy file creation".
My personal favorite is the variant using the LazyFileOutputStream and a custom implementation of a FileAppender. A working implementation of an LazyFileOutputStream can be found in Alessio Pollero's log4j-additions section.
An the LazyFileappender code is very simple:
public class LazyFileAppender<E> extends FileAppender<E> {
#Override
public void openFile(String file_name) throws IOException {
lock.lock();
try {
File file = new File(file_name);
boolean result = FileUtil.createMissingParentDirectories(file);
if (!result) {
addError("Failed to create parent directories for [" + file.getAbsolutePath() + "]");
}
LazyFileOutputStream lazyFos = new LazyFileOutputStream(file, append);
setOutputStream(lazyFos);
} finally {
lock.unlock();
}
}
}

Calling Remote EJB3 in separate EAR file from JSF in another EAR file on WAS 8

I'm new to EJB3 and having trouble calling a remote ejb from my JSF managed bean when the two are in separate ear files on the same server (WAS 8). If they are in the same ear file then I have no problems. But I need the call to work across different applications on the same server.
During the EJB injection into the Managed Bean, I get the following exception:
Caused by: javax.ejb.EJBException: The EJB/BelgianBeerSessionBean EJB reference in the null component in the BeerStoreWebProject.war module of the BeerStoreWebEAR application could not be resolved; nested exception is: com.ibm.ejs.container.EJBNotFoundException: EJB with interface com.ejb.view.BelgianBeerSessionBeanRemote not present in application BeerStoreWebEAR
Caused by: com.ibm.ejs.container.EJBNotFoundException: EJB with interface com.ejb.view.BelgianBeerSessionBeanRemote not present in application BeerStoreWebEAR
at com.ibm.ejs.container.HomeOfHomes.getHomeByInterface(HomeOfHomes.java:928)
at com.ibm.ws.ejbcontainer.injection.factory.EJBLinkObjectFactory.getObjectInstance(EJBLinkObjectFactory.java:261)
at com.ibm.ws.ejbcontainer.injection.factory.EJBLinkObjectFactory.getObjectInstance(EJBLinkObjectFactory.java:167)
I'm hoping that someone could help me get to the bottom of this and explain how I should be injecting and looking up a remote EJB if it is in a separate EAR file.
Here is my setup:
Project Setup
1) BelgianBeersEJMProjectClient (an ejb client project that contains the interfaces)
package com.ejb.view;
public interface BelgianBeerSessionInterface {
List<Country> getAllCountries();
void saveCountries(List<Country> countries);
}
package com.ejb.view;
#Remote
public interface BelgianBeerSessionBeanRemote extends
BelgianBeerSessionInterface {
}
2) BelgianBeersEJBProject (containing the ejb implementation)
package com.ejb;
#Stateless
public class BelgianBeerSessionBean implements BelgianBeerSessionBeanRemote,
BelgianBeerSessionBeanLocal {
public BelgianBeerSessionBean() {
// TODO Auto-generated constructor stub
}
public List<Country> getAllCountries() {
//to be implemented
return null;
}
public void saveCountries(List<Country> countries) {
//to be implemented
}
}
Also in the META-INF there is an ejb-jar.xml:
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar version="3.1" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd">
<display-name>BelgianBeersEJBProject </display-name>
<ejb-client-jar>BelgianBeersEJBProjectClient.jar</ejb-client-jar>
</ejb-jar>
3) BelgianBeersWebProject - contains the jsf app
#ManagedBean
#ViewScoped
public class BeerStorePageBean {
#EJB(name="EJB/BelgianBeerSessionBean")
private BelgianBeerSessionBeanRemote store;
public BelgianBeerSessionBeanRemote getStore() {
return store;
}
public void setStore(BelgianBeerSessionBeanRemote store) {
this.store = store;
}
private List<Country> countries = null;
#PostConstruct
public void populateCountries(){
System.out.println("Store = " + store);
countries = store.getAllCountries();
}
public List<Country> getAllCountries() {
return countries;
}
}
and in the web.xml there is an ejb entry:
<ejb-ref>
<description />
<ejb-ref-name>EJB/BelgianBeerSessionBean</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<home />
<remote>com.ejb.view.BelgianBeerSessionBeanRemote</remote>
</ejb-ref>
Deployment Units
EAR file 1 (BelgianBeersEARProject.ear) contains:
1) BelgianBeersEJBProject.jar
2) BelgianBeersEJBProjectClient.jar
EAR file 2 (BeerStoreWebEAR.ear) contains:
1. BeerStoreWebProject.war
2. BelginaBeersEJBProjectClient.jar
Please could somebody explain to me the correct way of calling a remote EJB which is in a separate EAR file. Please help! I'm tearing my hair out!
The #EJB annotation (and corresponding <ejb-ref> in XML) will only automatically link if the target EJB is in the same application. From the javadoc:
If no explicit linking information is provided and there is only one
session bean within the same application that exposes the matching
client view type, by default the EJB dependency resolves to that
session bean.
To link to an EJB in another application, you need to specify a binding. You can do this in several ways:
Specify <lookup-name>targetBindingName</lookup-name> in the <ejb-ref> in ejb-jar.xml.
Specify <ejb-ref name="EJB/BelgianBeerSessionBean" binding-name="targetBindingName"/> in the WEB-INF/ibm-web-bnd.xml file of the WAR module containing the ejb-ref. See the InfoCenter for more information on the format of the binding files.
Specify the target binding name during application deployment (that is, do not "use default bindings").
In any case, you're going to need the binding name of the target EJB. The InfoCenter link above describes both the "classic" WebSphere Application Server binding names and the Java EE 6 standard "java:global" names. The former can be configured in ibm-ejb-jar-bnd.xml and the latter cannot (aside from specifying alternate <application-name> or <module-name>), but it doesn't really matter which you use. To find which names are being used, it's easiest to start the EJB application and then look for the CNTR0167I messages that are printed by the EJB container when it starts (the first one is the "classic" binding):
[6/6/13 17:26:04:531 CDT] 00000049 WASNameSpaceB I CNTR0167I: The server is binding the javax.management.j2ee.ManagementHome interface of the Management enterprise bean in the mejb.jar module of the ManagementEJB application. The binding location is: ejb/mgmt/MEJB
[6/6/13 17:26:04:544 CDT] 00000049 AbstractEJBRu I CNTR0167I: The server is binding the javax.management.j2ee.ManagementHome interface of the Management enterprise bean in the mejb.jar module of the ManagementEJB application. The binding location is: java:global/ManagementEJB/mejb/Management!javax.management.j2ee.ManagementHome

Resources