Sending different error messages from web service - web-services

I wrote a web service using cxf web service. I want to send different error messages to client. I have a method and this method return an object if everything is ok. Method receives parameters if one of parameters is wrong, method must send different messages. But i can not change method return type so i cant send different objects. How can i do that?

Try to use the exceptions.
Within the java annotations cxf system you can return an exception if it looks like this :
import javax.xml.ws.WebFault;
#WebFault(name = "UsageMyException")
public class MyException extends Exception
{
private static final long serialVersionUID = 1L;
public MyException(final String string)
{
super(string);
}
public MyException(final Exception e)
{
super(e);
}
}
You can use more than one exception that extends each other. The exception corresponds to wsdl/soap FaultMessage.

Related

Hystrix fallbackMethod will not be called in unit test?

I am starting to use Hystrix on my application to deal with data coming from external services. Some main points in my code:
#HystrixCommand(fallbackMethod = "getImagesFallback")
public ImageResultResource getImages(String url)
{
ResponseEntity<ResultResource> result = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(getRequestHeaders()), ResultResource.class);
return result.getBody().getImageResultResource();
}
public ImageResultResource getImagesFallback(String url, Throwable e)
{
return new ImageResultResource();
}
In my unit test, I would like to test the fallback case, for example when the external service returns 404 Not Found response, so I mock my test like below:
doThrow(new HttpClientErrorException(HttpStatus.NOT_FOUND))//
.when(Mockito.spy(new ImageConnector()))//
.getImages(myMockedURL)
But when I run the test, it seems that the fallbackMethod that I defined above was not called. It returned directly the 404 Not Found that I mocked for the external service while I expect that the fallbackMethod should be catched here and no 404 Not Found will be thrown here.
Can anyone give me hint how can I test my fallbackMethod in this case, or did I make something wrong with the configuration here? Thank you so much!
Your fallback method needs to have the same signature as the method with the HystrixCommand annotation or the same signature with the addition of a Throwable. Here is the relevant Javanica documentation
public ImageResultResource getImagesFallback(String url, Throwable e) {
return new ImageResultResource();
}
Hystrix custom fallback methods throws the exception having the instance of HystrixRuntimeException..
So, you need to catch this exception and use getMessage method of it to print it.

JMS integration testing

I am trying to write an integration test for JMS service which looks like something like this.
#JmsListener(destination = "mailbox", containerFactory = "myFactory")
public void receiveMessage(Email message) throws InterruptedException {
try {
sendEmail(message);
}catch (Exception e){
LOGGER.log(Level.SEVERE,"Failed to deliver email",e);
Thread.sleep(TimeUnit.SECONDS.toSeconds(Optional.of(retryInterval).orElse(5)));
throw e;
}
}
private void sendEmail(Email message){
...............
}
First of all, can I mock this some how? I tried mocking it, but when I send a message the spring boot application is calling the actual JMS bean not the mock one. Seems like this is not possible.
Even if this is not possible, can I at least aoutowire the bean and somehow check if the receiveMessage method is being invoked. Furthermore, if it is being invoked, the sendEmail part should be faked so that it does not do any work. I have a few ideas such as creating a subclass for testing, but not happy with either of them. So wanted to if you can suggest me a better work around?
One approach is to use different profiles for say development, integration test and production and annotate the different components and your integration test class accordingly.
#Component
#Profile("it")
public class MessageReceiverIT {
#JmsListener(destination = "mailbox", containerFactory = "myFactory")
public void receiveMessage(SimpleMessage email) {
log.info("Integration test pretend to receive {}", email);
// (...)
This is the Integration test that uses the same Application class as the real Application, but if a message is received the MessageReceiverIT.receiveMessage() method will be invoked instead of the production component:
#RunWith(SpringRunner.class)
#SpringBootTest(classes=Application.class)
#ActiveProfiles("it")
public class JmsIntegrationTest {
#Inject
ConfigurableApplicationContext context;
#Test
public void testSend() throws Exception{
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
jmsTemplate.convertAndSend("mailbox", new SimpleMessage("it", "we need more IT"));
// (...)
Also check out Spring Boot Testing for alternative approaches such as the use of #TestConfiguration. I'm using Spring Boot in my examples, but there should be similar approaches if you have a none Spring Boot Application.

Error when deserializing Java client request to WCF service

I have a WCF service with yet only one method:
[OperationContract]
void SaveDocument (InwardDocument doc);
[DataContract]
public class InwardDocument{
[DataMember]
public Citizen Citizen {get;set;}
....
}
[DataContract]
public class Citizen{
[DataMember]
public string LastName {get;set;}
....
}
I've tested the service with both WCF test client and a separate .NET console application. In both cases the service works as expected. But when a java client tries to consume it, a deserialization problem occurs. I've put some markers inside the SaveDocument method to see what causes the problem:
public void SaveDocument(InwardDocument doc){
if(doc==null)
throw new ArgumentnullException("InwardDocument");
if(doc.Citizen==null)
throw new ArgumentnullException("InwardDocument.Citizen");//This exception is thrown when consumed by java client
}
As you can see the first exception is skipped which means doc argument itself is not null but for some reason, the Citizen property is null. The guy who generates the request in java client confirms that the InwardDocument.Citizen property is not null by debugging the code. In fact we've had a problem generating the proxy class in that java client which I describe in this SO thread. So I'm assuming it has something to do with that same problem.Maybe I need to add some more attributes to my classes and their members to care of any such problems that might occur in other platforms? Any suggestions are appreciated.
Have you tried to add Know Type attribute in your InwardDocument class. See link here.
[DataContract]
[KnownType(typeof(Citizen))]
public class InwardDocument{
[DataMember]
public Citizen Citizen {get;set;}
....
}
The problem was caused by incorrect creation of the corresponding JAXBelement instances. The solution to the problem is in this SO thread answer

Passing Objects to a Web Service's method

I have recently started working on (Java)Web Services.
I have certain web methods that accept different arguments - primitives,Maps,HttpServletRequest,FlowJob(Spring) etc.
I got numerous issues while attempting this - from a failed web service deployment saying 'interfaces not supported by JAX-WS' to runtime exceptions 'java.lang.Object cannot be cast to org.w3c.dom.Element' !
I have not put the steps deliberately;all I need to know is that is it possible to pass the above arguments to a Java Web Service method? In short,is something like this possible :
#WebService(serviceName = "WS")
public class WS {
#WebMethod
public Object processJob(MapargsMap){
}
#WebMethod
public String processJob(SomeCustomObject object){
}
}
}
Are there any work-arounds to make JAXB marshal and unmarshal custom objects,Maps etc.?If yes,what are they?
Thanks & regards !

Jetty UserRealm redirect on 3th failed login

If I have a custom Jetty UserRealm implementation and its configured for basic authentication (with SSL), is there any way to get it to go to an specific page after the 3rd failed login?
Well really I just want to display some contact information to the user if they cannot login after 3 attempts.
Alternatively is it possible to display the exception which I throw from the
public Principal authenticate(final String username, final Object credentials, final Request request)
method when its configured as basic authentication?
Thanks
Neil
The BasicAuthenticator is responsible for sending the 403 response when there's no valid credentials in the request.
Looking at the Jetty 6 source, you're best bet is probably to subclass the BasicAuthenticator and override public void sendChallenge(UserRealm realm,Response response)
public class MyAuthenticator extends BasicAuthenticator {
#Override
public void sendChallenge(UserRealm realm, Response response) {
int numberOfAttempts = getNumberOfAuthenticationAttempts();
if (numberOfAttempts > 3) {
sendContactDetails(realm, response);
}
else
super.sendChallenge(realm, response);
}
protected int getNumberOfAuthenticationAttempts() { ... }
protected void sendContactDetails(Response response) { ... }
}
Obviously the problem doing this is that you don't have access to the HttpServletRequest which may make tracking request attempts more difficult. You could probably gain access to this via HttpConnection.getCurrentConnection(). Otherwise the code for BasicAuthenticator doesn't lend itself to extension without a blob of copy/paste, but that may be OK in your case.
I'm ignoring the issue of how you track the number of requests have been made in the same authentication attempt, that's going to be dependent upon how your clients are connecting.
Alternatively you can set the ErrorHandler on the context, which is used when HttpResponse.sendError is called, which will be the case when you throw an exception in your realm.
I'd probably opt to use the first method as it more clearly separates responsibilities.