Camel does not delete camelLock file after finishing route test - java

I'm learning Apache camel from the "Camel in Action" book and currently I'm on data transformation. More particularly Content Enricher EIP. I noticed that when I run the code below from the book Camel creates fileName + .camelLock file but it doesn't remove it after finishing route.
Is there something wrong from the code side ? Or it should work like that ?
import java.io.File;
import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.processor.aggregate.AggregationStrategy;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Test;
public class OrderToCsvProcessorTest extends CamelTestSupport {
#Test
public void testOrderToCsvProcessor() throws Exception {
// this is the inhouse format we want to transform to CSV
String inhouse = "0000004444000001212320091208 1217#1478#2132";
template.sendBodyAndHeader("direct:start", inhouse, "Date", "20091208");
File file = new File("target/orders/received/report-20091208.csv");
assertTrue("File should exist", file.exists());
// compare the expected file content
String body = context.getTypeConverter().convertTo(String.class, file);
assertEquals("000000444,20091208,000001212,1217,1478,2132\nthis,is,sample,string", body);
}
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from("direct:start")
.process(new OrderToCsvProcessor())
.pollEnrich("file://target/input?noop=true",
new AggregationStrategy() {
#Override
public Exchange aggregate( Exchange oldExchange, Exchange newExchange) {
if (newExchange == null) {
return oldExchange;
}
String http = oldExchange.getIn().getBody(String.class);
String ftp = newExchange.getIn().getBody(String.class);
String body = http + "\n" + ftp;
oldExchange.getIn().setBody(body);
return oldExchange;
}
})
.to("file://target/orders/received?fileName=report-${header.Date}.csv");
}
};
}
}
Processor which is used in code:
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
public class OrderToCsvProcessor implements Processor {
public void process(Exchange exchange) throws Exception {
String custom = exchange.getIn().getBody(String.class);
String id = custom.substring(0, 9);
String customerId = custom.substring(10, 19);
String date = custom.substring(20, 29);
String items = custom.substring(30);
String[] itemIds = items.split("#");
StringBuilder csv = new StringBuilder();
csv.append(id.trim());
csv.append(",").append(date.trim());
csv.append(",").append(customerId.trim());
for (String item : itemIds) {
csv.append(",").append(item.trim());
}
exchange.getIn().setBody(csv.toString());
}
}

GenericFileOnCompletion is in charge of deleting the lock file. You need to handoverCompletions in AggregationStrategy just like this.
new AggregationStrategy() {
#Override
public Exchange aggregate( Exchange oldExchange, Exchange newExchange) { if (newExchange == null) {
return oldExchange; }
String http = oldExchange.getIn().getBody(String.class); String ftp = newExchange.getIn().getBody(String.class);
String body = http + "\n" + ftp;
oldExchange.getIn().setBody(body);
newExchange.handoverCompletions(oldExchange);
return oldExchange; } })

The issue is due to the fact that you are pulling a file using pollEnrich with a custom AggregationStrategy.
When using a custom AggregationStrategy in this use case, then certain properties of the aggregated Exchange need to be copied over to the original Exchange for the Camel markerFile to be deleted correctly
So, at the end of your AggregationStrategy you can do :
oldExchange.getProperties().putAll(newExchange.getProperties());
Source : https://access.redhat.com/solutions/2189891

Related

can't parse my Json object received with binders in spring cloud stream

I have a problem with Json converter, I am sending a Json object in rabbitmq with spring cloud stream, when i try to listen to that object and convert it to a java object.
here is where i receive the object :
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.Ebanking.transactionservice.entities.Transaction;
import org.Ebanking.transactionservice.repositories.TransactionRepository;
import org.Ebanking.transactionservice.services.TransactionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
#EnableBinding(Sink.class)
public class TransactionServiceImpl implements TransactionService {
#Autowired
TransactionRepository transactionRepository;
#Override
#StreamListener(target = Sink.INPUT)
public void listen(String payload) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Transaction transaction = mapper.readValue(payload,Transaction.class);
transactionRepository.save(transaction);
System.out.println("Transaction registered Successfully");
}
}
here is from where i send the object :
#StreamListener(target = Processor.INPUT)
#SendTo(Processor.OUTPUT)
public String processTransaction(Transaction transaction) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Long idDebi = transaction.getAccountId();
Long idCred = transaction.getAccountIdDestination();
Double amount = transaction.getAmount();
String str = mapper.writeValueAsString(transaction);
if (debitAccount(idDebi, amount).equals(true) && creditAccount(idCred, amount).equals(true)) {
processor.output().send(MessageBuilder.withPayload(str).setHeader("treatedTran","treatment").build());
return "transaction treated successfully";
}
else return "transaction failed";
} ```
?
You are not sending a Transaction object; you are simply sending Strings
public String processTransaction(
...
return "transaction treated successfully";
}
else return "transaction failed";

Apache Camel - Unable to propagate JMS Header Properties between Request - Response

I am trying to save a value on the Camel Exchange between a Request - Response invocation against a QPID endpoint.
You can see from my code that I set a Header (and Property) before i invoke the Endpoint. Upon return the same Header and Property Values are null.
I basically want to keep a track of the fileName and filePath so that I can write the results into the same location
Really struggling with this.
import org.apache.camel.builder.RouteBuilder;
import org.springframework.beans.factory.annotation.Value;
public class ProcessingRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
//#formatter:off
from("file:/home/molko/in/?recursive=true&include=.*.txt")
.log("File read from disk : ${file:name}")
.doTry()
.setHeader("JMSReplyTo", constant("response-1"; {create:always, node:{type:queue}}"))
.setHeader("JMSCorrelationID", constant(java.util.UUID.randomUUID().toString()))
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
final String fileParent = exchange.getIn().getHeader("CamelFileParent", String.class);
final String endPath = fileParent.substring(fileParent.lastIndexOf('/') + 1);
exchange.getIn().setHeader("endPath", endPath);
exchange.setProperty("endPath", endPath);
}
})
.to(amqp:request-1;{node:{type:queue}}?preserveMessageQos=true?exchangePattern=InOut")
.doCatch(Exception.class)
.log("Failed : ${file:name}")
.log("${exception.stacktrace}")
.stop();
from("amqp:response-1; {create:always, node:{type:queue}}")
.log("Received from qpid broker : ${date:now}")
.doTry()
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
byte[] response = exchange.getIn().getBody(byte[].class);
System.out.println("properties : " + exchange.getProperties());
System.out.println("headers : " + exchange.getIn().getHeaders());
}
})
.to("file:/home/molko/out")
.doCatch(Exception.class)
.log("Failed from qpid brokre : ${date:now}")
.log("${exception.stacktrace}")
.stop();
//#formatter:on
}
}
includeAllJMSXProperties is probably what you are looking for ,
Camel 2.11.2/2.12: Whether to include all JMSXxxx properties when
mapping from JMS to Camel Message. When set to true properties such as
JMSXAppID, and JMSXUserID etc will be included. Note: If you are using
a custom headerFilterStrategy then this option does not apply.
Source : https://camel.apache.org/jms.html

MQTT / Camel / Custom header parameters

So, the problem:
i need to send some custom value in the header via Apache Camel/MQTT.
Code example:
import java.util.Map;
import org.apache.camel.CamelContext;
import org.apache.camel.Message;
import org.apache.camel.impl.DefaultCamelContext;
public class MQTTEntryPoint {
private static final String BASE = "mqtt:test?host=tcp://ip_address&";
private static final String SUBSCRIBER = BASE + "subscribeTopicName=test2";
private static final String PUBLISHER = BASE + "publishTopicName=test2";
public static void main(String[] args) {
CamelContext camelContext = new DefaultCamelContext();
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
Message message = camelContext.createConsumerTemplate().receive(SUBSCRIBER).getIn();
String body = message.getBody(String.class);
System.out.println(body);
Map<String, Object> headers = message.getHeaders();
for (String key : headers.keySet()) {
System.out.println("Header key: " + key + ", Header value: " + headers.get(key));
}
}
});
thread.start();
camelContext.createProducerTemplate().sendBodyAndHeader(PUBLISHER, "some body value", "headerKey",
"some header value");
}
}
In system out i can see only:
some body value
Header key: CamelMQTTSubscribeTopic, Header value: test2
As you can see, sending of custom header value does not works. What is wrong?
The MQTT protocol AFAIR only supports a single payload without any additional headers.

Woocommerce REST API with scribes-java library returns consumer key param missing error message

Hi guys I am trying to use scribe-java library to access the REST api via http.code looks
package org.scribe.examples;
import java.util.*;
import org.scribe.builder.*;
import org.scribe.builder.api.*;
import org.scribe.model.*;
import org.scribe.oauth.*;
public class WooCommerceOauth1Example {
private static final String RESOURCE_URL = "http://WEBSITE.COM/wc-api/v1/orders";
public static void main(String[] args) {
OAuthService service = new ServiceBuilder().provider(OneLeggedApi10.class)
.apiKey("ck_SOME_NUMBER")
.apiSecret("cs_SOME_NUMBER")
.build();
// Now let's go and ask for a protected resource!
System.out.println("Now we're going to access a protected resource...");
OAuthRequest request = new OAuthRequest(Verb.GET, RESOURCE_URL);
//Since it is a one legged protocol, access token is empty.Right?
service.signRequest(new Token("", ""), request);
Response response = request.send();
System.out.println("Got it! Lets see what we found...");
System.out.println();
System.out.println(response.getCode());
System.out.println(response.getBody());
System.out.println();
System.out.println("Thats it man! Go and build something awesome with Scribe! :)");
}
}
Throws the following error
{"errors":[{"code":"woocommerce_api_authentication_error","message":"oauth_consumer_key parameter is missing"}]}
. Any Ideas why my code is throwing the above error? Note that I have checked the v1 endpoint with http and it returns sensible message back.so basically it is working.
Removing '&' + OAuthEncoder.encode(tokenSecret) from https://github.com/fernandezpablo85/scribe-java/blob/master/src/main/java/org/scribe/services/HMACSha1SignatureService.java#L32 and adding and changed signature type to QueryString and it works now.
I will propose a PR after cleaning.Thanks Pablo. Below is the full code
package org.scribe.builder.api;
import org.scribe.model.Token;
import org.scribe.model.Verb;
public class OneLeggedApi10 extends DefaultApi10a {
#Override
public String getAccessTokenEndpoint() {
return null;
}
#Override
public String getRequestTokenEndpoint() {
return null;
}
#Override
public String getAuthorizationUrl(Token requestToken) {
return null;
}
#Override
public Verb getAccessTokenVerb() {
return Verb.GET;
}
#Override
public Verb getRequestTokenVerb() {
return Verb.GET;
}
}
And the example class
package org.scribe.examples;
import org.scribe.builder.*;
import org.scribe.builder.api.*;
import org.scribe.model.*;
import org.scribe.oauth.*;
public class WooCommerceOauth1Example {
private static final String NETWORK_NAME = "Woocommerce";
private static final String RESOURCE_URL = "http://YOUR_DOMAIN/wc-api/v1/orders/count";
private static final String SCOPE = "*"; //all permissions
public static void main(String[] args) {
OAuthService service = new ServiceBuilder().provider(OneLeggedApi10.class)
.apiKey("API_KEY")
.apiSecret("SECRET_KEY")
.debugStream(System.out)
.signatureType(SignatureType.QueryString)
/*.scope(SCOPE).*/
.build();
System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ===");
System.out.println();
// Now let's go and ask for a protected resource!
System.out.println("Now we're going to access a protected resource...");
OAuthRequest request = new OAuthRequest(Verb.GET, RESOURCE_URL);
service.signRequest(new Token("", ""), request);
Response response = request.send();
System.out.println("Got it! Lets see what we found...");
System.out.println();
System.out.println(response.getCode());
System.out.println(response.getBody());
System.out.println();
System.out.println("Thats it man! Go and build something awesome with Scribe! :)");
}
}

Camel aggregation strategy xpath example

I need an xml to be sent into a queue and be aggregated by one of it's fields using xpath.
That's the code of my RouteBuilder class implementation:
public class SimpleRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("activemq:queue:test.input").aggregate(new MyAggregationStrategy()).
xpath("login/(login)='manager", String.class).completionPredicate(header("aggregated").isEqualTo(5))
.to("activemq:queue:test.output").end()
;
}
}
class MyAggregationStrategy implements AggregationStrategy {
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
Message newIn = newExchange.getIn();
String oldBody = oldExchange.getIn().getBody(String.class);
String newBody = newIn.getBody(String.class);
newIn.setBody(oldBody + newBody);
return newExchange;
}
}
The xml that is being sent looks like this:
<person>
<login>login</login>
<password>pass</password>
</person>
When I copy this jar into the activemq lib folder and start the activemq, such exception appears:
ERROR: java.lang.IllegalArgumentException: Invalid broker URI, no scheme specified: start
What could be the problem here?
Your code extract doesn't lead to the reported exception. And I am not sure, what your use case is.
Anyway, following route matches the login content of the input messages. When 5 messages with the same login have been received, then the aggregation is sent to the output target. Please note the null check for oldExchange in the aggregate method:
public class SimpleRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("activemq:queue:test.input")
.aggregate(new MyAggregationStrategy()).xpath("/person/login", String.class)
.completionSize(5)
.to("activemq:queue:test.output");
}
}
public class MyAggregationStrategy implements AggregationStrategy {
#Override
public Exchange aggregate(final Exchange oldExchange, final Exchange newExchange) {
Message newIn = newExchange.getIn();
String newBody = newIn.getBody(String.class);
if (oldExchange == null) {
newIn.setBody(newBody);
} else {
String oldBody = oldExchange.getIn().getBody(String.class);
newIn.setBody(oldBody + newBody);
}
return newExchange;
}
}

Categories

Resources