I have an OSGi service which I have exposed with CXF as a simple web service and for which I have created a client which invokes its methods. The methods of this service accept as one of their arguments a signed ticket which identifies the client performing the request. In order to inject this ticket to all requests coming from my client I have created a CXF out interceptor, which I have bound to the SETUP phase, and which is responsible for the injection of the ticket in the outgoing message.
In case the ticket injected by my interceptor has expired, the service will throw an exception which I would like to be able to catch, get a fresh ticket and repeat the request with this fresh ticket in order to completely abstract the ticket-management functionality from the rest of my code. I have therefore created an in fault interceptor, which I have bound to the PRE_LOGICAL phase and in which I am able to identify whether the specific exception type I am interested in has been thrown. I am however unsure as to how I can repeat the request and return the result of the second request instead of the first one. Does CXF offer a way for me to do this?
Since I wasn't able to find a way to repeat the request through a fault interceptor I ended up using an InvocationHandler to allow me to control the request (effectively wrapping the proxy I get from CXF in another proxy). What I ended up with is something like the following:
ClientProxyFactoryBean factory = new ClientProxyFactoryBean();
// Configure factory
MyService serviceClient = (MyService) factory.create(MyService.class);
MyService proxy = (MyService) Proxy.newProxyInstance(
ServiceInvocationHandler.class.getClassLoader(),
new Class[] { MyService.class },
new ServiceInvocationHandler(serviceClient));
Where the ServiceInvocationHandler is:
public class ServiceInvocationHandler implements InvocationHandler {
private final Object proxied;
private SignedTicket ticket;
public ServiceInvocationHandler(Object proxied) {
this.proxied = proxied;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object retVal = null;
try {
// Generate a ticket if the one held locally by this class is null
// and inject it in the method arguments
retVal = method.invoke(proxied, args);
} catch (Throwable t) {
if (t.getCause() instanceof InvalidTicketException) {
// Get a fresh ticket and inject it in the method arguments
retVal = method.invoke(proxied, args);
}
}
return retVal;
}
}
Related
I have the following code where if I keep the retry annotation on the controller method, then it is getting retried but if I keep the retry annotation on a different method, it doesn't retry. Scenario is, in the API method, createOrder(), I fetch the orderId from an external system which is working fine. But I need to retry the createOrder(String orderId) method which fails some of the times.
#GetMapping("/order")
//#Retry(name = ORDERSERVICE, fallbackMethod = "fallback_retry")
public ResponseEntity<String> createOrder() {
int orderId = 1; // makeDBCall or fetch it from somewhere
return createOrder(orderId); // need to retry this method in case it fails
}
#Retry(name = ORDERSERVICE, fallbackMethod = "fallback_retry")
public ResponseEntity<String> createOrder(int orderId) {
logger.info("item service call attempted:::" + attempts++);
String response = restTemplate.getForObject("http://localhost:8081/item/" + orderId, String.class);
logger.info("item service called");
return new ResponseEntity<String>(response, HttpStatus.OK);
}
resilience4j.retry:
instances:
orderService:
maxRetryAttempts: 3
waitDuration: 11000
This is because of Proxy. When annotated with #Retry a proxy instance of the class is created and is used. The proxies work in such a way that calls from one bean/class to another bean/class are intercepted, and it cannot intercept calls from method to method within the bean/class.
Hence, the workaround would be to move the method to a different class. Once the method is moved to a different class, the spring proxy would consider the call from a separate bean and it can intercept.
In my application I would like to log request and response with business logic. Application does some backend logic with SOAP communication and this is what I want to log.
Unfornatly in this same application I must serve data ( avg. is 4 request/s)
Let's say this service name is PlatformDataService.
How to turn off cxf logging for only one web service?
Enviorment:
JDK 8
cxf 2.7.14
AS : Jboss EAP 6.4
I turn on login on server by:
add logger org.apache.cxf INFO
and system property org.apache.cxf.logging.enabled=true
You can extend LoggingInInterceptor and LoggingOutInterceptor. Based on the soapAction you can ignore only logging for one service.
Extend LoggingOutInterceptor for all the outbound requests and override method handleMessage like this.
private boolean doNotLog=false;
public void handleMessage(Message message) throws Fault {
TreeMap<String,List> protocolHeaders =
(TreeMap<String, List>) message.get("org.apache.cxf.message.Message.PROTOCOL_HEADERS");
if (protocolHeaders != null) {
List value = protocolHeaders.get("SOAPAction");
String soapAction = value != null ? (String)value.get(0) : "";
if (soapAction.equalIgnoreCase(YOUR_SERVICE_SOAP_ACTION)) {
doNotLog=true;
}
}
super.handleMessage(message);
}
Now there is one more method you have to override in the same class.
#Override
protected String transform(String originalLogString) {
if (doNotLog) {
return null;
}
return originalLogString;
}
For all inbound responses, extend LoggingInInterceptor and only override transform method. You can just check the responseType from the originalLogString and ignore it.
We have Rest services implemented using Jersy,my question is when invoking some soap service from our rest implementation, we are creating object for delegate like below,
#POST
#Path("/forgotuserid/validate/mobilenumber")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public ServiceResponse validateMobileNumber(CommunicationDTO commonDTO)
throws ApplicationException, Exception {
ChMTYWebservicesProvidersWsMTY service = new ChMTYWebservicesProvidersWsMTY();
WsMTYPortType portType = service.getChMTYWebservicesProvidersWsMTYPort();
//TODO : other stuffs go here
return response;
}
is there any way to avoid new object creation and have single here?
If you are using Spring framework then there is an option Dependency Injection , You can use that feature.
You can code something like this:
public class SoapWSUtil{
private static WsMTYPortType type;
static {
type = (new ChMTYWebservicesProvidersWsMTY()).getChMTYWebservicesProvidersWsMTYPort();
}
public static WsMTYPortType getType(){
return type;
}
}
And then use it as SoapWSUtil.getType(). It will be thread safe in case, if you won't add state to SoapWSUtil
I have a webservice and from this webservice I should pass an obejct to an another service. I tried with #Pathparam and #QueryParam but Iam not getting the values in my service.
The code where I am passing the object is
public void MediatorCmpService() {
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
WebResource service = client.resource(getBaseURI());
boolean flag = validateConfig(iFGetResponse);
if (flag) {
CustomerData customerData = transformationPayload(iFGetResponse);
TrilliumxmlProducer tri=new TrilliumxmlProducer(customerData);
}
System.out.println(flag);
}
Here I am passing the customerData Object to my TrilliumxmlProducer Service. But this Object is not getting passed to the TrilliumxmlProducer service
The code for the TrilliumxmlProducer is
#Path("/generateTrillium")
public class TrilliumxmlProducer {
// This method is called if XMLis request
public TrilliumxmlProducer(CustomerData customerData) throws JAXBException {
getXML(customerData);
// TODO Auto-generated constructor stub
}
#GET
#Produces({ MediaType.APPLICATION_XML })
public CustomerData getXML(#QueryParam("customerData") CustomerData customerData) throws JAXBException {
System.out.println("--------2----------" + customerData.getREQUESTTYPE());
return customerData;
}
}
Here My object is giving nullpointer exception. Can anyone help me here
You do not seem to be passing a QueryParameter in your request.
A PathParam is used to extract data from the Path, ie "endpoint/{id}/help" then the PathParam "id" would return whatever is in between "endpoint/" and "/help".
A QueryParam is used to extract data from the Query, ie "endpoint/help?id=" then the QueryParam would return whatever you have instead of in youe request.
Although technically legal, you should try to avoid mixing and matching, and just use one or the other.
Edit
Also, while I'm not certain, I'm pretty confident that you can't/shouldn't use an object graph to pass around your rest resources.
I have a REST service for accounts. The controller calls the Service layer to find Accounts. AccountService can throw domain exceptions. It is usually a case related to client input error.In such a situation, I want to wrap the domain exception with ClientException. Is there a way that client can be presented with status code 400 and just the exception message? Or is there a better to handle the situation where the service layer detects an illegal argument?
#Controller
class AccountController
#ResponseBody
#RequestMapping("/accounts/${accountId}")
public Account account(#PathVariable int accountId, HttpServletResponse response){
try{
return accountService.find("Account not found with id: " + accountId);
}catch(Exception e){
response.setStatus(400);
throw new ClientException(e);
}
}
}
class AccountService{
public Account find(int accountId){
if(acountId > 100){
throw new AccountNotFoundException(accountId);
}else{
return new Account(accountId, "someone");
}
}
}
If this is a REST service, then simply setting the response status and a JSON body (with error message) should be enough. There's no real need to throw that ClientException.
You can create an exception handler that takes the exception and marshals it into a JSON response object.
I did this some time ago, and it worked fine, however I know longer have the source-code to share. .
Look at Spring MVC's exception handlers as a starting point.