Here's the thing:
I am trying to set up a schema validation through cxf with a custom validation event handler.
My configuration looks something like this:
<cxf:cxfEndpoint id="personEndpoint" address="/person"
serviceClass="org.apache.servicemix.samples.wsdl_first.Person"
wsdlURL="wsdl/person.wsdl">
<cxf:properties>
<entry key="schema-validation-enabled" value="true" />
<entry key="jaxb-validation-event-handler">
<bean class="org.dpytel.servicemix.camel.MyCustomHandler" />
</entry>
</cxf:properties>
</cxf:cxfEndpoint>
This is working fine - the schema validation is checked and when errors are encountered, "MyCustomHandler" gets executed.
My problem is that I want to save the whole message that caused the validation error to a file, but inside "MyCustomHandler" I don't have this information available (only some error message and the location)
Is there some other way to validate schema with cxf and log the message if something goes wrong?
You can use CXF Fault Interceptor to access the message content while validation exception will cause a fault:
http://fusesource.com/docs/esb/4.4.1/cxf_interceptors/CXFInterceptorImplMessage.html
Related
I have written a camel route that is basically a proxy for an https web service. Below is my route
Please note that the https service responds with gzip encoding !!
<camel:sslContextParameters id="sslContext">
<camel:trustManagers>
<camel:keyStore resource="certificates/cert.jks" type="jks"
password="test"/>
</camel:trustManagers>
</camel:sslContextParameters>
<cxf:cxfEndpoint id="source"
wsdlURL="wsdl/SampleService.wsdl"
serviceClass="com.sample"
address="http://localhost:9000/SampleService">
<cxf:properties>
<entry key="dataFormat" value="PAYLOAD"/>
</cxf:properties>
</cxf:cxfEndpoint>
<cxf:cxfEndpoint id="target"
wsdlURL="wsdl/target.wsdl"
serviceClass="com.sample1"
address="https://endpoint">
<cxf:properties>
<entry key="dataFormat" value="PAYLOAD"/>
</cxf:properties>
<cxf:features>
<bean class="org.apache.cxf.transport.common.gzip.GZIPFeature"/>
</cxf:features>
<cxf:inInterceptors>
<bean class="org.apache.cxf.transport.common.gzip.GZIPInInterceptor"/>
</cxf:inInterceptors>
</cxf:cxfEndpoint>
<bean id="headerProcessor" class="com.sample.HeaderProcessor"/>
<bean id="defaultHostnameVerifier" class="com.sample.customHostNameVerifier"/>
<camel:camelContext xmlns="http://camel.apache.org/schema/spring" id="vediContext" streamCache="true">
<onException>
<exception>org.apache.cxf.binding.soap.SoapFault</exception>
<redeliveryPolicy maximumRedeliveries="0" redeliveryDelay="2000"/>
</onException>
<camel:route>
<camel:from uri="cxf:bean:source"/>
<camel:to uri="cxf:bean:target?sslContextParameters=#sslContext&hostnameVerifier=#defaultHostnameVerifier">
</camel:to>
</camel:route>
</camel:camelContext>
With this route, when I invoke the endpoint via SOAP UI, the first invocation is always successful, I get a valid response.
For any invocation after that, I always get the following exception :
<soap:Fault>
<faultcode xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/">ns0:Client</faultcode>
<faultstring>Couldn't create SOAP message due to exception: XML reader error: com.ctc.wstx.exc.WstxUnexpectedCharException: Illegal character ((CTRL-CHAR, code 31))
at [row,col {unknown-source}]: [1,1]</faultstring>
</soap:Fault>
This issue was caused due to the payload size being pretty big. Raising another question to seek help around working with large SOAP payloads when working with Apache Camel.
I've enabled my spring application to use transactions and annotated my service method accordingly but the changes to my DB persist when a RuntimeException is thrown.
My Spring configuration looks like this:
<!-- Data Source. -->
<jee:jndi-lookup id="dataSource" jndi-name="java:/jdbc/BeheermoduleDS"/>
<!-- JPA Entity Manager. -->
<jee:jndi-lookup id="entityManagerFactory" jndi-name="java:/jpa/BeheermoduleDS"/>
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
My datasource configuration in my jboss' configuration file looks like this:
<datasource jta="true" jndi-name="java:/jdbc/BeheermoduleDS" pool-name="BeheermoduleDS" enabled="true" use-java-context="true" use-ccm="true">
<connection-url>jdbc:sqlserver://localhost:1433;databaseName=Gebruikers;</connection-url>
<driver>sqljdbc</driver>
<security>
<user-name>jboss</user-name>
<password>*****</password>
</security>
</datasource>
My Service method looks like this:
#Transactional
public void authorise(Gebruiker user) {
user.setStatus(GebruikerStatus.Actief.name());
gebruikerRepo.save(user);
if (true) {
throw new RuntimeException("Exception happened just like that");
}
// does more stuff here that is never reached
}
My repository extends a spring data repository and looks like this:
public interface GebruikerRepository extends PagingAndSortingRepository<Gebruiker, Long>, QueryDslPredicateExecutor<Gebruiker> {
}
The transaction is thrown and caught by a controller which just shows a message to the user that an exception occurred. When I check my SQL Server DB, the change made to the user status have been commited.
Weren't they supposed to have been rolled back with the RuntimeException?
After turning debug on for org.springframework.transaction.interceptor I saw that no transactions are being started for my service method, but they are for a bunch of JpaRepository methods.
Also, this is how my persistence.xml looks like:
<persistence-unit name="BeheermodulePU" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<non-jta-data-source>java:/jdbc/BeheermoduleDS</non-jta-data-source>
Judging from the symptoms you describe you are scanning for the same classes twice. You probably have the same <context:component-scan /> in both the configuration of the ContextLoaderListener and DispatcherServlet.
You want the ContextLoaderListener to scan for everything but #Controller and the DispatcherServlet only for #Controllers. Leading to something like this.
For the ContextLoaderListener
<!-- Load everything except #Controllers -->
<context:component-scan base-package="com.myapp">
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
For the DispatcherServlet
<!-- Load everything except #Controllers -->
<context:component-scan base-package="com.myapp" use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
See also #Service are constructed twice for another sample and broader explanation.
I have a camel 'seda' route that contains code roughly:
JaxbDataFormat jaxb = new JaxbDataFormat(false);
jaxb.setContextPath("com.example.data.api");
from("seda:validate")
.marshal(jaxb)
.to("spring-ws:" + getDataServiceURL())
.unmarshal(jaxb)
I send an object from com.example.data.api, the JaxbDataFormat formatter sets it up as a SOAP request and passes it along wo spring-ws to actually send to my service. This works like a charm most of the time.
I say "most" because every now and then, spring-ws throws an exception like so:
org.springframework.ws.client.WebServiceTransformerException: Transformation error: Can't transform a Source of type javax.xml.transform.stax.StAXSource; nested exception is javax.xml.transform.TransformerException: Can't transform a Source of type javax.xml.transform.stax.StAXSource
at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:608)
at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:537)
at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:492)
at org.springframework.ws.client.core.WebServiceTemplate.sendSourceAndReceive(WebServiceTemplate.java:479)
at org.springframework.ws.client.core.WebServiceTemplate.sendSourceAndReceive(WebServiceTemplate.java:470)
at org.apache.camel.component.spring.ws.SpringWebserviceProducer.process(SpringWebserviceProducer.java:81)
at org.apache.camel.util.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:61)
at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:73)
The core of that is this error message: "Can't transform a Source of type javax.xml.transform.stax.StAXSource".
None of that makes sense. The Jaxb marshalling will have already made sure that the object in question is an XML string (according to any debug logging I do). Furthermore, this exact code works most of the time and only occasionally will fail. It appears random.
For instance, I ran a test just a few minutes ago where I sent a message into my route and got this error. I then restarted my service and resend the exact same message... and it worked like a charm. Same code; same environment; same test -- two different results.
It's this randomness that makes this so maddening. Any ideas what I should be looking for to making sure this never happens?
The issue is not with Camel but Spring-WS. Modifying the transformerFactoryClass in WS template config would work
<bean id="baseCamelMarshallerWSTemplate" class="org.springframework.ws.client.core.WebServiceTemplate" scope="prototype">
<constructor-arg ref="messageFactory" />
<property name="messageSender">
<ref bean="httpSender"/>
</property>
<property name="checkConnectionForError" value="true"/>
**<property name="transformerFactoryClass" value="com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"/>**
</bean>
If you still face the issue, please share spring WS config and a test case
I have created a web service endpoint using Apache CXF 2.5.2, but I am having some issues with schema validation and MTOM interacting. If I enable MTOM and schema validation I must use the base64Binary type directly, however I am trying to conform to a fixed spec where the MTOM field also has a "contentType" attribute.
<jaxws:properties>
<entry key="mtom-enabled" value="true"/>
<entry key="schema-validation-enabled" value="true"/>
</jaxws:properties>
Is it possible to only enable schema validation for inbound or outbound messages? For example something like:
<entry key="schema-validation-enabled" value="inbound"/>
Alternatively is there an alternate way of achieving this, such as overriding the outbound message validation?
Thanks.
Since Apache CXF 3.0 this is sort of possible. You can't disable the validation on an in/outbound basis, but you can ignore the validation errors selectively (so you're still getting the performance hit).
You configure reader (inbound) & writer (outbound) validation event handlers in the CXF configuration.
<jaxws:properties>
<!-- Validation of the SOAP Message-->
<entry key="schema-validation-enabled" value="true" />
<entry key="jaxb-reader-validation-event-handler">
<bean class="com.example.cxf.InboundValidationEventHandler" />
</entry>
<entry key="jaxb-writer-validation-event-handler">
<bean class="com.example.cxf.OutboundValidationEventHandler" />
</entry>
</jaxws:properties>
Create the ValidationEventHandlers like this and return true. Returning true informs CXF to ignore a single validation error and continue validation.
package com.example.cxf;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
public class InboundValidationEventHandler implements ValidationEventHandler {
public boolean handleEvent(ValidationEvent event) {
String message = event.getMessage();
Throwable t = event.getLinkedException();
System.out.println("Ignoring Inbound Validation EVENT : " + message);
// ignore
return true;
}
}
#InInterceptors(interceptors = "org.apache.cxf.interceptor.LoggingInInterceptor" )
#OutInterceptors(interceptors = "org.apache.cxf.interceptor.LoggingOutInterceptor")
public class SKTWeb implements SKTWebService {
// method logic goes here
}
Hi , after adding these two lines inside the CXF Method Implementation .
I could get whip of SOAP Requestand Response under tomcat server console
see a instance of SOAP Request Printed under Tomcat console
INFO: Inbound Message
----------------------------
ID: 1
Address: /Sktweb-33.0/services/SKTWeb
Encoding: UTF-8
Content-Type: text/xml; charset=UTF-8
Headers: {cache-control=[no-cache], content-type=[text/xml; charset=UTF-8], connection=[keep-alive], host=[local
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns4:strategy xmlns:ns
Could anybody please tell me how can get this inside my Log file (Log4j)
Currently this is my log4j.properties file
log4j.rootCategory=INFO, A1
# A1 is a DailyRollingFileAppender
log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A1.file=/Haieeee.log
log4j.appender.A1.datePattern='.'yyyy-MM-dd
log4j.appender.A1.append=true
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-22d{dd/MMM/yyyy HH:mm:ss} - %m%n
And also i have META-INF\cxf\org\apache\cxf\Logger Log4jLogger.class inside the Web Application .
And also i kept
<cxf:bus>
<cxf:features>
<cxf:logging/>
</cxf:features>
</cxf:bus>
Inside the endpoints.xml file
Any help please
A slight bit of confusion it seems. You need your assembled application to have a locatable file META-INF/cxf/org.apache.cxf.Logger (yes, those are dots! It's not a .java or .class file) and it should have the contents:
org.apache.cxf.common.logging.Log4jLogger
I use exactly the above in my code and it works like a charm. (I don't use it with the message logging feature though; too much traffic when deployed for my tasteā¦)
Basically you want your properties file to be picked by CXF then it use this properties file instead of CXF's.
I am using spring configuration in my CXF application. If you are not using any Spring config then you create a new config and load it on start up using spring context listener, then you can add the below code in your XML file.
<bean id="log4jInitialization"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="org.springframework.util.Log4jConfigurer" />
<property name="targetMethod" value="initLogging" />
<property name="arguments">
<list>
<value>file:fullpath/filename.properties</value>
</list>
</property>
</bean>
You can also have classpath:filename.properties in the <list> </list>. The logging implemented in Spring framework will be used to log all the request and response. You can also use the same logging implementation to use in your application.
Always go with interceptors...Add slf4j-log4j12-1.6.1.jar,slf4j-api-1.6.1.jar and commons-logging-1.1.1.jar. Paste the following code in your cxf.xml...
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor" id="loggingInInterceptor" />
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" id="logOutInterceptor" />
<cxf:bus>
<cxf:inInterceptors>
<ref bean="loggingInInterceptor" />
</cxf:inInterceptors>
<cxf:outInterceptors>
<ref bean="logOutInterceptor" />
</cxf:outInterceptors>
</cxf:bus>