Search code examples
javatomcataxishapi

Using Hapi on an Axis service: "Can't create XML document"


I'm developing an Axis service to interface with a HL7 remote service. I have a class (Hl7MessageTranslator) to encode query request like this:

public Hl7MessageTranslator(...)
{
...
parser = new DefaultXMLParser();
}

public String encodeRequest(...) throws ... HL7Exception
{
// prepare HL7 query request
QRY_A19 qryA19 = new QRY_A19();
    ...
    return parser.encode(qryA19);
 }

the encodeRequest() method works fine when called outside the tomcat environment (JUnit test) but fails when called from the Axis service: I get the following warning while creating the class:

SLF4J: This version of SLF4J requires log4j version 1.2.12 or later. See also  http://www.slf4j.org/codes.html#log4j_version
INFO - 2014-05-20 09:11:07,543 - Classe: ca.uhn.hl7v2.util.Home - Metodo: setHomeDirectory - Descrizione: hapi.home is set to C:\Programmi\eclipse-j2ee-helios\. 
INFO - 2014-05-20 09:11:07,933 - Classe: ca.uhn.hl7v2.VersionLogger - Metodo: printHapiVersion - Descrizione: HAPI version is: 2.2 
INFO - 2014-05-20 09:11:07,949 - Classe: ca.uhn.hl7v2.VersionLogger - Metodo: checkStructureLibraries - Descrizione: Default Structure libraries found for HL7 versions 2.5, 2.6,  
WARN - 2014-05-20 09:11:08,011 - Classe: ca.uhn.hl7v2.VersionLogger - Metodo: checkDOMImplementation - Descrizione: Error occured while trying to retrieve a DOMImplementation. 
java.lang.RuntimeException: java.lang.ClassCastException: org.apache.xerces.dom.DOMXSImplementationSourceImpl cannot be cast to org.w3c.dom.DOMImplementationSource
at ca.uhn.hl7v2.util.XMLUtils.getDOMImpl(XMLUtils.java:55)
at ca.uhn.hl7v2.VersionLogger.checkDOMImplementation(VersionLogger.java:44)
at ca.uhn.hl7v2.VersionLogger.init(VersionLogger.java:36)
at ca.uhn.hl7v2.DefaultHapiContext.<init>(DefaultHapiContext.java:126)
at ca.uhn.hl7v2.DefaultHapiContext.<init>(DefaultHapiContext.java:112)
at ca.uhn.hl7v2.DefaultHapiContext.<init>(DefaultHapiContext.java:103)
at ca.uhn.hl7v2.parser.Parser.<init>(Parser.java:71)
at ca.uhn.hl7v2.parser.XMLParser.<init>(XMLParser.java:89)
at ca.uhn.hl7v2.parser.DefaultXMLParser.<init>(DefaultXMLParser.java:81)
at com.avelco.integrazioni.areavasta.naar.Hl7MessageTranslator.<init>(Hl7MessageTranslator.java:105)
at com.avelco.integrazioni.areavasta.naar.NaarBridge.requestGrid(NaarBridge.java:135)
at com.avelco.integration.services.Service.requestGrid(Service.java:122)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
...
WARN - 2014-05-20 09:11:08,011 - Classe: ca.uhn.hl7v2.VersionLogger - Metodo: checkDOMImplementation - Descrizione: XML parsing and encoding as well as working with Conformance Profiles will fail. 

and the following error while calling the parser.encode() method:

20/05/2014 09:11:08 : debug: Filling MSH ...
20/05/2014 09:11:08 : debug: Filling QRD ...
20/05/2014 09:11:08 : debug: Filling QRF ...
ca.uhn.hl7v2.HL7Exception: Can't create XML document - java.lang.RuntimeException
at ca.uhn.hl7v2.parser.DefaultXMLParser.encodeDocument(DefaultXMLParser.java:115)
at ca.uhn.hl7v2.parser.XMLParser.doEncode(XMLParser.java:241)
at ca.uhn.hl7v2.parser.Parser.encode(Parser.java:276)
at com.avelco.integrazioni.areavasta.naar.Hl7MessageTranslator.encodeRequest(Hl7MessageTranslator.java:174)
at com.avelco.integrazioni.areavasta.naar.NaarBridge.requestGrid(NaarBridge.java:144)
at com.avelco.integration.services.Service.requestGrid(Service.java:122)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)

Since it works when called by JUnit it must be a dependency/configuration problem but I can't figure where to look for it.

Thanks in advance

Massimo


Solution

  • At last I came out of this.

    As Hussein Zawawi suggested it was a jar conflict with axis, only it was Xerces and not log4j the cause.

    It seems that some HAPI DefaultXMLParser methods expected org.w3c.dom Objects but the factory in my environment produced org.apache.xerces.dom ones.

    Unfortunately I couldn't remove Xerces from the project without breaking the legacy software I'm working with. Eventually I had to write my own implementation of DefaultXMLParser rewriting faulty methods and replacing XML parse and serializing calls.

    public class AvXmlParser extends DefaultXMLParser
    {
    
    /*
     * (non-Javadoc)
     * @see ca.uhn.hl7v2.parser.DefaultXMLParser#encodeDocument(ca.uhn.hl7v2.model.Message)
     */
    public Document encodeDocument(Message source) throws HL7Exception
    {
    String messageClassName = source.getClass().getName();
    String messageName = messageClassName.substring(messageClassName.lastIndexOf('.') + 1);
    org.w3c.dom.Document doc = null;
    try
    {
    // doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
        doc = XmlUtilities.emptyDom();
    // Element root = doc.createElement(messageName);
        Element root = doc.createElementNS("urn:hl7-org:v2xml",messageName);
        doc.appendChild(root);
    }
    catch (Exception e)
    {
        throw new HL7Exception("Can't create XML document - " + e.getClass().getName(), e);
    }
    encode(source, doc.getDocumentElement());
    return doc;
    }
    
    /**
     * @param groupObject
     * @param groupElement
     * @throws HL7Exception
     */
    private void encode(ca.uhn.hl7v2.model.Group groupObject, org.w3c.dom.Element groupElement) throws HL7Exception
    {
    String[] childNames = groupObject.getNames();
    String messageName = groupObject.getMessage().getName();
    try
    {
        for (int i = 0; i < childNames.length; i++)
        {
        Structure[] reps = groupObject.getAll(childNames[i]);
        for (int j = 0; j < reps.length; j++)
        {
            Element childElement = groupElement.getOwnerDocument().createElement(makeGroupElementName(messageName, childNames[i]));
            groupElement.appendChild(childElement);
            if (reps[j] instanceof Group)
            {
            encode((Group) reps[j], childElement);
            }
            else if (reps[j] instanceof Segment)
            {
            encode((Segment) reps[j], childElement);
            }
        }
        }
    }
    catch (DOMException e)
    {
        throw new HL7Exception("Can't encode group " + groupObject.getClass().getName(), e);
    }
    }
    
    /*
     * (non-Javadoc)
     * @see ca.uhn.hl7v2.parser.XMLParser#parseStringIntoDocument(java.lang.String)
     */
    protected synchronized Document parseStringIntoDocument(String message) throws HL7Exception
    {
    try
    {
        Document doc = XmlUtilities.parseString(message);
        return doc;
    }
    catch (Exception e)
    {
        throw new HL7Exception("Exception parsing XML",e);
    }
    }
    }
    

    (The XmlUtilities class is a utility class already available in my environment). Most of the problems were so because of the legacy software I'm working with and not because of HAPI or Xerces but I hope my solution can be useful in future.