We are creating an application using Apache Camel 2.13.2 for routing messages from different protocols. This will be a service component and we would also like to embed a simple web ui for monitoring messages and see configuration.
I have created this UI using AngularJS but I am not really sure how I could use Apache Camel as a Web Server for this.
Help is greatly appreciated.
I had the same problem on my project and I used the jetty component to expose static resources. It is explained on my blog:
expose static resources with camel
To sum-up it is necessary to define a ResourceHandler on the jetty component in specifying the directory of resources.
Example how to serve static files using Camel:
from("jetty:http://0.0.0.0:9080/images/plotdot9-ls.png")
.to("direct:getPNG");
from("jetty:http://0.0.0.0:9080/images/plotdot9.png")
.to("direct:getPNG");
from("direct:getPNG").process(new Processor() {
public void process(Exchange exchange) throws Exception {
HttpExchange httpExchange = (HttpExchange) exchange;
String uri = httpExchange.getRequest().getRequestURI();
int fileLocn = uri.lastIndexOf('/');
String filename = uri.substring(fileLocn);
exchange.getOut().setHeader("Content-Type", "image/png");
exchange.getOut().setBody(getClass().getResourceAsStream("/images" + filename));
}
});
Source: Camel users group
Related
I am using camel to send message to an IBM MQQueue.
The MDB listening to this queue expects messages of the type com.ibm.jms.JMSMapMessage.
When I use camel producerTemplate, an exception is thrown.
I am doing this
producerTemplate.sendBody("wmq:queue",hashMap);
Exception data: java.lang.ClassCastException: com.ibm.jms.JMSMapMessage incompatible with javax.jms.ObjectMessage
So I tried Spring jmsTemplate, and it worked.
jmsTemplate.send(new MessageCreator() {
#Override
public Message createMessage(Session session)
throws JMSException {
return session.createObjectMessage((Serializable) sctHmap);
}
});
Question:
The jms component documentation says
It uses Spring's JMS support for declarative transactions, including
Spring's JmsTemplate for sending and a MessageListenerContainer for
consuming.
I tried with disabling camels auto conversion using mapJmsMessage=false.
I realised it would not help as it would have sent a hash map, I still got the same exception. Is there any way I can get the producerTemplate to work in the same way as JMSTemplate? ProducerTemplate seems to be more elegant, atleast in terms of my unit tests
It seems I misinterpreted the classcast exception message. Camel was correctly sending, com.ibm.jms.JMSMapMessage, the MDB at the consumer application was expecting javax.jms.ObjectMessage.
I resolved it by setting jmsMessageType=object in the endpoint URI. :)
I created a web service client to handle cxf soap web services with apache camel.
String serviceUri = "cxf:http://localhost:10000/myservice?serviceClass=" +
MyRequest.class.getCanonicalName();
from(uri).to("mock:xyz");
The web service receives the soap call but throws an exception since the request requires a handling for wss.
org.apache.cxf.binding.soap.SoapFault: MustUnderstand headers: [{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security] are not understood.
The reason is, that the service requires ws security, which can be seen by lloking at the request.
<SOAP-ENV:Header><wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" SOAP-ENV:mustUnderstand="1">
I found out that I need to implement an interceptor to handle header properties.
My questions:
How can I add an interceptor to handle the header attributes with Camel Java-DSL?
Will this be sufficient to get rid of the SOAP Fault?
You can do it through
cxfEndpointConfigurer option #see: Camel-CXF configuration
(I use Spring (it is much easier)), but I guess for DSL URI will look like:
String serviceUri = "cxf:http://localhost:10000/myservice?serviceClass=" +
MyRequest.class.getCanonicalName() +
"&cxfEndpointConfigurer="+ MyConfigurer.class.getCanonicalName();
by implementing org.apache.camel.component.cxf.CxfEndpointConfigurer you have ability to add an Interceptor inside configureServer method
server.getEndpoint().getInInterceptors().add(new MyJAASLoginInterceptor());
if you run your Camel in container with JAAS (like JBOSS) you can use extension from
org.apache.cxf.interceptor.security.JAASLoginInterceptor
with needed callback handler.
Simple example which validates user/password from WSS header against JBOSS users:
public class MyJAASLoginInterceptor extends javax.security.auth.callback.JAASLoginInterceptor {
#Override
protected CallbackHandler getCallbackHandler(String name, String password) {
return new org.apache.cxf.interceptor.security.NamePasswordCallbackHandler(name, password, "setCredential");
}
}
I have a project starts up with Spring Boot.
It has some restful API via Spring Integration inbound gateway.
Afterward, some webservice endpoint added to the project with CXF.
When I setup the CXFServlet mapping, all the restful API became 404.
Only I suspend the CXF config the restful API available again.
May I know if there is anything block the restful API or the spring integration inbound gateway during using CXF?
CXFServlet and Bus
#Configuration
#ComponentScan("com.kennie")
#ImportResource("classpath:cxf-services.xml")
public class SimbaAdapterApplicationConfiguration {
#Bean
public ServletRegistrationBean dispatcherServlet() {
return new ServletRegistrationBean(new CXFServlet(), "/ws/*");
}
#Bean(name=Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
SpringBus bus = new SpringBus();
bus.getInInterceptors().add(new LoggingInInterceptor());
bus.getOutInterceptors().add(new LoggingOutInterceptor());
return bus;
}
XML configuration
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<jaxws:server id="MyService" address="/ws/MyService"
serviceClass="com.kennie.IMyService" >
<jaxws:serviceBean>
<ref bean="myServiceImpl" />
</jaxws:serviceBean>
</jaxws:server>
Service Interface
#WebService
public interface IMyService{
#WebMethod
public #WebResult(name = "Response") Response doRequest(
#WebParam(name = "Request", mode = WebParam.Mode.IN)
Request request
);
}
I'm not familiar with CXF, but I know that Spring Integration HTTP is fully based on Spring MVC. So, if you can configure Spring MVC over CXF, all those Spring Integration HTTP Inbound Gateways will be available there as well.
I think your problem is somewhere with distinguishing Servlet mapping.
Looks like your REST API is routed through the CXF Servlet and that one doesn't like it, hence rejecting.
When you add CXF to your code, all the RESTful APIs will be routed through it.
I see two contradictory settings with the way you have configured CXF -
The url-mapping . You are injecting CXF with this code:
#Bean
public ServletRegistrationBean dispatcherServlet() {
return new ServletRegistrationBean(new CXFServlet(), "/ws/*");
}
Meaning the url at which CXF is listening is /ws/*.
The jax-ws server! Firstly, you need to change it to jax-rs . WS is for SOAP. RS is for Restful. You have defined its address as:
<jaxws:server id="MyService" address="/ws/MyService"
Meaning the server is listening at /ws/MyService
CXF and the jax-rs server are both listening at ws/ something. Now, this is not really a problem. You just need to add this to the URL you are hitting so that the complete URL is something like this:
http:<server>:<port>/<context-root>/<CXF Endpoint>/<jax-rs server address>/<REST API endpoint>
I am guessing you don't want ws appearing twice in the URL. Remove it from the jax-rs address.
Hope this helps.
You can register more one servlet for http rest api, this method is tested and OK:
#SpringBootApplication(
//scanBasePackages = {"com.huawei.manage"}
)
public class Application {
#Bean
public ServletRegistrationBean dispatcherServlet() {
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.scan("com.huawei.manage.hsf.controller");
DispatcherServlet rest_dispatcherServlet = new DispatcherServlet(applicationContext);
ServletRegistrationBean registrationBean = new ServletRegistrationBean(rest_dispatcherServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/*");
return registrationBean;
I am using Camel as an Orchestration Engine.
clients sends HTTP request <-> CAMEL code <---- HTTP Req----- > external
server(s)
I am using HTTP4 Component (with default settings) for making HTTP Requests
to external server. I have quite a few http backends.
Right now the way we are making http calls to our backend is as follow:-
// The producer is created during app initialisation. This is actually done
via blueprint.xml
ProducerTemplate producer = camelContext.createProducerTemplate();
// Whenever I need to make a http call I am executing the below code with
URL set as something like:- "http4://order-api:8099/orders/v1/ordersearch/"
Exchange exchange = producer.request(URL, new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
log.info("Executing the HTTP request : URL - " + URL + " Headers -
" + headers + " Body : " + body);
exchange.getIn().setHeaders(headers);
exchange.getIn().setBody(body);
}
});
The query I am having is:-
Does HTTP4 in the default setting camel uses some http connection
pooling while making a call to the external servers?
If yes Is there a way I can configure the connection pooling from
blueprint.xml?
I am using Camel 2.16.1 and the application is deployed in Karaf 3.0.5.
The http4 component use Apache HttpClient, which support pooling with the use of a HttpClientConnectionManager.
By default, camel uses a PoolingHttpClientConnectionManager which is configured with the properties connectionsPerRoute and maxTotalConnections.
If you want to have more control over this clientConnectionManager, you can provide your own implementation of org.apache.http.conn.HttpClientConnectionManager
See HttpClient connection manager
I have a web application with separate front and back:
/project
+--- /back
+--- /front
The back is developped using Spring boot + Spring MVC, while the front is using AngularJS.
I am trying to set up the security for the communication between the back/front. What I did:
- create a ConfigSecurity class which extends from WebSecurityConfigurerAdapter
- create a SpringWebMvcInitializer which extends from AbstractAnnotationConfigDispatcherServletInitializer and call ConfigSecurity
- create a SecurityWebInitializer class which extends AbstractSecurityWebApplicationInitializer
My ConfigSecurity looks like this:
#Configuration
#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class ConfigSecurity extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/demo/**","/home").permitAll()
.anyRequest().fullyAuthenticated()
.and()
.formLogin().loginPage("...")
.and()
.httpBasic();
}
}
My problems:
In configureGlobal(), I can set the username and password to access my protected urls, but how can I do when there is not only one single user? I mean, I want to grant access to all the users that are registered in my database.
Since the back and the front are only communicating with REST (through JSON files), what should be done with formLogin() in ConfigSecurity? By default, Spring Security generates a default login form. I don't need a it in the back of the application since it is the front which is responsible for displaying the loginPage. How can I skip the login page in the back? Maybe by putting the username and password in JSON file the front is sending to the back? Does someone know how it can be done?
I am using Java Configuration for Spring (not XML configuration).
You have many options, all of them require quite a lot of code, but most of it is already well implemented around the internet so you just would have to make it fit your needs. You can either go with simplest way which would be http sessions, JSON token or JWT (JSON web token) or anything else.
Spring blog has a very long post about how to implement different
solutions here:
https://spring.io/guides/tutorials/spring-security-and-angular-js/
JHipster also has different authentication methods which you can take a look at. They have very well implemented role security in front-end which I like a lot and would really suggest looking into: https://github.com/jhipster/jhipster-sample-app
Here's also a JWT which is requires the most code: http://blog.jdriven.com/2014/10/stateless-spring-security-part-2-stateless-authentication/
HTTP Sessions would definitely be the easiest to set up and is well supported by Spring Security out of the box already.
Found great help on this baeldung website (even though it is using XML configuration) and this website (using Java configuration).
For global explanation of how Spring security works, this link helps me a lot.