RESTEasy JSON Exception Response: Send list of objects - java

I have web client (HTML5) and backend server based on RESTEasy webservices and session beans. In my server side code I am iterating over list of objects and per object i am executing some business logic:
List<TestTO> failedTestList = new ArrayList<TestTO>();
for (TestTO testTO : testTOList) {
try {
// some weired business logic :P
} catch (Exception e) {
logger.error("Unable to create data -" + e.getMessage());
failedTestList.add(testTO);
}
}
if (!failedTestList.isEmpty()) {
// throw custom exception embedded with failed TO list
}
I have written custome exception handlers, to catch exceptions and return proper response back to client. This class looks like:
public class CustomExceptionHandler implements ExceptionMapper<CustomException> {
public CustomException getCustomErrorCode(final CustomException customException) {
// Some logic to get cause and set error code
return customException;
}
#Override
public Response toResponse(final CustomException customException) {
return Response.serverError().entity(
"{\"Error Code\":\"" + getCustomErrorCode(customException).getErrorCode() + "\", "
+ "\"Error Message\":\"" + customException.getLocalizedMessage() + "\"}").build();
}
}
I am thinking of an option to send this failed TO list back to client, so that it can understand processing of which objects got failed. I was going through different articles, but could not find anything which fits my requirement.
Please give me an idea and link to reference, on how to implement such requirement. Please note that, my client expects response in JSON format. Please let me know, if you require more information.
Thanks.

Related

Spring 5 Error handling of Postexchange requests

I use an external rest api in my spring application, I can send json post requests to create objects but when a field is incorrect or if there is a duplicate it returns a 400 bad request error, and a body saying what the problem is.
I use Spring 5 with #PostExchange in the following code:
This is used to point spring into the right direction of the external api
public interface HardwareClient {
#PostExchange("/assetmgmt/assets/templateId/C04DBCC3-5FD3-45A2-BD34-8A84CE2EAC20")
String addMonitor(#RequestBody Monitor monitor);
}
This is the helper that is autowired into the class where I have the data that needs to be sent.
#Component
public class HardwareHelper {
private Logger logger = Logger.getLogger(getClass().getName());
#Autowired
HardwareClient hardwareClient;
#Async
public Future<String> addMonitor(MonitorForm monitorForm){
try {
Monitor monitor = new Monitor(monitorForm.objectID(), monitorForm.model(), monitorForm.make(),monitorForm.serialNumber(), monitorForm.orderNumber(),monitorForm.budgetholder(),monitorForm.ownership());
hardwareClient.addMonitor(monitor);
return new AsyncResult<String>("Success");
} catch (Exception e){
logger.info("HardwareHelper.addMonitor error: " + e.getMessage());
//todo error handling
}
return null;
}
}
When an error occurs the logger will print the error but I need to be able to control what happens after based on the response. So I need to see the body of the post request that is returned after. If everything goes well an ID is returned that I can read by printing the results of the addMonitor() method, but this is obviously not possible when it throws an exception as it skips to the catch part. How do I scan the request body when an error is thrown and handle this appropriately

How to parse DFT_P03 message with ZPM segment

I am coding a server application that will receive DFT_P03 messages with an added ZPM segment (which i have created a class for as per the HAPI documentation). Currently i am able to access this field as a generic segment when doing the following :
#Override
public Message processMessage(Message t, Map map) throws ReceivingApplicationException, HL7Exception
{
String encodedMessage = new DefaultHapiContext().getPipeParser().encode(t);
logEntryService.logDebug(LogEntry.CONNECTIVITY, "Received message:\n" + encodedMessage + "\n\n");
try
{
InboundMessage inboundMessage = new InboundMessage();
inboundMessage.setMessageTime(new Date());
inboundMessage.setMessageType("Usage");
DFT_P03 usageMessage = (DFT_P03) t;
Segment ZPMSegment = (Segment)usageMessage.get("ZPM");
inboundMessage.setMessage(usageMessage.toString());
Facility facility = facilityService.findByCode(usageMessage.getMSH().getReceivingFacility().getNamespaceID().getValue());
inboundMessage.setTargetFacility(facility);
String controlID = usageMessage.getMSH().getMessageControlID().encode();
controlID = controlID.substring(controlID.indexOf("^") + 1, controlID.length());
inboundMessage.setControlId(controlID);
Message response;
try
{
inboundMessageService.save(inboundMessage);
response = t.generateACK();
logEntryService.logDebug(LogEntry.CONNECTIVITY, "Message ACKed");
}
catch (Exception ex)
{
response = t.generateACK(AcknowledgmentCode.AE, new HL7Exception(ex));
logEntryService.logDebug(LogEntry.CONNECTIVITY, "Message NACKed");
}
return response;
}
catch (IOException e)
{
logEntryService.logDebug(LogEntry.CONNECTIVITY, "Message rejected");
throw new HL7Exception(e);
}
}
I have created a DFT_P03_Custom class as following :
public class DFT_P03_Custom extends DFT_P03
{
public DFT_P03_Custom() throws HL7Exception
{
this(new DefaultModelClassFactory());
}
public DFT_P03_Custom(ModelClassFactory factory) throws HL7Exception
{
super(factory);
String[] segmentNames = getNames();
int indexOfPid = Arrays.asList(segmentNames).indexOf("FT1");
int index = indexOfPid + 1;
Class<ZPM> type = ZPM.class;
boolean required = true;
boolean repeating = false;
this.add(type, required, repeating, index);
}
public ZPM getZPM()
{
return getTyped("ZPM", ZPM.class);
}
}
When trying to typecast the message to a DFT_P03_Custom instance i get a ClassCastException. As per their documentation, i did create the CustomModelClassFactory class but using this i just get tons of validation errors on the controlId field.
I am already using an identical logic to send custom MFN_M01 messages with an added ZFX segment and that works flawlessly. I understand there is some automatic typecasting being done by HAPI when it receives a DFT_P03 message and that is likely what i need to somehow override for it to be able to give me a DFT_P03_Custom instance instead.
If you have some insight on how i can achieve this without having to use a generic segment instance please help!
Thank you!
I finally figured this out. The only way i got this to work was to generate a conformance profile XML file (using an example message from our application as a base) with the messaging workbench on the HAPI site and use the maven plugin to generate the message and segment classes. Only with these classes am i able to correctly parse a message to my custom class. One thing to note is that it DOES NOT work if i try to use the MSH, PID, PV1 or FT1 classes provided by HAPI and use my Z-segment class. It only works if all the segments are the classes generated by the conformance plugin. This combined with a CustomModelClassFactory class (as shown on the HAPI website) and the proper package structure finally allowed me to access my Z-segment.

Netty how to handle exception on HttpChunkAggregator

I have an application where I am using HttpChunkAggregator to avoid dealing with chunks because I need to parse the whole input as a unit to create the json node. Since HttpChunkAggregator must take a maxContentLength, so I need to handle cases when the incoming request exceeds the content size, I want to return a nice formatted error message to the client. Here is what I am doing:
1: Subclass HttpChunkAggregator and override the exceptionCaught method
public class MyHttpChunkAggregator extends HttpChunkAggregator {
public MyHttpChunkAggregator(int maxContentLength) {
super(maxContentLength);
}
//#Override
public void exceptionCaught(ChannelHandlerContext context, ExceptionEvent ee)
throws Exception {
if (ee.getCause() instanceof TooLongFrameException) {
logger.log(Level.WARNING, "Exception caught in channel handler", ee.getCause());
HttpResponse httpResponse;
try {
//build a http response
httpResponse = //call my function here to build a response
ee.getChannel().write(httpResponse);
ee.getChannel().close();
} catch (IOException ioe) {
Throwables.propagate(ioe);
}
}
}
}
2: Add my customized handler to the pipeline
ChannelPipeline p = Channels.pipeline();
p.addLast("requestDecoder", new HttpRequestDecoder());
p.addLast("responseEncoder", new HttpResponseEncoder());
p.addLast("chunkAggregator", new MyHttpChunkAggregator(1048576)));
//adding the real business handle class to parse the input content
By doing this, I am able to achieve messageRecived NOT being invoked in my real business handler since if the input is too big, I don't want to proceed anymore. However, I am currently see two issues that I want to address:
exceptionCaught is invoked multiple times. I want to send a nice formatted message the first time it happens and then permanently terminate the processing of this request.
because it is invoked multiple times, I saw the following in the log:
java.lang.IllegalStateException: cannot send more responses than requests
On the client side, I got the following error:
org.apache.http.NoHttpResponseException: The target server failed to respond
What I am doing wrong here?
Thanks,

jaxws exception/error handling

I try to build wsdl client for jre5 with JAX-WS RI 2.1.3 its my first expirience. I genereted classes with wsdl2java tool from cxf and wrote wrapper class around client looks like:
public class RequestHelper {
private DataLoadService service = new DataLoadService();
private DataLoadServiceSoap client;
private static String token;
//....my constructor....
public void sendData(data){
try{
if (tokenIsExpired()){
renewToken();
}
client.sendData(data, this.token);
}catch(SOAPFaultException e){
//...work with e
}
}
}
I can't understand how i can process exception in sendData method. I mean, for example, in HTTP we have status codes, we can read status code and decide which type of error we get from server and how we want process them.
In my case i have problem with token expired time. Sometimes sendData request goes to the server for a long time. And the token is no longer valid when the request is already on the server then i get exception with text message "Token expired". And i want catch this type of exception separately, somthing like this:
public class RequestHelper {
private DataLoadService service = new DataLoadService();
private DataLoadServiceSoap client;
private static String token;
//....my constructor....
public void sendData(data){
try{
if (tokenIsExpired()){
renewToken();
}
client.sendData(data, this.token);
}catch(SOAPFaultException e){
//...work with e
}catch(TokenExpiredException e){
renewToken();
client.sendData(data, this.token);
}
}
}
How i can achieve this with JAX-WS RI 2.1.3 library?
UPD:
} catch (SOAPFaultException e) {
SOAPFault f = e.getFault();
f.getFaultString() //yes here we have error description with "Token"
//but with locals dependency, this is not safe handle exception by this value
f.getFaultCode() //here simply string "soap:Receiver", do not know how i can recognize only "token exceptions"
}
Find out what is been returned as part of the SOAPFaultException from the server. If the Exception contains the error message then we can write something like below. note: Error code will be the best way to handle this.
try{
if (tokenIsExpired()){
renewToken();
}
client.sendData(data, this.token);
}catch(SOAPFaultException e){
if(e.getFault().getFaultString().equalsIgnoreCase("Token expired") ) {
renewToken();
client.sendData(data, this.token);
}
......
}
Another way is to have custom SOAP exception thrown from the sever with error code and error message and handle that in the code

BlazeDS - AMFConnection.call giving HTTP 400 status

I'm trying to use BlazeDS's AMFConnection class to connect to pyamf, but when I call AMFConnection.call(), I get HTTP status 400 (Bad Request - "The request body was unable to be successfully decoded."). I'm more or less following this example: (pyamf.org/wiki/ClientHowTo ... sorry, I'm a new user so I guess I can't use hyperlinks. append a "http://" to those if you want to follow them)
Here's my code:
package amfconnectiontest;
import flex.messaging.io.amf.client.AMFConnection;
import flex.messaging.io.amf.client.exceptions.*;
public class Main {
public static void main(String[] args) {
AMFConnection amfConnection = new AMFConnection();
String url = "http://demo.pyamf.org/gateway/recordset";
String service = "service.getLanguages";
try
{
amfConnection.connect(url);
}
catch (ClientStatusException cse)
{
System.out.println(cse);
return;
}
// Make a remoting call and retrieve the result.
try
{
Object result = amfConnection.call(service);
System.out.println("results: " + result.toString());
}
catch (ClientStatusException cse)
{
System.out.println(cse);
}
catch (ServerStatusException sse)
{
System.out.println(sse);
}
// Close the connection.
amfConnection.close();
}
}
Any ideas?
The ability to en/decode BlazeDS specific messages (implementing ISmallMessage) has landed on the PyAMF trunk (r2726 and up). See the related ticket - http://pyamf.org/ticket/581
This version or one very similar is likely to become 0.5. If you need to connect to a BlazeDS service I would suggest checking out the trunk.

Categories

Resources