How to enable multiple datasource in camel jdbc endpoint? - apache-camel

I want to enable camel load balancer for multiple datasource. Any one please let me how to enable multiple datasource in camel jdbc endpoint.
Thanks in advance!!
Here is my code. Creating multiple datasource in defaultcamelcontext.
SimpleRegistry simpleregistry = new SimpleRegistry();
Map<String, Object> ds = new HashMap<String, Object>();
ds.put("dataSource", mydataSource);
ds.put("dataSource1", mydataSource1);
simpleregistry.putAll(ds);
Camel camel = CamelExtension.get(system);
DefaultCamelContext defaultCamelContext = camel.context();
defaultCamelContext.setRegistry(simpleregistry);
My route builder pointing to multiple datasource:
from("direct:checkUser").setBody(simple("${body}"))
.loadBalance()
.failover()
.to("jdbc:dataSource?resetAutoCommit=false&outputType=SelectList","jdbc:dataSource1?resetAutoCommit=false&outputType=SelectList");
My requirement is if datasource is down my request need to redirect/pick automatically to datasource1. Please let me how to achieve it.

Separate the to, so they are individual
from("direct:checkUser").setBody(simple("${body}"))
.loadBalance().failover()
.to("jdbc:dataSource?resetAutoCommit=false&outputType=SelectList")
.to("jdbc:dataSource1?resetAutoCommit=false&outputType=SelectList");

Related

Camel 3 - Dynamic uri for deadLetterChannel

I'm trying to setup a smart JMS deadLetterChannel where the final uri of the DLQ is computed dynamically, depending on original queue name (eg adding a ".dead" suffix).
I have seen in the doc that it's possible by setting the CamelJmsDestinationName header.
Therefore, I tried this:
DefaultErrorHandlerBuilder dlc = deadLetterChannel("jms:queue:dummy")
.useOriginalMessage()
.maximumRedeliveries(2);
dlc.onPrepareFailure( exchange -> {
// Override destination
exchange.getMessage().setHeader("CamelJmsDestinationName", "jms:queue:test");
});
I have tried many different values for CamelJmsDestinationName :
"jms:queue:test"
"queue:test"
"test"
But none of them is working; the header is ignored and the exchange always goes to original uri ("queue:dummy").
What am I doing wrong ??
I'm using Camel 3.6 and camel-sjms2 component bound to an Artemis ActiveMQ broker:
#Resource(mappedName = "java:/ConnectionFactory")
private static ConnectionFactory connectionFactory;
#Produces
#ApplicationScoped
#Named("jms")
public final Sjms2Component createJmsComponent() {
Sjms2Component component = new Sjms2Component();
ConnectionResource pool = new ConnectionFactoryResource(poolSize, connectionFactory);
component.setConnectionResource(pool);
return component;
}

Apache Camel : using throttle : how to change the value of timePeriodMillis using a config file?

i use the throttle in apache camel blueprint : throttle timePeriodMillis="1000"
with constant = 4
i want to put the value of timePeriodMillis dynamically using placeholder.Is this possible?
See the documentation: http://camel.apache.org/using-propertyplaceholder.html
And the section Using Property Placeholders for Any Kind of Attribute in the XML DSL
Properties component can be used here
ex:
Properties properties = new Properties();
InputStream input = null;
public void configure() throws IOException {
CamelContext context = new DefaultCamelContext();
input = new FileInputStream("sample.properties");
properties.load(input);
System.out.println("CITY IS" +properties.getProperty("wl.city"));
String city = properties.getProperty("wl.city");

Spring RestTemplate and JSON how to ignore empty Arrays deserialization?

I am currently using Spring 4.1.6 with a RestTemplate to consume a third party webservice with JSON which I cannot change its behavior.I am using Jackson databind v2.6.0.
Problem: Sometimes the service returns for a member a hashmap {member:{"key":"value",...}} sometimes the same member is just an empty array {member:[]}. So I can not ignore the property by default.
Is there a way to configure the deserialization to ignore empty arrays? I saw a jackson property "WRITE_EMPTY_JSON_ARRAYS" but I am not quite sure how I can use it with my restTemplate and spring configuration.
Are there other possiblities e.g. use some combination of #JsonXXX Annotations? I saw #JsonSerialize which can be used on class level, but I don't like to write a deserializer for all my classes just to handle this situation (However if there is no other way of course I will do)
Example responses to llustrate the behavior of the service:
response with a hashmap
{"id":170,"categories":{"13":"caro"}}
response with empty array of the same member
{"id":170,"categories":[]}
Example of my RestTemplate usage:
BasicAuthRequestFactory requestFactory = new BasicAuthRequestFactory(httpClient);
restTemplate = new RestTemplate(requestFactory);
Article a = restTemplate.getForObject(new URI("http://..."), Article.class);
Error:
caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.LinkedHashMap out of START_ARRAY token
at [Source: java.io.PushbackInputStream#4aa21f9d; line: 1, column: 1456] (through reference chain: ResponseArticleWrapper["data"]->Article["categories"])
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
Example of my current annotated class:
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonInclude(Include.NON_NULL)
public class Article {
#JsonProperty("id")
private Integer id;
#JsonProperty("categories")
private Map<Integer,String> categories = new HashMap<Integer,String>();
}
Thank you in advance for any hints and examples.
Since jackson-databind 2.5 there is DeserializationFeature for handling this case. It's turned off by default, so you need to configure it in your ObjectMapper:
#Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, true);
return objectMapper;
}
You can see how the custom ObjectMapper for RestTemplate is configured here: How can we configure the internal Jackson mapper when using RestTemplate?
After you're done with the configuration, you can just let Spring wire it for you in your class:
#Autowired
private RestOperations restTemplate;
and use the provided restTemplate instance.

Apache Camel 2.13.1 MyBatis Transaction not rolled back

I have a scenario, where I have to first update a row in three tables, then insert a new row into each of those tables. All this should be in a single batch of statements and rollback if it fails.
Scenario below
e.g
statement1 = update table1;
statement2= update table2;
statement3 =update table3;
statement4 insert into table1;
statement5 insert into table2;
statement6 insert into tables3
The answer to the above question by the Camel Community was to use a Transactional Client, but now the issue is with the transaction not being rolled back on failure of one of the MyBatis statements.
E.g. Exception case:The first two updates were not rolled back on failure of the third one below:
.to("mybatis:userMapper.updatePerson?statementType=Update") --- Passed
.to("mybatis:userMapper.updateCertificate8?statementType=Update") ---- Passed
.to("mybatis:userMapper.updateApplicationGroup?statementType=Update") ---- Failed
**`Am I missing anything?`**
Camel Registry
SimpleRegistry registry = new SimpleRegistry();
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(
sqlSessionFactory.getConfiguration().getEnvironment()
.getDataSource());
registry.put("transactionManager",dataSourceTransactionManager);
SpringTransactionPolicy springTransactionPolicy = new SpringTransactionPolicy();
springTransactionPolicy.setTransactionManager(dataSourceTransactionManager);
springTransactionPolicy.setPropagationBehaviorName("PROPAGATION_REQUIRED");
registry.put("PROPAGATION_REQUIRED",springTransactionPolicy);
camelContext = new DefaultCamelContext(registry);
camelContext.setTracing(true);
camelContext.start();
Camel Route:
onException(JMSException.class)
.handled(true).maximumRedeliveries(0).end();
onException(IllegalArgumentException.class)
.handled(true).maximumRedeliveries(0).rollback("Rolling back the IllegalArgumentException")
.end();
onException(PersistenceException.class)
.handled(true).maximumRedeliveries(0).rollback("Rolling back the transaction")
.end();
onException(RollbackExchangeException.class)
.handled(false).maximumRedeliveries(0).process(new CamelTibcoMessageProcessor())
.end();
from("timer:foo?period=10000")
.policy("PROPAGATION_REQUIRED") .to("mybatis:userMapper.updatePerson?statementType=Update")
.to("mybatis:userMapper.updateCertificate8?statementType=Update")
.to("mybatis:userMapper.updateApplicationGroup?statementType=Update")
.to("mybatis:userMapper.insertPersonFromCAMSCTSBridge?statementType=InsertList&executorType=batch")
.end();
Figured it out, the solution is straightforward see link for Camel MyBatis and MyBatis-Spring .
Convert the Spring config to Java and you have it. Below is what I did and it worked fine.
Add mybatis-spring maven dependency to your pom.
**------------------Sample setup--------------------**
SimpleRegistry registry = new SimpleRegistry();
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass("oracle.jdbc.driver.OracleDriver");
cpds.setJdbcUrl("jdbc_url");
cpds.setUser("username");
cpds.setPassword("password");
TransactionAwareDataSourceProxy transactionAwareDataSourceProxy = new TransactionAwareDataSourceProxy(cpds);
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(transactionAwareDataSourceProxy);
registry.put("transactionManager",transactionManager);
ApplicationContext appContext = new ClassPathXmlApplicationContext();
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setConfigLocation(appContext.getResource("mapper/your_mybatis_config.xml"));
factoryBean.setDataSource(cpds);
SpringTransactionPolicy propagationRequired = new SpringTransactionPolicy();
propagationRequired.setTransactionManager(transactionManager);
propagationRequired.setPropagationBehaviorName("PROPAGATION_REQUIRED");
registry.put("PROPAGATION_REQUIRED",propagationRequired);
SpringTransactionPolicy propagationRequiredNew= new SpringTransactionPolicy();
propagationRequiredNew.setTransactionManager(transactionManager);
propagationRequiredNew.setPropagationBehaviorName("PROPAGATION_REQUIRES_NEW");
registry.put("PROPAGATION_REQUIRES_NEW",propagationRequiredNew);
camelContext = new DefaultCamelContext(registry);
camelContext.setTracing(true);
camelContext.start();
MyBatisComponent component = new MyBatisComponent();
component.setSqlSessionFactory(factoryBean.getObject());
camelContext.addComponent("mybatis", component);
camelContext.addRoutes(new SomeRoute());

Camel set CXF timeouts with Java DSL

I'm pretty new to camel and stuck with a problem.
I am trying to create a dynamic web service proxy (which is working) using the cxf endpoint. Everything is going well except I have no idea how to set the cxf endpoint timeouts using the Java DSL.
I have found many articles on how to do it using Spring configuration, but I am trying to achieve this by using only Java DSL.
Here is what I currently have , please could someone point me in the right direction on how to manipulate the CXF timeout's (connect/receive) using the Java DSL
public void configure() throws Exception
{
onException(Exception.class).handled(true).transform()
.method(MyExceptionHandler.class, "handleException");
CxfEndpoint inboundCxf = new CxfEndpoint();
inboundCxf.setAddress(soapProxyConfig.getBaseUrl()
+ soapProxyConfig.getAddress());
inboundCxf.setCamelContext(camelContext);
inboundCxf.setDataFormat(DataFormat.RAW);
inboundCxf.setServiceName(new QName(soapProxyConfig
.getTargetNamespace(), soapProxyConfig.getRemoteServiceName()));
inboundCxf.setPortName(new QName(soapProxyConfig.getTargetNamespace(),
soapProxyConfig.getRemotePortName()));
inboundCxf.setWsdlURL(soapProxyConfig.getRemoteWsdl());
SedaEndpoint sedaEndpoint = new SedaEndpoint();
sedaEndpoint.setConcurrentConsumers(100);
sedaEndpoint.setExchangePattern(ExchangePattern.InOut);
sedaEndpoint.setSize(100);
sedaEndpoint.setCamelContext(camelContext);
sedaEndpoint.setEndpointUriIfNotSpecified("seda:" + routeId + "-Queue");
Endpoint[] remoteEndpoints = new Endpoint[soapProxyConfig
.getRemoteUrls().size()];
for (int i = 0; i < soapProxyConfig.getRemoteUrls().size(); i++)
{
Endpoint endpoint = camelContext.getEndpoint(soapProxyConfig
.getRemoteUrls().get(i));
endpoint.setCamelContext(camelContext);
remoteEndpoints[i] = endpoint;
}
from(inboundCxf).routeId(routeId)
.routePolicy(new WebServiceRoutePolicy()).to(sedaEndpoint);
from(sedaEndpoint).routeId(routeId + "-Queue").loadBalance()
.roundRobin().to(remoteEndpoints).id("Out");
Ok, so after some testing and pulling my hair out I found that I was going about it the totally wrong way.
I dont need to set the inbound CXF timeout values, I just need to set the outbound http timeout value which gives me the desired timeout detecetion.
So now I have a route that looks like this
onException(Exception.class).handled(true).transform(
method(SoapExceptionHandler.class, "handleException"));
SedaEndpoint sedaEnpoint = createSedaEnpoint();
JettyHttpEndpoint jettyEnpoint = createJettyHttpEndpoint();
CxfEndpoint cxfEnpoint = createCxfEndpoint();
from(cxfEnpoint).routeId(getRouteName()).to(sedaEnpoint);
from(sedaEnpoint).to(jettyEnpoint)
.routeId(getRouteName() + "-endpoint");
And for anyone who wants to know how to set the timeout for the JettyProducer here we go
private JettyHttpEndpoint createJettyHttpEndpoint() throws Exception
{
JettyHttpComponent jettyComponent = new JettyHttpComponent();
jettyComponent.setCamelContext(camelContext);
jettyComponent.setHttpClientMinThreads(proxyConfig
.getMinRemoteClientThreads());
jettyComponent.setHttpClientMaxThreads(proxyConfig
.getMaxRemoteClientThreads());
JettyHttpEndpoint jettyEnpoint = new JettyHttpEndpoint(jettyComponent,
"jetty:http", new URI(proxyConfig.getTargetEndpointUrl()));
jettyEnpoint.setCamelContext(camelContext);
jettyEnpoint.setExchangePattern(ExchangePattern.InOut);
jettyEnpoint.setThrowExceptionOnFailure(false);
jettyEnpoint.getClient().setTimeout(
proxyConfig.getRemoteEndpointTimeout());
return jettyEnpoint;
}
With that configuration and setting the timeout in the Jetty endpoint I now get my configurable timeout :)

Resources