Apache Camel Multicast notifyBuilder fails - apache-camel

Of some reason, QUEUE_A does not ALWAYS has 1 exchanges - sometimes it has 0, unless I add a Thread.sleep(100) to the test. I guess whenCompleted/whenDone isn't completely done when it actually says it's done. How can I verify that it is completely done?
multicast().parallelProcessing().to(QUEUE_A, QUEUE_B, QUEUE_C, QUEUE_D)
And testing with:
#Test
public void test() {
NotifyBuilder notify = new NotifyBuilder(context)
.from(QUEUE_INCOMING)
.whenCompleted(1)
.create();
template.sendBody(QUEUE_INCOMING, streamToString(loadResourceAsStream("/data/TestData.xml")));
boolean matches = notify.matches(4, SECONDS);
assertTrue("Notify failed", matches);
Thread.sleep(100); //Without this, it fails
verifyEndpoints(1, context, QUEUE_A, QUEUE_B, QUEUE_C, QUEUE_D);
}
public static void verifyEndpoints(int expectedSize, ModelCamelContext context, String... endpoints) {
for (String endpoint : endpoints) {
BrowsableEndpoint be = context.getEndpoint(endpoint, BrowsableEndpoint.class);
assertThat(String.format("Endpoint exchanges '%s' has wrong size", endpoint), be.getExchanges(), hasSize(expectedSize));
}
}
And the endpoint bean, using ActiveMQ when testing, but is going to use WebSphere MQ in prod:
<bean id="wmq" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localhost?broker.persistent=false" />
</bean>
</property>
</bean>

The problem is that you browse a WMQ asap after sending a message to it, and therefore depending on broker implementation and timing etc, you may not see the very last messages, when using the JMS browsing api.
And hence why it seems to fix when you wait a bit with the sleep.

Related

how to use custom error handler with camel rest dsl?

I am trying to use my own complex error handler for a rest dsl route. With myErrorHandler I define my own handler and its works. If occur an exception my handler is called and do his stuff. At the end of the handler I clear my exchange:
private void clearExchange() {
exchange.getIn().reset();
exchange.setException(null);
exchange.getMessage().setHeader(Exchange.HTTP_RESPONSE_CODE, 500);
exchange.getIn().setBody("Server Error");
}
but my main problem is, I don’t get as client a response with status code 500. My Application show me the exception stacktrace. If I use simple onException in my camelcontext, its works but my error handler are not called. I thought if an exception occur, the exchange go to my error handler and after this he go back to the consumer.
<bean id="myErrorHandler" class="org.apache.camel.builder.DefaultErrorHandlerBuilder">
<property name="onExceptionOccurred" ref="myErrorProcess"/>
</bean>
<bean id="myErrorProcess" class="de.myErrorProcess">
<property name="PropertiesFilePath" value="conf\general.properties"/>
</bean>
<camel:camelContext errorHandlerRef="myErrorHandler" xmlns="http://camel.apache.org/schema/spring">
<routeContextRef ref="RouteA"/>
<restConfiguration component="jetty" host="0.0.0.0" scheme="http" port="80"
apiContextPath="api-doc" enableCORS="false">
<componentProperty key="useContinuation" value="false"/>
<dataFormatProperty key="prettyPrint" value="true"/>
</restConfiguration>
<rest>
<get id="getPing" uri="/ping">
<responseMessage code="200" responseModel="de.model.Ping" message="Ok"/>
<to uri="direct:ping"/>
</get>
</rest>
</camel:camelContext>

QPID Connection factory properties

My system is based on camel and use Apache QPID 0.37.0 to consume messages from a remote AMQPS sever. Our system authenticates via a client certificate. Thus I have this piece of configuration:
<bean id="jmsConnectionFactory" class="org.apache.qpid.jms.JmsConnectionFactory">
<constructor-arg name="remoteURI" value="amqps://some-location:5671?transport.keyStoreLocation=/very/long/path/nnn-openssl.p12&transport.keyStorePassword=*******&transport.trustStoreLocation=/very/long/path/server.keystore&transport.trustStorePassword=*******"/>
</bean>
This is just working fine. However, configuring key/trust store this way (i.e. in the URI) has several drawbacks:
First, it is not easy to read and maintain.
Some components log the URI, so the paths (I can live with it) and the passwords (ouch...) get logged.
I know it's possible to configure via a system property (javax.net.ssl.keyStore, and son on), but it's not an option because different modules may use different key and trust store, and we want to keep them in separate files.
Is there a way to configure those transport properties of JmsConnectionFactory in a different way ?
Something like:
<bean id="jmsConnectionFactory" class="org.apache.qpid.jms.JmsConnectionFactory">
<constructor-arg name="remoteURI" value="amqps://some-location:5671"/>
<property name="transport.keyStoreLocation" value="/very/long/path/nnn-openssl.p12"/>
...
</bean>
Note that this factory is used in a JMSConfig, which in turn is used within an AMQPComponent:
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration" >
<property name="connectionFactory" ref="jmsConnectionFactory" />
...
</bean>
<bean id="amqp" class="org.apache.camel.component.amqp.AMQPComponent">
<property name="testConnectionOnStartup" value="true"/>
<property name="configuration" ref="jmsConfig" />
...
</bean>
The short answer is no, that's all that class supports. However you could write a configuration bean which has the properties you require, and have that create the bean. Off the top of my head, something like this:
#Configuration
public class QpidConfiguration {
// Add setters for these
private String host;
private int port = 5671;
private String keyStore;
private String keyStorePassword;
private String trustStoreLocation;
private String trustStorePassword;
#Bean
public JmsConnectionFactory createConnectionFactory() {
return new JmsConnectionFactory("amqps://" + host" + ":" + port + "?transport.keyStoreLocation=" + keyStoreLocation + "&transport.keyStorePassword=" + keyStorePassword + "&transport.trustStoreLocation=" + trustStoreLocation + "&transport.trustStorePassword=" + trustStorePassword);
}
}
You probably want to add some parameter validation in there to be safe.
You can then define the bean using more convenient properties.
<bean id="jmsConnectionFactory" class="com.example.QpidConfiguration">
<property name="host" value="some-location"/>
<property name="keyStoreLocation" value="/very/long/path/nnn-openssl.p12"/>
...
</bean>
You can also leverage encrypted property placeholders, if your heart so desires.

Not working - Programmatic approach for CXF's Circuit-Breaker feature

As per the documentation - https://cwiki.apache.org/confluence/display/CXF20DOC/JAX-RS+Failover#JAX-RSFailover-Code.1, I tried running the following code along with associated configurations, but the circuit breaker mechanism is not opening up once the threshold count for connectivity failures have exceeded. As the circuit stays closed, the invocation attempts are still being accepted which is against expected behaviour.
public class CustomerRestClient {
private CustomerRestClientFactory customerRestClientFactory;
public List<Customer> filterByFirstName(String firstName) {
List<Customer> filteredCustomers = new ArrayList<>();
CircuitBreakerFailoverFeature cbFailoverFeature = new CircuitBreakerFailoverFeature(4, 180000L);
SequentialStrategy strategy = new SequentialStrategy();
cbFailoverFeature.setStrategy(strategy);
List<Feature> featureList = new ArrayList<Feature>();
featureList.add(cbFailoverFeature);
WebClient client = customerRestClientFactory.getClient(featureList).path("/");
// Call service to get all customers
List<Customer> customers = client.get(new GenericType<List<Customer>>() {});
return filteredCustomers;
}
public void setCustomerRestClientFactory(CustomerRestClientFactory customerRestClientFactory) {
this.customerRestClientFactory = customerRestClientFactory;
}
}
public class CustomerRestClientFactory implements InitializingBean {
private List providerList; // Value is injected by Spring
private String serviceUrl; // Value is injected by Spring
public WebClient getClient(List<? extends Feature> featureList) {
if (featureList == null || featureList.isEmpty()) {
throw new IllegalArgumentException("featureList is not initialized.");
}
JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
bean.setAddress(serviceUrl);
bean.setServiceClass(WebClient.class);
bean.setProviders(providerList);
bean.setFeatures(featureList);
return bean.createWebClient();
}
}
<bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat"> <constructor-arg type="java.lang.String" value="yyyy-MM-dd'T'HH:mm:ss"/>
</bean>
</property>
<property name="serializationInclusion">
<value type="com.fasterxml.jackson.annotation.JsonInclude.Include">NON_NULL</value>
</property>
</bean>
<bean id="jsonProvider" class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider">
<property name="mapper" ref="objectMapper"/>
</bean>
<util:list id="providerList">
<ref bean="jsonProvider" />
<bean name="exceptionHandler" class="com.mycompany.refapp.exception.AppExceptionHandler" />
</util:list>
<bean id="customerRestClientFactory" class="com.mycompany.refapp.client.CustomerRestClientFactory">
<property name="providerList" ref="providerList" />
<property name="serviceUrl" value="${customer.rest.service.url}" />
</bean>
Log containing stack traces (available here).
After a lot of debugging, I came to an understanding that the counter for connection failures never exceeds the threshold limit because the state of the data (including the counter) is specific to each of the WebClient objects, instantiated for each call. I assumed that if the same instance of a WebClient is used across multiple calls that fail, then the counter would have been updated and eventually open the circuit. Please find attached screenshot for details.
I would like to get a second opinion on whether my understanding is correct.
You have opened issue https://issues.apache.org/jira/browse/CXF-7663 in parallel, so I share the response from Colm here:
If you want to use the Circuit-Breaker feature then you need to use
the same Webclient instance for all of the invocations - it won't work
if you are creating a new WebClient per-call. Here's a test that shows
how it works:
https://github.com/coheigea/testcases/blob/218044e3126cff9339e27a69cd8d3c5f3fe308ea/apache/cxf/cxf-failover/src/test/java/org/apache/coheigea/cxf/failover/feature/FailoverTest.java#L90

how to do corrleationId copying at route level? and only if CorrelationID is not filled

My Usecase (in camel):
if incoming message has correlationId (say clientCorrId) => leave as such, do nothing, as clientCorrId is used by client to map response.
if incoming message do not have correlationId => take messageId and put it in correlationId (at route level, not in every route that uses "jms" component)
Copying correlationId should be done only at a route level
How to do corrleationId copying at route level? (not globally as in useMessageIDAsCorrelationID as below)
<bean id="jms" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="jmsConnectionFactory" />
<!--property name="useMessageIDAsCorrelationID" value="true" / WARNING! Do not use this as we need to copy only in the beginning not everywhere -->
<property name="transactionManager" ref="jpaTransactionManager" />
<property name="transacted" value="true" />
</bean>
I want to avoid having a separate bean code like this to copy correlationId ONLYIF it is empty:
if (EMPTY_MSG_ID.equals(currentCorrId)) {
log.info("No corrId set, setting msgId to corrid :" + msgId);
outHeader.put(correlationIdKey, msgId);
} else {
outHeader.put(correlationIdKey, currentCorrId);
log.info("CorrId already set: " + currentCorrId);
}
You can use an interceptor to intercept from jms endpoints, and add the missing id if needed. See http://camel.apache.org/intercept

Spring #Transactional and PROPAGATION_REQUIRES_NEW with sql server 2012

I have a service that has several methods marked with #Transactional, including methods a, b and c. These 3 methods are nested in the following way a -> b -> c. Here is a code sample:
#Transactional
public void a() {
while(condition) {
try {
b();
} catch(MyException e) {
logger.warn(e.getMessage());
}
}
}
Method b however is annotated like this:
#Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = {MyException.class})
However, when MyException is thrown from method c, the exception is caught at method a and when that exits, the transaction is comitted and that includes whatever has been done by call to b() that threw the exception and should have been rolled back(?).
I am using sql server 2012 express with spring 3.0.7 and my spring configuration is like this:
<tx:annotation-driven />
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<qualifier value="txm1"/>
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceXmlLocation" value="classpath:META-INF/jpa-persistence.xml"/>
<property name="persistenceUnitName" value="Unit1" />
</bean>
Method b seems to be in the same class as method a. If you're not using AspectJ, the #Transactional-annotations are handled by a JDK dynamic proxy, through which your calls from outside the class travel to method a. The call needs to travel through the proxy for the #Transactional-annotations to have effect, see for example here, under 'Understanding AOP proxies': http://static.springsource.org/spring/docs/3.0.0.M3/spring-framework-reference/html/ch08s06.html
The key thing to understand here is that the client code inside the
main(..) of the Main class has a reference to the proxy. This means
that method calls on that object reference will be calls on the proxy,
and as such the proxy will be able to delegate to all of the
interceptors (advice) that are relevant to that particular method
call. However, once the call has finally reached the target object,
the SimplePojo reference in this case, any method calls that it may
make on itself, such as this.bar() or this.foo(), are going to be
invoked against the this reference, and not the proxy. This has
important implications. It means that self-invocation is not going to
result in the advice associated with a method invocation getting a
chance to execute.

Resources