I have a route that I am testing. I use stub://jms:queue:whatever to send/receive messages and extending CamelTestSupport for my test classes. I am having an issue with one of the routes that has a bean that uses an idempotent repo to store messages by "message id" for which it reads and stores the JMSMessageID property from exchange.
The problem I run into is that I can't figure out a way to set this property on messages sent on stubbed endpoints. Every time the method that requires this prop is called, the id returns null and i have to handle it as a null pointer. I can do this but the cleanest approach would be to just set the header on the test message. I tried includeSentJMSMessageId=true on endpoint, I tried using sendBodyAndHeader on producer and passing "JMSMessageID", "ID: whatever" in arguments, doesn't appear to work? I read that the driver/connectionfactory is supposed to set the header, but I'm not too familiar with how/where to do this. And since I am using a stubbed end points, I'm not creating any brokers/connectionfactories in my uts.
So dont stud out the JMS component replace it with a processor and then add the preferred JMSMessageID in the processor.
Something like this code:
#Test
void testIdempotency() throws Exception {
mockOut.expectedMinimumMessageCount(1);
//specify the route to test
AdviceWithRouteBuilder.adviceWith(context, "your-route-name", enrichRoute -> {
//replace the from with a end point we can call directly.
enrichRoute.replaceFromWith("direct:start");
//replace the jms endpoint with a processor so it can act as the JMS Endpoint.
enrichRoute.weaveById("jms:queue:whatever").replace().process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
//Set that ID to the one I want to test
exchange.getIn().setHeader("JMSMEssageID", "some-value-to-test");
}
});
// add an endpoint at the end to check if received a mesage
enrichRoute.weaveAddLast().to(mockOut);
});
context.start();
//send some message
Map<String,Object> sampleMsg = getSampleMessageAsHashMap("REQUEST.json");
//get the response
Map<String,Object> response = (Map<String,Object>)template.requestBody("direct:start", sampleMsg);
// you will need to check if the response is what you expected.
// Check the headers etc.
mockOut.assertIsSatisfied();
}
The JMSMessageID can only be set by the provider. It cannot be set by a client despite the fact that javax.jms.Message has setJMSMessageId(). As the JavaDoc states:
This method is for use by JMS providers only to set this field when a message is sent. This message cannot be used by clients to configure the message ID. This method is public to allow a JMS provider to set this field when sending a message whose implementation is not its own.
Related
I am writing an application where the Client issues commands to a web service (CQRS)
The client is written in C#
The client uses a WCF Proxy to send the messages
The client uses the async pattern to call the web service
The client can issue multiple requests at once.
My problem is that sometimes the client simply issues too many requests and the service starts returning that it is too busy.
Here is an example. I am registering orders and they can be from a handful up to a few 1000s.
var taskList = Orders.Select(order => _cmdSvc.ExecuteAsync(order))
.ToList();
await Task.WhenAll(taskList);
Basically, I call ExecuteAsync for every order and get a Task back. Then I just await for them all to complete.
I don't really want to fix this server-side because no matter how much I tune it, the client could still kill it by sending for example 10,000 requests.
So my question is. Can I configure the WCF Client in any way so that it simply takes all the requests and sends the maximum of say 20, once one completes it automatically dispatches the next, etc? Or is the Task I get back linked to the actual HTTP request and can therefore not return until the request has actually been dispatched?
If this is the case and WCF Client simply cannot do this form me, I have the idea of decorating the WCF Client with a class that queues commands, returns a Task (using TaskCompletionSource) and then makes sure that there are no more than say 20 requests active at a time. I know this will work but I would like to ask if anyone knows of a library or a class that does something like this?
This is kind of like Throttling but I don't want to do exactly that because I don't want to limit how many requests I can send in a given period of time but rather how many active requests can exist at any given time.
Based on #PanagiotisKanavos suggjestion, here is how I solved this.
RequestLimitCommandService acts as a decorator for the actual service which is passed in to the constructor as innerSvc. Once someone calls ExecuteAsync a completion source is created which along with the command is posted to the ActonBlock, the caller then gets back the a Task from the completion source.
The ActionBlock will then call the processing method. This method sends the command to the web service. Depending on what happens, this method will use the completion source to either notify the original sender that a command was processed successfully or attach the exception that occurred to the source.
public class RequestLimitCommandService : IAsyncCommandService
{
private class ExecutionToken
{
public TaskCompletionSource<bool> Source { get; }
public ICommand Command { get; }
public ExecutionToken(TaskCompletionSource<bool> source, ICommand command)
{
Source = source;
Command = command;
}
}
private IAsyncCommandService _innerSrc;
private ActionBlock<ExecutionToken> _block;
public RequestLimitCommandService(IAsyncCommandService innerSvc, int maxDegreeOfParallelism)
{
_innerSrc = innerSvc;
var options = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism };
_block = new ActionBlock<ExecutionToken>(Execute, options);
}
public Task IAsyncCommandService.ExecuteAsync(ICommand command)
{
var source = new TaskCompletionSource<bool>();
var token = new ExecutionToken(source, command);
_block.Post(token);
return source.Task;
}
private async Task Execute(ExecutionToken token)
{
try
{
await _innerSrc.ExecuteAsync(token.Command);
token.Source.SetResult(true);
}
catch (Exception ex)
{
token.Source.SetException(ex);
}
}
}
I want to do some server-side events (SSE) to a web app. I think I have all the SSE plumbing up and going. I now need to create a Source on the Akka HTTP side of the house.
I found you can do something like this:
val source = Source.actorRef(5, akka.stream.OverflowStrategy.dropTail)
What I want to do is somehow "publish" to this source, presumably by sending an actor a message. I see from the docs that this call creates Source<T,ActorRef>.
How can I get this ActorRef instance so I can send messages to it?
To obtain the materialized ActorRef from Source.actorRef, the stream has to be running. For example, let's say that you want to send the SSE payload data (in the form of a String) to this actor, which converts that data to ServerSentEvent objects to send to the client. You could do something like:
val (actor, sseSource) =
Source.actorRef[String](5, akka.stream.OverflowStrategy.dropTail)
.map(s => /* convert String to ServerSideEvent */)
.keepAlive(1.second, () => ServerSentEvent.heartbeat)
.toMat(BroadcastHub.sink[ServerSentEvent])(Keep.both)
.run()
// (ActorRef, Source[ServerSentEvent, NotUsed])
Now you can send messages to the materialized actor:
actor ! "quesadilla"
And use sseSource in your route:
path("events") {
get {
complete(sseSource)
}
}
Note that there is no backpressure with this approach (i.e., messages to the actor are fired-and-forgotten).
I have a backend listener that posts JMeter results to an external server. It works for most parts. However, I'd like to get cookie info for failed requests. Backend listener only gets SampleResult and I don't see an API to access cookie info from SampleResult. Does anyone have an idea?
View Result Tree listener is able to print out request cookies, so there must be a way. However, it's not obvious what's the class name for that particular listener. If anyone can point me to that source code, it'll be a starting point.
With current JMeter implementation it is not possible unless your create your own AbstractBackendListenerClient implementation which will be cookies-aware.
Also depending on how do you parse result you can substitute a "not interesting" SampleResult field (for example Response Message) with cookie values for failed requests. It can be done using i.e. JSR223 PostProcessor and the following Groovy code
if (!prev.isSuccessful()) {
def manager = sampler.getCookieManager()
def cookies = new StringBuilder()
for (int i = 0; i < manager.getCookieCount(); i++) {
cookies.append(manager.get(i).getName()).append('=').append(manager.get(i).getValue())
}
prev.setResponseMessage(cookies.toString())
}
Hard to help without seeing some code, but one general direction could be this: you can check if your SampleResult is of type HTTPSampleResult, and if yes, get its cookies, using getCookies() method. Whole process could be wrapped as the following function:
public String getCookiesForHttpResult(SampleResult sampleResult) {
if (sampleResult instanceof HTTPSampleResult) {
HTTPSampleResult httpSampleResult = (HTTPSampleResult) sampleResult;
return httpSampleResult.getCookies();
}
// not HTTP result
return null;
}
Something like that is done in JMeter's RequestViewHTTP.java
Getting CookieManager in backend listener can be problematic, since it's mutable: by the time backend listener reads from CookieManager, list of cookies may be different from the time of request execution.
I hope it is ok to ask two somehow related Questions in one.
I am using a camel route to send a SOAP message to a webservice using Reliable Messaging. Now there is two Problems i ran into, first the WS-Addressing version that is used is wrong, i need to have 2005/08 but instead it is using 2004/08.
For setting up the endpoint i am using (shortend a bit)
CxfEndpoint cxfEndpoint = new CxfEndpoint();
cxfEndpoint.setWsdlURL(getWsdlURL());
cxfEndpoint.setDataFormat(DataFormat.CXF_MESSAGE);
cxfEndpoint.setCamelContext(camelContext);
camelContext.addEndpoint(outEndpoint.getId(), cxfEndpoint);
I also set up a cxfbus in the camel-context.xml file and a seperate http-conduit.xml
now my question for the WS-Addressing is, how can i change it to use WS-Addressing 2005/08? i already tried to add following to my route, before the endpoint is called, but it did not change the Addressing Namespace.
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
AddressingPropertiesImpl addrProps =
new AddressingPropertiesImpl("http://www.w3.org/2005/08/addressing");
Map<String, Object> requestContext = new HashMap<String, Object>();
requestContext.put("javax.xml.ws.addressing.context", addrProps);
exchange.getIn().setHeader(Client.REQUEST_CONTEXT, requestContext);
}
})
Regarding the Offer in the CreateSequence added the following before the endpoint is added to the CamelContext:
RMManager rmManager = cxfEndpoint.getBus().getExtension(RMManager.class);
rmManager.getSourcePolicy().setIncludeOffer(false);
Although this worked fine it had the nasty side effect that my http-conduit was no longer used. I fixed this with following:
cxfEndpoint.setBus(bus);
where bus is being #Autowired
but in my opinion this broke the WS-Reliable Messaging for my incoming CXF Endpoint that are created in a similiar way. It still sends the correct messages but before the CreateSequenceResponse is send, there is an empty SOAP message sent, that causes the client to drop out of the Sequence creation.
Now my question would be, is there a better way to remove the Offer from the CreateSequence?
I am working on a SoapHandler implementation. Basically my aim is to get both request and response payloads and insert them to the database.
Although I can get the request and response payloads, I couldn't make sure if my code is working thread-safe. In other words, I am not sure if responses match with the proper requests.
public boolean handleMessage(SOAPMessageContext mContext) {
boolean isResponse = (Boolean) mContext
.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (!isResponse) {
try {
mContext.put("currentStream", new ByteArrayOutputStream());
mContext.getMessage().writeTo((OutputStream) mContext.get("currentStream"));
} catch (SOAPException | IOException e) {
e.printStackTrace();
}
} else {
try {
mContext.getMessage().writeTo(
(OutputStream) mContext.get("currentStream"));
System.out.println(((OutputStream) mContext.get("currentStream"))
.toString());
((OutputStream) mContext.get("currentStream")).flush();
} catch (SOAPException | IOException e) {
e.printStackTrace();
}
}
return true;
}
I found this in JCP specs:
9.3.3 Handler Implementation Considerations
Handler instances may be pooled by a JAX-RPC runtime system. All instances of a specific handler are
considered equivalent by a JAX-RPC runtime system and any instance may be chosen to handle a particular
message. Different handler instances may be used to handle each messages of an MEP. Different threads
may be used for each handler in a handler chain, for each message in an MEP or any combination of the
two. Handlers should not rely on thread local state to share information. Handlers should instead use the
message context, see section 9.4.
9.4 Message Context
Handlers are invoked with a message context that provides methods to access and modify inbound and
outbound messages and to manage a set of properties.
Different types of handler are invoked with different types of message context. Sections 9.4.1 and 9.4.2
describe MessageContext and LogicalMessageContext respectively. In addition, JAX-RPC bindings 12
may define a message context subtype for their particular protocol binding that provides access to protocol
specific features. Section10.3 describes the message context subtype for the JAX-RPC SOAP binding.
http://download.oracle.com/otn-pub/jcp/jaxrpc-2.0-edr2-spec-oth-JSpec/jaxrpc-2_0-edr2-spec.pdf?AuthParam=1431341511_1ac4403a34d7db108bce79eda126df49
Does this imply that a new MessageContext object is created for each request (in which case I think the code will be thread safe), or the same MessageContext object can be used for multiple requests (then my code will not be thread safe).
Any help / alternative solution will be appreciated.
Rule of thumb: a FooContext object is contextual by definition, relating to a specific execution context. EJBContext relating to a single EJB; FacesContext relating to a single Faces request context; SOAPMessageContext relating to a single SOAPMessage. From the JSR-109 documentation:
The container must share the same MessageContext instance across all Handler instances and the target endpoint that are invoked during a single request and response or fault processing on a specific node.
So, you can be sure that there's one new SOAPMessageContext instance per request. Within the context of a single request however, that instance is yours to mangle. So the question really is, what do you mean by "threadsafety"? Do you plan to have multiple threads processing a single SOAPMessageContext during each request? I don't recommend it
EDIT: While the specification doesn't state in black and white that a MessageContext is threadsafe, it's implied throughout the specification. The following is an excerpt from the section of the spec that states what's possible on a MessageContext, within a handler:
Handlers may manipulate the values and scope of properties within the message context as desired. E.g. ... a handler in a server-side SOAP binding might add application scoped properties tot he message context from the contents of a header in a request SOAP message...
SOAP handlers are passed a SOAPMessageContext when invoked. SOAPMessageContext extends MessageContext with methods to obtain and modify the SOAP message payload
The specification won't be expecting programmers to modify the content of the context if it weren't safe to do so.