Apache CXFRS and CAMEL configuration - cxfrs

i want to consume the REST result by hitting a REST web Service available at http://someotherhost site. i have written a proxy client for it
I want to hit the above REST service using apache CXFRS client and the write the result to a file. for which i am doing the following,could any one review the below and comment the things i have done wrong .
a) My camel context configuration with apache cxf is as below
<jaxrs:client address="http://someotherhost/test/" id="cityServiceClient" username="test"
password="pwd"
serviceClass="com.santosh.proxy.service.city.CityService">
<jaxrs:features>
<ref bean="loggingFeature" />
</jaxrs:features>
</jaxrs:client>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<package>com.santosh.routes</package>
<routeBuilder ref="cityserviceroutebuilder" />
</camelContext>
b) MY Proxy service Interface
#Path(value="/getCities")
public interface CityService {
#POST
#Produces(value="text/xml")
public String getCities(#QueryParam("countrycode") String countryCode);
}
c) Call to service
CityService cityService = (CityService) context.getBean("cityServiceClient");
cityService.getCities("ae");
d) Camel Routes
public class CityRoutes extends RouteBuilder {
public void configure() throws Exception {
//ROUTES
from("cxfbean:cityServiceClient")
.to("file://data/xmls/cities?fileName=test.xml");
}
}

I got the solution, basically my camel-context configuration was not up to that mark,
The below configuration solved my problem.
<! -- 4 THE ACTUAL SERVER WHICH WILL GET HIT -->
<jaxrs:server id="restService" depends-on="camelContext"
address="http://REALSERVER.COM/REST/" createdFromAPI="true"
staticSubresourceResolution="true">
<jaxrs:serviceBeans>
<ref bean="servicecity" />
</jaxrs:serviceBeans>
</jaxrs:server>
<bean name="servicecity" id="servicecity" class="com.santosh.CityServiceImpl" />
<! -- 3 YOUR PROXY CLIENT -->
<cxf:rsClient id="rsClient" address="http://REALSERVER.COM/REST/"
serviceClass="com.santosh.CityServiceImpl"
username="santosh" password="pwd" />
<! -- 1 JAXRS PROXY CLIENT -->
<jaxrs:client id="cityServiceClient" address="http://localhost:8123/REST/"
serviceClass="com.santosh.CityService" username="santosh" password="pwd">
</jaxrs:client>
<! -- 2 YOUR LOCAL SERVER THAT YOU NEED TO HIT, YOUR LOCAL SERVER -->
<cxf:rsServer id="rsServer" address="http://localhost:8123/REST/" serviceClass="com.santosh.CityServiceImpl" />
THE STEPS ARE
1) create JAXRS PROXY CLIENT and get it in your have code
CityService cityService = (CityService) context.getBean("cityServiceClient");
cityService.getCities("INDIA");
2) the above code will call the SERVER (LOCAL)
3) the above step will call YOUR PROXY CLIENT
4) the PROXY CLIENT will call the ACTUAL REAL SERVER

Related

Spring Boot Camel Test

I am writing a test for Camel using Spring boot.
Below is configuration on the test class
#RunWith(CamelSpringBootRunner.class)
#SpringBootApplication
#ComponentScan(basePackages = ["example.test"])
#UseAdviceWith
#BootstrapWith(SpringBootTestContextBootstrapper)
#DirtiesContext
class RouteTest {
private static final Logger LOGGER = LoggerFactory.getLogger(RouteTest.class)
#Autowired ModelCamelContext camelContext
#Test
void "flow"() {
camelContext.getRouteDefinition(route.routeId).adviceWith(camelContext, new AdviceWithRouteBuilder() {
#Override
void configure() throws Exception {
}
}
LOGGER.info("IN TEST: ******* Camel Status: "+camelContext.getStatus())
}
I expect camel should not be started. But when I run the test it is already started.
I noticed that CamelSpringBootRunner does start camel context in CamelSpringBootExecutionListener.
How do I force not to start the camel context.
In the latest version of camel there is an option for autoStartup of camel. You an achieve what you want by adding autoStartup option.
For example the route below is configured autoStartup=false to prevent Camel starting when Spring starts.
<camelContext id="myCamel" xmlns="http://camel.apache.org/schema/spring" autoStartup="false">
<route>
<from uri="direct:start"/>
<to uri="mock:result"/>
</route>
</camelContext>
You can manually start Camel later by invoking its start method as shown below:
ApplicationContext ac = ...
SpringCamelContext camel = (SpringCamelContext) ac.getBean("myCamel");
// now start Camel manually
camel.start();
If you are using older version of camel then autoStartup option will not work try using shouldStartContext instead.
Sometimes starting camel after setting shouldStartContext doesn't work so I have put the work around in below example. Try this :
setting shouldStartContext manually before starting the context from the code:
((SpringCamelContext)camelContext).setShouldStartContext(true);
camelContext.start();
Example context:
<camel:camelContext id="ids.camel.context" shouldStartContext="false">
<!-- Queue endpoints. -->
<camel:endpoint id="defaultInQueue" uri="jms:queue:${default.in.queue.name}"/>
<camel:endpoint id="defaultOutQueue" uri="jms:queue:${default.out.queue.name}"/>
<!-- Route to send messages to IDS -->
<camel:route id="out" trace="true">
<camel:from uri="direct:sender"/>
<!-- Do not expect answer (fire and forget) -->
<camel:setExchangePattern pattern="InOnly"/>
<camel:to ref="defaultOutQueue"/>
</camel:route>
<!-- Route to receive -->
<camel:route id ="in" trace="true">
<camel:from ref="defaultInQueue"/>
<camel:to uri="bean:defaultTextAdapter?method=onMessage"/>
</camel:route>
</camel:camelContext>
Using Camel 2.20.1 solved the issue

Spring data #transactional not rolling back with SQL Server and after runtimeexception

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.

cxf-rs-ws authorization under karaf

I'm trying to configure a cxf soap webservice with authorization and authentication to be deployed on Servicemix.
I configured the LDAP authentication module as follows:
<!-- Bean to allow the $[karaf.base] property to be correctly resolved -->
<ext:property-placeholder placeholder-prefix="$[" placeholder-suffix="]"/>
<jaas:config name="myRealm">
<jaas:module className="org.apache.karaf.jaas.modules.ldap.LDAPLoginModule" flags="required">
connection.url = ldap://srv-ldap:389
user.base.dn = ou=people,dc=intranet,dc=company,dc=com
user.filter = (uid=%u)
user.search.subtree = false
role.base.dn = ou=groups,dc=intranet,dc=company,dc=com
role.filter = (member:=uid=%u,ou=people,dc=intranet,dc=company,dc=com)
role.name.attribute = cn
role.search.subtree = true
authentication = simple
</jaas:module>
</jaas:config>
<service interface="org.apache.karaf.jaas.modules.BackingEngineFactory">
<bean class="org.apache.karaf.jaas.modules.properties.PropertiesBackingEngineFactory"/>
</service>
And here is the beans.xml file
<jaxws:endpoint id="myService"
implementor="com.myorg.services.impl.MyServiceWSImpl"
address="/myService">
<jaxws:inInterceptors>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken" />
<entry key="passwordType" value="PasswordText" />
</map>
</constructor-arg>
</bean>
<ref bean="authenticationInterceptor" />
<ref bean="authorizationInterceptor" />
</jaxws:inInterceptors>
<jaxws:properties>
<entry key="ws-security.validate.token" value="false" />
</jaxws:properties>
</jaxws:endpoint>
<bean id="authenticationInterceptor"
class="org.apache.cxf.interceptor.security.JAASLoginInterceptor">
<property name="contextName" value="myRealm" />
</bean>
<bean id="authorizationInterceptor"
class="org.apache.cxf.interceptor.security.SecureAnnotationsInterceptor">
<property name="securedObject" ref="securedBean"/>
</bean>
Finally, in my WebService implementation I annotated a method with #RolesAllowed.
#RolesAllowed("Role1")
public Department get(String name) throws IdMException {
return service.get(name);
}
The authentication interceptor is retrieving the user, authenticating it and retrieving the groups as RolePrincipal instances.
Then, in the authorization interceptor (SecureAnnotationsInterceptor), the method configuration is read, the expectedRoles are "Role1", but the SimpleAuthorizingInterceptor.isUserInRole method returns false.
I haven't found any example trying to do more or less the same and the few information I found was from the CXF documentation page http://cxf.apache.org/docs/security.html#Security-Authorization
I have to be missing something important, hope somebody could help me.
Thanks in advance and kind regards.
Your problem is because of Karaf's RolePricipal do not implements Group as CXF expected. Instead of it, it implements Pricipal so CXF thinks that 1st role name is a username. That is why "SimpleAuthorizingInterceptor.isUserInRole method returns false".
A solution is to wait for fixed versions of CXF (2.7.11 and 3.0.0).
If not possible to update to newer version, then an odd and temporary solution (simply workaround) is to add more than one role to a user in LDAP and to method.
You can find more about that bug here: CXF-5603

How to make CXF SOAP Request to be printed under log file

#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>

Loading a Service on startup of the ServiceMix 4.3 which consumes another service using ActiveMQ/Apache Camel

We are trying with ServiceA calling ServiceB as soon as bundle loads during the SericeMix startup. Service2 having activemq endpoints we need to invoke a method of that particular service. I tried by spring init-method attribute in the bean tag which helps in auto trigger a method in ServiceA in that method I am calling the serviceB’s method. I am getting Exception like No Consumer available for the endpoint. I assume that as soon as the Service1 is up it is not getting the instance of the service2 which needs to get initialized using #Produce annotation activemq endpoint. The same services work fine in the other normal scenarios.
Exception:
Caused by: org.apache.camel.CamelExchangeException: No consumers available on endpoint: Endpoint[direct://ServiceB]. Exchange[Message: BeanInvocation public java.lang.String java.lang.Object.toString() with null]]
at org.apache.camel.component.direct.DirectProducer.process(DirectProducer.java:46)
at org.apache.camel.component.bean.CamelInvocationHandler.invoke(CamelInvocationHandler.java:64)
... 35 more
I am copy pasting the Code Block for your reference.
public class ServiceA{
#Produce(uri = "direct:ServiceB") //Active MQ endpoint
private ServiceB serviceB;
public void start()
{
Object obj = serviceB.getData(); }
. . .
.....
}
}
**bundle-context.xml**
//Changes for method to auto trigger during spring bean load
<bean id="serviceA" class="com.test.serviceA" init-method="start">
</bean>
**bundle-context-camel.xml**
<osgi:camelContext id="ServiceA"
xmlns="http://camel.apache.org/schema/spring">
<template id="producerTemplate" />
<!-- These routes are outbound to other services -->
<route>
<from uri="ServiceB" />
<bean ref="enrichOutboundExchangeRef" />
<to uri="activemq:ServiceB?transferException=true" />
</route>
..............
</osgi:camelContext>
Or is their anyother way if i need to achieve this requirement? where i can load a service(consumes other services) automatically during the servicemix bootup.
You can use seda instead of direct as it's queue based and thus consumers can come and go.
Also try using springs depends-on attribute
<bean id="serviceA" depends-on="myCamel" .../>
<osgi:camelContext id="myCamel" ...>
We tried the above approach but we still we are getting exceptions, we resolved it by adding a listener to the onCamelContextStarted() during th init of the serviceA.
Thanks
Ravi
If you are getting "no consumers available on endpoint", it means that messages are being routed to an endpoint that hasn't been initialized. I recommend decoupling the services using a JMS queue between them. That way serviceA can put messages in the queue (independent of serviceB's availability) and serviceB can then act as a polling consumer against that queue whenever its ready.

Resources