I have found something that may be related, removing whitespace from the response. But what's the best way to do that?
I am in the process of moving a Tomcat 6 (using Java 6) server to Tomcat 8.5 (using Java 8u111). One of the jsp's is giving me a problem on the new server. It sends a SOAP request and processes the response. I get the following error out of it
Error : com.sun.xml.internal.messaging.saaj.soap.impl.TextImpl cannot be cast to javax.xml.soap.SOAPBodyElement
when executing line 245
SOAPBodyElement sbeResponseRoot = (SOAPBodyElement) iterRoot.next();
This is the SOAP response it is trying to process.
<?xml version="1.0" encoding="UTF-8" ?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:WS_TestResponse xmlns:ns1="LLX_Service">
<outResultCode xsi:type="xsd:int">-1</outResultCode>
<outResultMsg xsi:type="xsd:string">Invalid ID Value, record not found</outResultMsg>
<outResultData xsi:type="xsd:string">IsTermed=No</outResultData>
</ns1:WS_TestResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Full stack trace follows:
org.apache.jsp.util.ws.ws_test_id_jsp._jspService(ws_test_id_jsp.java:245)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:443)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:385)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:329)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474)
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783)
org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:789)
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1437)
org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
java.lang.Thread.run(Unknown Source)
And a copy of the code.
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/8.5.9
* Generated at: 2016-12-28 02:33:46 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp.util.ws;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import javax.xml.soap.*;
import java.net.*;
import java.util.*;
import java.sql.*;
import org.w3c.dom.*;
public final class ws_test_id_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
static {
_jspx_dependants = new java.util.HashMap<java.lang.String,java.lang.Long>(4);
_jspx_dependants.put("/util/inc_data_load.jsp", Long.valueOf(1348785010000L));
_jspx_dependants.put("/util/inc_ws_data_test_emp.jsp", Long.valueOf(1482885343175L));
_jspx_dependants.put("/util/inc_ws_base.jsp", Long.valueOf(1482885343291L));
_jspx_dependants.put("/util/inc_ws_send.jsp", Long.valueOf(1482892420777L));
}
private static final java.util.Set<java.lang.String> _jspx_imports_packages;
private static final java.util.Set<java.lang.String> _jspx_imports_classes;
static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("java.sql");
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.xml.soap");
_jspx_imports_packages.add("java.util");
_jspx_imports_packages.add("java.net");
_jspx_imports_packages.add("org.w3c.dom");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}
public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
}
public void _jspDestroy() {
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
return;
}
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html; charset=utf-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
"", true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write('\r');
out.write('\n');
// Build XML and pass it all to the web service. Trap any errors in strStatus.
String strStatus = "";
String strServiceCallName = "WS_Tester";
String strServiceResultMsg = "";
Vector vecServiceResultArray = new Vector();
int intServiceResultCode = -42;
int intServiceProgressMarker = 0;
boolean boolOK = false;
boolean boolDebugL9On = false;
// Always debug on the test server.
boolDebugL9On = ((request.getServerName().trim().toLowerCase().compareTo("testserver") == 0) || boolDebugL9On);
try {
// Test data for push.
String strID = "111223499";
String strEmpNum = "890168";
String strLastName = "Tester12";
String strFirstName = "Sammy";
String strMiddleName = "P";
String strMaidenName = "";
String strDOB = "07/05/1988";
String strHireDate = "09/21/2012";
String strTitle = "VP of Testing";
String strAddressLine1 = "400 W. Jones Ave.";
String strAddressLine2 = "Hancock Building, Apt. C4";
String strCity = "myTown";
String strState = "WA";
String strPostalCode = "99999";
String strGLocNum = "12038";
String strOccGrp = "Facility";
// Init the factories.
SOAPConnectionFactory scfFactory = SOAPConnectionFactory.newInstance();
SOAPFactory sfFactory = SOAPFactory.newInstance();
MessageFactory mfFactory = MessageFactory.newInstance();
// Create the SOAP Connection.
SOAPConnection scTunnel = scfFactory.createConnection();
// Build the SOAP request message.
SOAPMessage smRequest = mfFactory.createMessage();
// Set the extra envelope attributes.
SOAPEnvelope seEnvelope = smRequest.getSOAPPart().getEnvelope();;
seEnvelope.setAttribute("xmlns:SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/");
seEnvelope.setAttribute("xmlns:SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/");
seEnvelope.setAttribute("xmlns:http", "http://schemas.xmlsoap.org/wsdl/http/");
seEnvelope.setAttribute("xmlns:soap", "http://schemas.xmlsoap.org/wsdl/soap/");
seEnvelope.setAttribute("xmlns:tns", "LLX_Service");
// Remove the SOAP message header, it is not needed in this case.
SOAPHeader shRequestHeader = smRequest.getSOAPHeader();
shRequestHeader.detachNode();
// Build the SOAP body element CheckProspect.
SOAPBody sbRequestBody = smRequest.getSOAPBody();
javax.xml.soap.Name nameRequestName = sfFactory.createName(strServiceCallName, "mns", "LLX_Service");
SOAPBodyElement sbeRequestElement = sbRequestBody.addBodyElement(nameRequestName);
// Add all child elements to the WS action element.
SOAPElement seComKey = sbeRequestElement.addChildElement("key");
seComKey.addTextNode("user");
SOAPElement seComPW = sbeRequestElement.addChildElement("pw");
seComPW.addTextNode("pass");
SOAPElement seEmpID = sbeRequestElement.addChildElement("id");
seEmpID.addTextNode("myid="+strID);
if (boolDebugL9On) {
// Debug code, writes xml to the log file.
System.out.println("");
smRequest.writeTo(System.out);
System.out.println("");
} // End if (boolDebugL9On)
URL urlWebService = new URL ("https://www.xxxxxxxxxxxx.com/xxxxxxxx/");
// Send the SOAP request message and get back the SOAP response message.
SOAPMessage smResponse = scTunnel.call(smRequest, urlWebService);
scTunnel.close();
if (boolDebugL9On) {
// Debug code, writes xml to the log file.
System.out.println("");
smResponse.writeTo(System.out);
System.out.println("");
} // End if (boolDebugL9On)
strServiceResultMsg = "Processing call.";
vecServiceResultArray = new Vector();
intServiceResultCode = -10000;
// Pull out the SOAP response body.
SOAPBody sbResponseBody = smResponse.getSOAPBody();
// Check for SOAP faults.
if (sbResponseBody.hasFault()) {
intServiceProgressMarker = 101; // Tracking information.
SOAPFault newFault = sbResponseBody.getFault();
strStatus = "SOAP FAULT:<br>";
strStatus += "<br>code = " + newFault.getFaultCodeAsName();
strStatus += "<br>message = " + newFault.getFaultString();
strStatus += "<br>actor = " + newFault.getFaultActor()+"<br>";
strServiceResultMsg = "WS call returned a fault.";
intServiceResultCode = -10001;
boolOK = false;
} else {
// Pull the response results element out of the SOAP response body.
java.util.Iterator iterRoot = sbResponseBody.getChildElements();
SOAPBodyElement sbeResponseRoot = (SOAPBodyElement) iterRoot.next();
Iterator iterElement = sbeResponseRoot.getChildElements();
strStatus = "SOAP Response:<br>";
do {
//org.apache.axis.message.MessageElement meResponseElement = (org.apache.axis.message.MessageElement) iterElement.next();
SOAPElement meResponseElement = (SOAPElement) iterElement.next();
String strElementName = meResponseElement.getLocalName();
String strElementValue = ((meResponseElement.getValue() == null) ? meResponseElement.toString() : meResponseElement.getValue());
if (strElementName.compareTo("outResultCode") == 0) {
// Check for success or failure.
intServiceResultCode = Integer.valueOf(strElementValue).intValue();
boolOK = (intServiceResultCode >= 0);
intServiceProgressMarker = (boolOK) ? 1 : 100; // Tracking information.
strStatus += "Response code came back as *" + strElementValue + "*<br>";
} else {
if (strElementName.compareTo("outResultMsg") == 0) {
strServiceResultMsg = strElementValue;
strStatus += "Response message came back as *" + strElementValue + "*<br>";
} else {
if (strElementName.compareTo("outResultData") == 0) {
strServiceResultMsg = strElementValue;
strStatus += "Response data came back as *" + strElementValue + "*<br>";
} else {
if (strElementName.compareTo("outData") == 0) {
strStatus += "Response data array came back : *" + strElementValue + "*<br>";
// Check for a data array.
if (iterRoot.hasNext()) {
// Load up vecServiceResultArray for later use.
SOAPBodyElement sbeResponseDataArray = (SOAPBodyElement) iterRoot.next();
java.util.Iterator iterDataArray = sbeResponseDataArray.getChildElements();
while (iterDataArray.hasNext()) {
//org.apache.axis.message.MessageElement meDataElement = (org.apache.axis.message.MessageElement) iterDataArray.next();
SOAPElement meDataElement = (SOAPElement) iterDataArray.next();
String strDataName = meDataElement.getLocalName();
String strDataValue = ((meDataElement.getValue() == null) ? meDataElement.toString() : meDataElement.getValue());
Vector vecRow = new Vector();
vecRow.add(strDataName);
vecRow.add(strDataValue);
vecServiceResultArray.add(vecRow);
} // End while (iterDataArray.hasNext())
} // End if (iterRoot.hasNext())
} else {
strStatus += "Unknown response element returned, it is called *"+strElementName+"* and holds *" + strElementValue + "*<br>";
} // End if (strElementName.compareTo("outData") == 0)
} // End if (strElementName.compareTo("outResultData") == 0)
} // End if (strElementName.compareTo("outResultMsg") == 0)
} // End if (strElementName.compareTo("outResultCode") == 0)
} while (iterElement.hasNext());
} // End if (sbResponseBody.hasFault())
} catch(Exception e) {
intServiceProgressMarker = 102; // Tracking information.
strStatus = "Error : "+((e.getMessage() != null) ? e.getMessage() : e.toString());
strStatus += "<br>";
boolOK = false;
StackTraceElement[] aryStackTrace = e.getStackTrace();
for (int intElement = 0; intElement < aryStackTrace.length; intElement++)
{
strStatus += aryStackTrace[intElement].toString();
strStatus += "<br>";
}
} // End try
out.write("\r\n");
out.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\r\n");
out.write("<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n");
out.write("\t<head>\r\n");
out.write("\t\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\r\n");
out.write("\t\t<title>Test Web Service</title>\r\n");
out.write("\t</head>\r\n");
out.write("\t\r\n");
out.write("\t<body>\r\n");
out.write("\t\t");
out.print(strStatus);
out.write("<br /><br />\r\n");
out.write("\t\t");
for (int intRow = 0; intRow < vecServiceResultArray.size(); intRow++) {
Vector vecRow = (Vector) vecServiceResultArray.elementAt(intRow);
out.write("<div><span>");
out.print(vecRow.elementAt(0));
out.write("</span> | <span>");
out.print(vecRow.elementAt(1));
out.write("</span></div>");
} // End for (int intRow = 0; intRow < vecServiceResultArray.size(); intRow++)
out.write("\r\n");
out.write("\t</body>\r\n");
out.write("</html>");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
Any ideas on why this is happening?
Ok, if anyone else runs up against this here is what I found and how I fixed it. Whitespaces, like new line and carriage return and tab in the body element screwed up parsing the child elements. To strip them out I replaced the following line:
SOAPMessage smResponse = scTunnel.call(smRequest, urlWebService);
with this code snip:
SOAPMessage smResponse2 = scTunnel.call(smRequest, urlWebService);
// strip off the newlines and CR's and tabs.
java.io.ByteArrayOutputStream baosHolder = new java.io.ByteArrayOutputStream();
smResponse2.writeTo(baosHolder);
String strSOAPMsg = baosHolder.toString().replaceAll("\n+","").replaceAll("\r+","").replaceAll("\t+","");
SOAPMessage smResponse = mfFactory.createMessage(new MimeHeaders(), new java.io.ByteArrayInputStream(strSOAPMsg.getBytes(java.nio.charset.Charset.forName("UTF-8"))));
That converted the javax.xml.soap.SOAPMessage to a string via the java.io.ByteArrayOutputStream object, replaced the offending chars, and wrapped it back up in a new SOAPMessage object that didn't have the whitespace and would parse normally.
That turned the response from this:
<?xml version="1.0" encoding="UTF-8" ?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<ns1:WS_TestResponse xmlns:ns1="LLX_Service">
<outResultCode xsi:type="xsd:int">-1</outResultCode>
<outResultMsg xsi:type="xsd:string">Invalid ID Value, record not found</outResultMsg>
<outResultData xsi:type="xsd:string">IsTermed=No</outResultData>
</ns1:WS_TestResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
to this:
<?xml version="1.0" encoding="UTF-8" ?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><SOAP-ENV:Body><ns1:WS_TestResponse xmlns:ns1="LLX_Service"><outResultCode xsi:type="xsd:int">-1</outResultCode><outResultMsg xsi:type="xsd:string">Invalid ID Value, record not found</outResultMsg><outResultData xsi:type="xsd:string">IsTermed=No</outResultData></ns1:WS_TestResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
If there is an easier way, I'd love to hear it.