I got a CXF OSGi Web service (based on the example demo in servicemix: https://github.com/apache/servicemix/tree/master/examples/cxf/cxf-jaxws-blueprint)
The Web service works fine and i call all the available implemented methods of the service.
My question is how can i retrieve the request inside a WS method and parse in a string XML format.
I have found that this is possible inside interceptors for logging, but i want also to the WS-Request inside my methods.
For storing the request in the database I suggest to extend the new CXF message logging.
You can implement a custom LogEventSender that writes into the database.
I had similar requirement where I need to save data into DB once method is invoked. I had used ThreadLocal with LoggingInInterceptor and LoggingOutInterceptor. For example in LoggingInInterceptor I used to set the message into ThreadContext and in webservice method get the message using LoggingContext.getMessage() and in LoggingOutInterceptor I used to removed the message(NOTE: Need to be careful here you need to explictly remove the message from thread context else you will end up with memory leak, and also incase of client side code interceptors get reversed.
public class LoggingContext {
private static ThreadLocal<String> message;
public static Optional<String> getMessage() {
return Optional.ofNullable(message.get());
}
public static void setMessage(final String message) {
LoggingContext.message = new ThreadLocal<>();
LoggingContext.message.set(message);
}
}
Not an answer to this question but i achieved to do my task by using JAXB in the end and do some manipulations there.
Related
I am facing one issue.
I am calling some API's in parallel using Spring Webflux. If any child thread faces any issue, it needs to log the request. Now the issue is , for logging a normal POJO class in which there is a static method which gets a bean via ApplicationContent and store the data in a Queue.
Now the issue is, I want to access request params like Request URL / Controller etc.
I tried
ServletRequestAttributes sra =
(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
logger.error("====="+sra);
HttpServletRequest httpRequest = sra.getRequest();
but In this case, sra is null. I tried adding the following code,
#Configuration
public class InheritableRequestContextListener extends RequestContextListener {
private static final String REQUEST_ATTRIBUTES_ATTRIBUTE =
InheritableRequestContextListener.class.getName() + ".REQUEST_ATTRIBUTES";
#Override
public void requestInitialized(ServletRequestEvent requestEvent) {
System.out.println("111111111111111111");
if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) {
throw new IllegalArgumentException(
"Request is not an HttpServletRequest: " + requestEvent.getServletRequest());
}
HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest();
ServletRequestAttributes attributes = new ServletRequestAttributes(request);
request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes);
LocaleContextHolder.setLocale(request.getLocale());
RequestContextHolder.setRequestAttributes(attributes, true);
}
}
but this is not helping. Can anyone help. I am using springboot version ; 2.0.2.RELEASE.
There are several reasons as to why your implementation does not work.
Webflux is thread agnostic, which means that any thread can deal with anything at anytime in the application. If the application finds it efficiant to switch the current executing thread, it will do so.
Servlet applications on the other hand assigns one thread to each request and sticks with that thread throughtout execution.
ApplicationContext uses as you can see ServletRequests, so it is not usable in a Webflux application. It in turn uses threadlocal to store the request object to the designated thread.
In webflux you cant use threadlocal, bucase as soon as the application switches threads everything in threadlocal is gone. Thats why you get null.
So how do you pass data from thread to thread.
What you need to do is to implement a filter that intercepts the request, extracs the information you want and places it in the reactive context object.
https://projectreactor.io/docs/core/release/reference/#context
Here is a post that addresses the problem.
https://developpaper.com/implementation-of-requestcontextholder-in-spring-boot-webflux/
If I have an Apex function that is named authorize() that just gets a username, password, and session token, and another function called getURL('id#', 'key'), that takes an id# for the record as a string and a key for the image to return as a string as parameters. getURL calls the authorize function inside it in order to get the credentials for its callout. The authorize is a post request, and the getURL is a get request.
I am trying to figure out how to test both of these callouts just so I can make sure that getURL is returning the proper JSON as a response. It doesn't even have to be the URL yet which is its intention eventually. But I just need to test it to make sure these callouts are working and that I am getting a response back for the 75% code coverage that it needs.
I made a multiRequestMock class that looks like this:
public class MultiRequestMock implements HttpCalloutMock {
Map<String, HttpCalloutMock> requests;
public MultiRequestMock(Map<String, HttpCalloutMock> requests) {
this.requests = requests;
}
public HTTPResponse respond(HTTPRequest req) {
HttpCalloutMock mock = requests.get(req.getEndpoint());
if (mock != null) {
return mock.respond(req);
} else {
throw new MyCustomException('HTTP callout not supported for test methods');
}
}
public void addRequestMock(String url, HttpCalloutMock mock) {
requests.put(url, mock);
}
}
I then began to write a calloutTest.cls file but wasn't sure how to use this mock class in order to test my original functions. Any clarity or assistance on this would be helpful Thank you.
I believe in your calloutTest class you use Test.setMock(HttpCalloutMock.class, new MultiRequestMock(mapOfRequests)); then call the getUrl and/or authorize methods and instead of the request really executing the response returned will be that which is specified in the response(HttpRequest) method you have implemented in the MultiRequestMock class. That is basically how I see it working, for more info and an example you can see this resource on testing callout classes. This will get you the code coverage you need but unfortunately cannot check you are getting the correct JSON response. For this, you may be able to use the dev console and Execute Anonymous?
You may want to look at simplifying your HttpCalloutMock Implementation and think about removing the map from the constructor as this class really only needs to return a simple response then your calloutTest class can be where you make sure the returned response is correct.
Hope this helps
I am using Flowable 6.4.1 in spring-boot to create processes and run from my java code, but requirement is to not use any xml, so due to this I have hit a blockade.
I have a user task, taking input from user, depending on that input, call to corresponding service task is made.
Below is a short example of what I am going to do:
basic-process.bpmn20.xml:
<process id="basicprocess" name="Basic Process" isExecutable="true">
<startEvent id="startEvent"/>
<sequenceFlow sourceRef="startEvent" targetRef="getInput"/>
<userTask id="getInput" name="Get input from user" />
<sequenceFlow sourceRef="getInput" targetRef="decision"/>
<exclusiveGateway id="decision"/>
<sequenceFlow sourceRef="decision" targetRef="firstServiceTask">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[
${number>100}
]]>
</conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="decision" targetRef="secondServiceTask">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[
${number<=100}
]]>
</conditionExpression>
</sequenceFlow>
<serviceTask id="firstServiceTask" name="Number is greater than predefined target"
flowable:class="demo.service.tasks.FirstServiceTask"/>
<sequenceFlow sourceRef="firstServiceTask" targetRef="greaterEnd"/>
<serviceTask id="secondServiceTask" name="Number is less than predefined target"
flowable:class="demo.service.tasks.SecondServiceTask"/>
<sequenceFlow sourceRef="secondServiceTask" targetRef="lesserEnd"/>
<endEvent id="greaterEnd"/>
<endEvent id="lesserEnd"/>
</process>
Above, XML shows the process and I'm starting the process using REST API
Below is the controller:
DefinitionsController.java:
#RestController
#SuppressWarnings("rawtypes")
public class DefinitionsController {
#Autowired
private RepositoryService mRepositoryService;
#Autowired
private RuntimeService mRuntimeService;
#Autowired
private TaskService mTaskService;
#PostMapping("/start-service")
public String startService(#RequestBody String input) {
Integer request = Integer.parseInt(input);
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("number", request);
ProcessInstance instance = mRuntimeService.startProcessInstanceByKey("basicprocess", variables);
Task userTask = mTaskService.createTaskQuery().processInstanceId(instance.getId()).taskDefinitionKey("getInput").singleResult();
mTaskService.complete(userTask.getId());
return "ProcessInstance id is "+instance.getProcessInstanceId();
}
}
FirstServiceTask.java:
public class FirstServiceTask implements JavaDelegate{
#Override
public void execute(DelegateExecution execution) {
System.err.println("Came in first service task");
}
}
Same for SecondServiceTask.java except the sysout statement.
REST RESPONSE: I get the processInstance Id and sysout statement of respective service task gets printed in console..
Pretty easy to wire the Service Task classes from xml, however if I were to not use XML, I would need to create the same process using flowable-modeler api of FLOWABLE.
So, basically I want to have control over those service tasks from my java code and in order to do that how do I wire the Service Tasks that are created using flowable-modeler with my java code ?
I have gone through docs, but found the xml way only.
Configuring Service Tasks (created using flowable-modeler) with Java code can be done by the 4 ways shown here.
The delegate expression which is going to be configured should be either present on the classpath or should have a spring-bean created.
I created bean using a method in main class, and put the name of method in delegate expressionattribute in flowable-modeler/process api and that's what was needed to do that.
Attached image should clarify things, which shows the way to wire Service Tasks (created using flowable-modeler API) with Java classes in workspace.
firstServiceTask in highlighted field is the method which returns bean of FirstServiceTask
EDIT: Apart from above solution, we can also specify class name in class field alone and all configuration is done. Forex: I have a class called TestClass.java in package org.flowable.learning, so I'll just specify org.flowable.learning.TestClass in class field, which is just above highlighted Delegate expression field in attached screenshot
In my application, I need to call an external endpoint and if it is too slow a fallback is activated.
The following code is an example of how my app looks like:
#FeignClient(name = "${config.name}", url = "${config.url:}", fallback = ExampleFallback.class)
public interface Example {
#RequestMapping(method = RequestMethod.GET, value = "/endpoint", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
MyReturnObject find(#RequestParam("myParam") String myParam);
}
And its fallback implementation:
#Component
public Class ExampleFallback implements Example {
private final FallbackService fallback;
#Autowired
public ExampleFallback(final FallbackService fallback) {
this.fallback = fallback;
}
#Override
public MyReturnObject find(final String myParam) {
return fallback.find(myParam);
}
Also, a configured timeout for circuit breaker:
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000
How can I implement an integration test to check if my circuit break is working, i.e, if my endpoint (mocked in that case) is slow or if it returns an error like 4xx or 5xx?
I'm using Spring Boot 1.5.3 with Spring Cloud (Feign + Hystrix)
Note i donot know Feign or Hystrix.
In my opinion it is problematic to implement an automated integrationtest that simulates different implementatondetails of Feign+Hystrix - this implementation detail can change at any time. There are many different types of failure: primary-Endpoint not reachable, illegal data (i.e. receiving a html-errormessage, when exprecting xml data in a special format), disk-full, .....
if you mock an endpoint you make an assumption of implementationdetail of Feign+Hystrix how the endpoint behaves in a errorsituation (i.e. return null, return some specific errorcode, throw an exception of type Xyz....)
i would create only one automated integration test with a real primary-enpoint that has a never reachable url and a mocked-fallback-endpoint where you verify that the processed data comes from the mock.
This automated test assumes that handling of "networkconnection too slow" is the same as "url-notfound" from your app-s point of view.
For all other tests i would create a thin wrapper interface around Feign+Hystrix where you mock Feign+Hystrix. This way you can automatically test for example what happens if you receive 200bytes from primary interface and then get an expetion.
For details about hiding external dependencies see onion-architecture
I have a Website that contains a number of webpages and some WCF services.
I have a logging IHttpModule which subscribes to PreRequestHandlerExecute and sets a number of log4net MDC variables such as:
MDC.Set("path", HttpContext.Current.Request.Path);
string ip = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if(string.IsNullOrWhiteSpace(ip))
ip = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
MDC.Set("ip", ip);
This module works well for my aspx pages.
To enable the module to work with WCF I have set aspNetCompatibilityEnabled="true" in the web.config and RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed on the service.
But when the service method is called the MDC no longer contains any of the set values. I have confirmed they are being set by putting a logging method in the PreRequestHandlerExecute.
I think the MDC is loosing the values because in the log I can see the PreRequestHandlerExecute handler method and service method calls are on separate
threads.
The post log4net using ThreadContext.Properties in wcf PerSession service suggests using log4net.GlobalContext but I think that solution would run into issues if two users hit the application at the same time as GlobalContext is shared by all threads.
Is there a way to make this work?
Rather than taking the values from the HttpContext and storing them in one of log4net's context objects, why not log the values directly from the HttpContext? See my answer to the linked question for some techniques that might work for you.
Capture username with log4net
If you go to the bottom of my answer, you will find what might be the best solution. Write an HttpContext value provider object that you can put in log4net's GlobalDiagnosticContext.
For example, you might do something like this (untested)
public class HttpContextValueProvider
{
private string name;
public HttpContextValueProvider(string name)
{
this.name = name.ToLower();
}
public override string ToString()
{
if (HttpContext.Current == null) return "";
var context = HttpContext.Current;
switch (name)
{
case "path":
return context.Request.Path;
case "user"
if (context.User != null && context.User.Identity.IsAuthenticated)
return context.User.Identity.Name;
case "ip":
string ip = context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if(string.IsNullOrWhiteSpace(ip))
ip = context.Request.ServerVariables["REMOTE_ADDR"];
return ip;
default:
return context.Items[name];
}
return "";
}
}
In the default clause I assume the name, if it is not a specifically case that we want to handle, represents a value in the HttpContext.Current.Items dictionary. You could make it more generic by also adding the ability to access Request.ServerVariables and/or other HttpContext information.
You would use this object like so:
Somewhere in your program/web site/service, add some instances of the object to log4net's global dictionary. When log4net resolves the value from the dictionary, it will call ToString before logging the value.
GDC.Set("path", new HttpContextValueProvider("path"));
GDC.Set("ip", new HttpContextValueProvider("ip"));
Note, you are using log4net's global dictionary, but the objects that you are putting in the dictionary are essentially wrappers around the HttpContext.Current object, so you will always be getting the information for the current request, even if you are handling simultaneous requests.
Good luck!