Me hace ilusion, la verdad.
Realmente el que lo reporta soy yo. https://issues.apache.org/jira/browse/CXF-5527
En el foro.
Ha salido publicado en la version 2.7.9. Aqui su Release Notes.
Me hace ilusion, la verdad.
Realmente el que lo reporta soy yo. https://issues.apache.org/jira/browse/CXF-5527
En el foro.
Ha salido publicado en la version 2.7.9. Aqui su Release Notes.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> <context:annotation-config /> <context:component-scan base-package="es.depontevedra.cividas.rmi.connect" /> <bean id="cividasE" class="org.springframework.remoting.rmi.RmiProxyFactoryBean"> <property name="serviceUrl" value="rmi://${cividas.server.host}:${cividas.server.port}/${cividas.server.name}" /> <property name="serviceInterface" value="com.ontimize.locator.EntityReferenceLocator" /> <property name="refreshStubOnConnectFailure" value="true" /> </bean> <bean id="cividasU" class="org.springframework.remoting.rmi.RmiProxyFactoryBean"> <property name="serviceUrl" value="rmi://${cividas.server.host}:${cividas.server.port}/${cividas.server.name}" /> <property name="serviceInterface" value="com.ontimize.locator.UtilReferenceLocator" /> <property name="refreshStubOnConnectFailure" value="true" /> </bean> <bean id="cividasRemoteEntity" class="es.depontevedra.cividas.rmi.connect.CividasRemoteEntity"> <property name="user" value="${cividas.server.user}" /> <property name="pass" value="${cividas.server.pass}" /> <property name="host" value="${cividas.server.host}" /> <property name="port" value="${cividas.server.port}" /> <property name="name" value="${cividas.server.name}" /> </bean> <bean id="cividasEntity" class="es.depontevedra.cividas.rmi.connect.CividasEntity"> <property name="user" value="${cividas.server.user}" /> <property name="pass" value="${cividas.server.pass}" /> <property name="host" value="${cividas.server.host}" /> <property name="port" value="${cividas.server.port}" /> <property name="name" value="${cividas.server.name}" /> </bean> </beans>
depues en la clase que implemntes capturas:
public class CividasConnection { private static final Logger LOGGER = LoggerFactory.getLogger(CividasConnection.class); @Autowired private EntityReferenceLocator cividas; @Autowired private UtilReferenceLocator cividasUtil;
He encontrado documentacion de como crear los mensajes SoapFaul con el detalle como si fuese un XML. Pero ninguno que indique el procedimiento contrario. Tengo un SOAPFault con un xml en el detail y lo quiero serializar.
Este es el mensaje que me llega desde el WebService al que me conecto:
<?xml version='1.0' encoding='UTF-8'?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <soapenv:Fault> <faultcode>soapenv:Server</faultcode> <faultstring>0301 - Organismo no autorizado 'P3600000H' 'CDISFWS01'</faultstring> <faultactor>CDISFWS01</faultactor> <detail> <Atributos xmlns="http://www.map.es/scsp/esquemas/V2/soapfaultatributos"> <IdPeticion>1390408700541</IdPeticion> <NumElementos>1</NumElementos> <TimeStamp>2014-01-22T17:37:49.601+01:00</TimeStamp> <Estado> <CodigoEstado>0301</CodigoEstado> <CodigoEstadoSecundario /> <LiteralError>Organismo no autorizado 'P3600000H' 'CDISFWS01'</LiteralError> <TiempoEstimadoRespuesta>0</TiempoEstimadoRespuesta> </Estado> <CodigoCertificado>CDISFWS01</CodigoCertificado> </Atributos> </detail> </soapenv:Fault> </soapenv:Body> </soapenv:Envelope>
Como lo trato:
public String realizarConsulta(String datosPeticion) { try { // llamada al servicio, la parte, en la que va todo bien. // ... } catch (Exception e) { if(e instanceof javax.xml.ws.soap.SOAPFaultException){ javax.xml.soap.SOAPFault fault = ((javax.xml.ws.soap.SOAPFaultException) e).getFault(); es.map.scsp.esquemas.v2.soapfaultatributos.Atributos atributos = getSoapfaultatributo(fault); if(atributos != null){ String codigoEstado = atributos.getEstado().getCodigoEstado(); String literalError = atributos.getEstado().getLiteralError(); return errorMesagge(codigoEstado, literalError); }else{ String faultCode = fault.getFaultCode(); String faultString = fault.getFaultString(); return errorMesagge(faultCode, faultString); } }else{ LOGGER.error("ERROR", e); return errorMesagge(null, e.getMessage()); } } } @SuppressWarnings("unchecked") private es.map.scsp.esquemas.v2.soapfaultatributos.Atributos getSoapfaultatributo(javax.xml.soap.SOAPFault fault) { es.map.scsp.esquemas.v2.soapfaultatributos.Atributos atributos = null; try { javax.xml.soap.Detail detail = fault.getDetail(); if(detail != null){ Iterator<DetailEntry> iterator = detail.getDetailEntries(); while(iterator.hasNext()){ DetailEntry detailEntry = (DetailEntry) iterator.next(); Document document = detailEntry.getOwnerDocument(); DOMImplementationLS domImplLS = (DOMImplementationLS) document .getImplementation(); LSSerializer serializer = domImplLS.createLSSerializer(); String str = serializer.writeToString(detailEntry); str = str.replace("UTF-16", "UTF-8"); LOGGER.trace("detailEntry: "+ str); Object xmlBinderObjeto = xmlBinder.unmarshal(str); if(xmlBinderObjeto instanceof es.map.scsp.esquemas.v2.soapfaultatributos.Atributos){ atributos = (es.map.scsp.esquemas.v2.soapfaultatributos.Atributos) xmlBinderObjeto; } } } } catch (Exception e) { LOGGER.warn("ERROR al deserializar ATRIBUTOS del SOAPFault. ", e); } return atributos; }
Ahora bien, por ejemplo, no tienes el xsd del mensaje o te lo han cambiado si avisar…
@SuppressWarnings("unchecked") @Override public String realizarConsulta(String datosPeticion) { try { // llamada al servicio, la parte, en la que va todo bien. // ... } catch (Exception e) { if(e instanceof javax.xml.ws.soap.SOAPFaultException){ javax.xml.soap.SOAPFault fault = ((javax.xml.ws.soap.SOAPFaultException) e).getFault(); String faultCode = fault.getFaultCode(); String faultString = fault.getFaultString(); LOGGER.info("faultCode: "+faultCode); LOGGER.info("faultString: "+faultString); javax.xml.soap.Detail detail = fault.getDetail(); if(detail != null){ Iterator<DetailEntry> iterator = detail.getDetailEntries(); while(iterator.hasNext()){ DetailEntry detailEntry = (DetailEntry) iterator.next(); String NamespaceUri_soapfaultatributos = "http://www.map.es/scsp/esquemas/V2/soapfaultatributos"; if(NamespaceUri_soapfaultatributos.equalsIgnoreCase(detailEntry.getElementQName().getNamespaceURI())){ Iterator<?> it = detailEntry.getChildElements(); String codigoEstado = null; String literalError = null; String idPeticion = null; String timeStamp = null; while(it.hasNext()){ Object object = it.next(); if(object instanceof SOAPElement){ SOAPElement element = (SOAPElement) object; String name = element.getLocalName(); if("IdPeticion".equalsIgnoreCase(name)){ idPeticion = element.getValue(); LOGGER.info("IdPeticion: "+idPeticion); }else if("TimeStamp".equalsIgnoreCase(name)){ timeStamp = element.getValue(); LOGGER.info("TimeStamp: "+timeStamp); }else if("Estado".equalsIgnoreCase(name)){ Iterator<?> itElements = element.getChildElements(); while(itElements.hasNext()){ Object objeto = itElements.next(); if(objeto instanceof SOAPElement){ SOAPElement elementHijo = (SOAPElement) objeto; String nameHijo = elementHijo.getLocalName(); if("CodigoEstado".equalsIgnoreCase(nameHijo)){ codigoEstado = elementHijo.getValue(); LOGGER.info("CodigoEstado: "+codigoEstado); }else if("LiteralError".equalsIgnoreCase(nameHijo)){ literalError = elementHijo.getValue(); LOGGER.info("LiteralError: "+literalError); } } } } } } } } } return errorMesagge(faultCode, faultString); }else{ LOGGER.error("ERROR", e); return errorMesagge(null, e.getMessage()); } } }
Ni decir falta que habria que refactorizar un poco 😉 jeje.
Mediante el siguiente comando obtienes el certificado del servidor. De esta manera puedes añadir el certificado, el que lo firma (que debe ir tambien en el certificado), en el fichero cacerts de java.
openssl s_client -showcerts -connect server:port > ./certificadoServidor.cer </dev/null
muy facil e intuitivo:
Post original de Emerson Miranda
Lo copio y pego, para no tardar en buscarlo
public static void printStackTrace() { System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); StackTraceElement[] stack = Thread.currentThread().getStackTrace(); for(int pos=stack.length - 1; pos > 1; pos--){ StackTraceElement elem = stack[pos]; //se elimina el paquete del nombre de la clase String name = elem.getClassName().substring(elem.getClassName().lastIndexOf(".") + 1 ); System.out.println(name + "." + elem.getMethodName() + ":" + elem.getLineNumber()); if(pos > 2)System.out.print("->"); } System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); }
Cuando sucede un error en un servicio web. Se devuelve un mensaje SoapFault. Indicando codigo y error. Pero no tenemos traza del error. Si quieres que tu servicio devuelva tambien la traza de error en el mensaje SoapFault debes indicarlo asi:
<jaxws:endpoint address="/consultarIdentidad" id="mockConsulta" wsdlLocation="wsdl/ConsultaIdentidad.wsdl" implementor="es.depontevedra.soap.interoperabilidad.identidad.services.paxase.ConsultaIdentidad"> <jaxws:properties> <entry key="exceptionMessageCauseEnabled" value="true" /> <entry key="faultStackTraceEnabled" value="true" /> </jaxws:properties> </jaxws:endpoint>
faultStackTraceEnabled: es la parte stack trace de la excepcion.
exceptionMessageCauseEnabled: es la parte Caused by:…
En cxf cuando firmamos, encriptamos… los mensajes SOAP, tanto cliente como servidor, deben de comprobar siempre que la cabecera esta firmada, o encriptada o … Pero que pasa cuando los mensajes SOAPFault no estan firmados, o encriptados o …
Pues que hay un error indicando: org.apache.cxf.binding.soap.SoapFault: No SIGNED element found matching XPath /soapenv:Envelope/soapenv:Body
Como indicar a CXF que no intente comprobar la seguridad de los mensajes que son SoapFault:
<cxf:bus> <cxf:features> <cxf:logging /> </cxf:features> <cxf:inInterceptors> <ref bean="checkResponse" /> <bean class="org.apache.cxf.ws.security.wss4j.DefaultCryptoCoverageChecker"> <property name="checkFaults" value="false"/> </bean> </cxf:inInterceptors> <cxf:outInterceptors> <ref bean="SignRequest" /> </cxf:outInterceptors> </cxf:bus>
Jira en CXF informando y solucionando este bug.
Tengo un servicio que hace de proxy. La peticion que le llega la envia a otro Servicio Web y este otro devuelve la respuesta.
Por un lado tengo un modulo: cliente-servicio_externo.
Por otro lado tengo el modulo: servidor-proxy.
El cliente es una dependencia del servidor-proxy, para que mediante la configuracion de Spring, llamar al servicio externo.
<cxf:bus bus="clientPaxaseBus"> <cxf:features> <cxf:logging /> </cxf:features> <cxf:inInterceptors> <ref bean="checkResponse" /> <bean class="org.apache.cxf.ws.security.wss4j.DefaultCryptoCoverageChecker" /> </cxf:inInterceptors> <cxf:outInterceptors> <ref bean="SignRequest" /> </cxf:outInterceptors> </cxf:bus> <jaxws:client id="clientPaxaseConsultaIdentidad" address="#{url}/consultarIdentidad" bus="clientPaxaseBus" serviceClass="es.map.xml_schemas.PeticionPortType"/>
Pongo una configuracion de BUS generica, para todos los clientes. Especifico el nombre del bus: bus=»clientPaxaseBus».
<bean id="logInbound" class="org.apache.cxf.interceptor.LoggingInInterceptor" /> <bean id="logOutbound" class="org.apache.cxf.interceptor.LoggingOutInterceptor" /> <bean id="cdi" class="es.depontevedra.soap.interoperabilidad.identidad.services.spi.ConsultaIdentidadEnPaxase" /> <jaxws:endpoint id="cdiService" implementor="#cdi" address="/consultaidentidad" publishedEndpointUrl="http://${service.host}:${service.port}/${service.wsname}/consultaidentidad"> <jaxws:inFaultInterceptors> <ref bean="logInbound" /> </jaxws:inFaultInterceptors> <jaxws:inInterceptors> <ref bean="logInbound" /> </jaxws:inInterceptors> <jaxws:outFaultInterceptors> <ref bean="logOutbound" /> </jaxws:outFaultInterceptors> <jaxws:outInterceptors> <ref bean="logOutbound" /> </jaxws:outInterceptors> </jaxws:endpoint>
Evito la configuracion bus, poniendo los interceptors a mano en cada endpoint. No he sido capaz de generar un cxf:bus generico nombrando o etiquetandolo de alguna manera. Esta solucion no me gusta, pero funciona. A ver si encuentro una manera mas limpia…