React to duplicate unique key error in MongoDB's java driver - java

I am developing an application which uses MongoDB, and one of my fields must be unique. This field is calculated by the application based on another value in the DB. If I am running multiple instances of the application, however, I can imagine the applications calculating the same value.
In this case, I would like to catch the exception, recalculate the value, and try again. Unfortunately, the exception raised seems to be a simple MongoWriteException. It seems to me that the only way I will know that it is due to the duplicate key issue is based on the exception message, but parsing and making use of the message really doesn't feel right. Are there any other options?

You can check the ErrorCategory of the error inside the MongoWriteException and confirm it was due to a duplicate key using getCategory():
catch(MongoWriteException ex) {
if(ex.getError().getCategory() == ErrorCategory.DUPLICATE_KEY) {
//handle duplicate key error
} else {
//do something else...
}
}

Related

Is executing code inside of an exception bad in this case?

I have this specific scenario:
my exceptions have a code and a localized message
The thrower just knows the code
The catcher expects a localized message
The localization is inside of a DB table
Would it be wrong something like this:
public class MyException{
public MyException(int code){
try{
this.message = db.selectMessage(code);
}catch(Exception ex){
this.message = "";
}
}
}
This would completely hide from the thrower the fact that the message is localized.
Alternatively I should go with something like this:
public class ExceptionUtils{
public static throwMyException(int code) throws MyException{
String message = db.selectMessage(code);
throw new MyException(code, message);
}
}
But this requires the thrower to know about this util.
I would suggest using ResourceBundle class as it is widely accepted way for localization. This way you store your messages in files as oppose to DB. Also reading your messages from those files is handled by JVM and you don't have to write your own code for it. However, if you insist on using DB, I would sudgest to read all your messages from DB into file system or onto your memory during your app initialization and then you don't have to read from DB and risk DB connectivity failure for each exception.
This is a better approach:
public class MyException extends Exception {
private int code;
public MyException(String message, int code) {
super(message);
this.code = code;
}
public int getCode() {
return code;
}
}
Usage:
Integer messageCode = null;
try {
// do stuff
} catch (MyException e) {
logger.log(e.getMessage(), e); // log actual message
messageCode = e.getCode();
}
if(messageCode != null /* && you really want to show it to end user */) {
String localizedMessage = db.selectMessage(code);
// show localized message to end user
}
Adavantages:
You don't need a Util class to throw exceptions.
You don't need to access db every time you throw an exception but
only when you catch it and "decide" to fetch the message if you want
to show it to user.
You don't need to catch an exception inside another exception.
You don't lose the actual non-localized message.
You don't lose actual stack trace in case db.getMessage() fails and throws exception.
Edit:
There is a dispute about whether the if part is a good idea or not so I have to elaborate.
message and localized version of message, these are very different.
Message:
is a description of what has gone wrong.
is what you see in console and in log records when exception occurs.
is in English.
must be shown regardless of any conditions and if not shown it's considered a very bad practice.
Localized Message:
is a translation of Message for the benefit of End User and not programmer.
is not in English.
is not expected to be shown either in console or log records.
is only needed when interacting with End User in UI.
is not expected to be used in non-UI related parts of code.
In the actual code provided by asker, message is replaced by localized message which violates expected behavior of a well-designed exception so I separated these two. In my code the message is Always shown and can be logged whenever exception occurs regardless of any conditions; Fetching localized message occurs only IF you actually need to interact with End Users. So access to DB can be skipped when you are not interacting with them.
the catch block is designed to do some actions after an exception occurs in your program, hence i would recommend you to provide some of the exception handling code in the catch block as it will allow others to understand your program efficiently
It is not bad as long it is code that helps you best handle the exception
The problem is one of too many moving parts. If your database access within the catch block fails by throwing an exception - and it can fail for any one of a number of reasons - then you won't ever see even your original exception. The same goes for anything you do in the catch block that could itself throw an exception.
This has recently happened to me, in fact, in legacy code (different language though same idea). Man is that a pain when you know your production system is failing for some specific reason but you have no idea what that specific reason is ...
It may be the case that your routine db.selectMessage() is itself protected against and won't throw an exception. Ok then. But it's going to be your responsibility to check that in every catch block you write. It's better to go with a design approach that doesn't involve catch blocks that do much of anything except things known to be 'safe'.
In some languages, by the way, catching all exceptions catches some really nasty ones (in Java, those aren't usually subclasses of java.lang.Exception though). And sometimes you really don't want to do anything unnecessary, 'cause you don't know what state you're in and what'll happen.
In this case, you're probably going to be logging that exception somewhere (or otherwise notifying the user). That logging code is (or should be) centralized in your application. That's the place to carefully translate/localize/interpret the exception code ... someplace where in one place you can make sure it works and is protected ... same as the logging code itself.

Handling exceptions in Java (GWT)

I'm currently dealing with exceptions handling and I'm wondering where should I catch them.
Here is an stack from the GWT app :
A helper with a method which can throws NumerFormatExeption
(FormHelper.java)
A widget which uses this helper (CostWidget.java)
A presenter which calls this widget to retrieve data (BuildingPresenter.java)
FormHelper.java
public static Integer prepareIntegerForDb(String string) {
return Integer.parseInt(string);
}
CostWidget.java
public DetailCostProxy getCostDetail() {
...
costDetail.setQuantity(FormHelper.prepareDoubleForBd(qtTextBox.getText()));
...
return costDetail;
}
public List<DetailCostProxy> getCostList() {
...
costDetails .add(ligneCout.getCostDetail());
...
}
BuildingPresenter.java
public void saveBuilding(final BuildingProxy inter, final CollectRequestContext savecontext) {
savecontext.save(display.getCostWidget().getCoutList()).fire(new Receiver<BuildingProxy >() {....
}
I am thinking about :
1) adding "throws NumberFormatException" to prepareIntegerForDb() in the helper
2) adding "throws NumberFormatException" to getCostDetail() in the widget
3) adding "throws NumberFormatException" to getCostList() in the widget
4) caching the exception in the presenter (in saveBuilding)
The aim is :
to log the exception
to provide the user with a message saying that something went wrong
What do you think about this approach considering that this in an example and I will have to apply this pattern into the entire app (more than 20 presenters).
Is my way a good way to handle exceptions in GWT ? or should I log the error directly in the helper or elsewhere ?
prepareIntegerForDB() should throw the exception. This happens automatically when Integer.parse() fails, and you do not have to actually throw the Exception.
getCostDetail() should explicitly catch and throw the exception, and possibly expand upon why it was thrown. Something like "The cost was not in a readable format". That method is responsible for only that one line.
getCostList() should catch and handle the exceptions. That method is responsible for an entire collection. If you do not handle the bad data here, you will lose the good data. Here is one way to handle the bad data.
public List<DetailCostProxy> getCostList() {
...
try {
DetailCostProxy cost = lineCount.getCostDetail()
costDetails.add(cost);
catch (NumberFormatException e) {
costDetails.add(null);
}
...
}
Finally, the method that displays your data to the user should interpret the data passed to it before displaying it. If you used my example above, this would be as simple as checking for null values.
What do you think about this approach considering that this in an
example and I will have to apply this pattern into the entire app
(more than 20 presenters).
Adding throws NumberFormatException declarations won't help you to "provide the user with a message saying that something went wrong". NumberFormatException-s are RuntimeException-s so the throws declaration won't even force to try/catch in the code that uses these methods.
Is my way a good way to handle exceptions in GWT ? or should I log the
error directly in the helper or elsewhere ?
4) catching the exception in the presenter (in saveBuilding)
The aim is :
to log the exception
to provide the user with a message saying that something went wrong
This question is not specific to GWT.
To catch the Exception is a good idea if you know how to deal with it.
If you signal the error to the user, you need to be able to have the user decide how to handle the issue (for example a pop-up message proposing two actions to resume the application execution).

Servlet catch unique constraint exception

I'm trying to insert some data into the table named rmas.
The table format is
|rcode|rname|vcode|vanme
Here, I set primary key for rcode.
When I'm inserting a record with existing rcode, it displays something like ORA-0000-1 unique constraint Violated..
If I'm using the following code, it displays the message even in the case of other errors.
catch(Exception e)
{
//out.println("rcode already exists");
}
So, I want to catch that primary key exception only and display as "rcode already exist". Is it possible? If yes, then how?
Thanks in advance
Exception is the parent of all the exception. If you have catch(Exception e) { } block written then all the exceptions will fall into this category. You need to find which exception the compiler is returning. Say if your compiler returns this exception SQLIntegrityConstraintViolationException then the following block would come
catch(SQLIntegrityConstraintViolationException e)
{
// Error message for integrity constraint violation
}
catch(NullPointerException e)
{
// Null Pointer exception occured.
}
catch(Exception e)
{
// Other error messages
}
In this way you can have any number of exception blocks. But make sure more specific exception types are first written and then the parent exceptions
You're catching an Exception, which is the superclass of all exceptions. By catching this you use the Pokémon Style ("Gonna catch 'em all!") which is, in general, a bad practice since you lose the ability to take different courses of action based on the particular exception that was thrown in that block of code.
Catch only the exception related to the constraint violation to avoid showing the message for every exception.
Why would you like to do this on a servlet escapes me, but I suggest you take a look at the architecture of your solution and provide a layered approach, catching this exceptions in the Persistence tier and returning your own result code, that defines which message should be displayed to the user.
Note: I used Result code and not Error code to allow returning a code for a successful operation.
I wouldn't have any such code in a servlet. I think it belongs in a class that lives in your persistence tier. Servlets are HTTP listeners; they shouldn't have database code in them.
Have your interface-based persistence class catch that exception and handle it appropriately. Write an inteface-based service that uses the persistence class to fulfill the use case. Let the servlet call the service and figure out what to display next based on what happens.
It's called a layered architecture. I'd recommend it highly.
In my case in a spring boot application, I used DataIntegrityViolationException to catch unique constraint like this:
try {
userRepository.save(user);
log.debug("Created Information for User: {}", user);
} catch (DataIntegrityViolationException e) {
}
I would catch in the following manner:
catch(Exception ex){
if(ex.getMessage().contains("UNIQUE KEY"))
return "Error - Unique Key Violation!!";
else if(ex.getMessage().contains("FOREIGN KEY"))
return "Error - Foreign Key Violation!!";
else
return "Other Error: " + ex.getMessage();
}
Hope that's simple and functional!!

How to Continue bulk inserts when exception occurs

I am using jpa with hibernate I want to insert 100 record in Database, suppose I get exception JDBC batch update in 50th record insertion i need to handling the Exception and I need to persist remaining record to DB.
Code:
private List<TempCustomers> tempCustomer =new ArrayList<TempCustomers>();
public String migrateCustomers() {
TempCustomers temp = null;
for(DoTempCustomers tempCustomers:doTempCustomers){
try {
temp=new TempCustomers();
BeanUtils.copyProperties(temp, tempCustomers);
tempCustomer.add(temp);
entityManager.persist(temp);
}catch (Exception e) {
tempCustomer.add(temp);
entityManager.persist(temp);
log.info("Exception ..."+e);
return "null";
}
}
return "null";
}
Nagendra.
What Mr. RAS is telling is correct.
For example you are persisting 100 entities and exception happened in the 50th Entity persist. You have exception handler it will work for you to handle the situation. It ll skip the current one and process the next one.
Things to take care as follows:
1- Your exception handling should be within the loop, hope you already have it.
2- For exception you can save the entity in different list for further analysis for error details. do it in the exception catch block.
3- I am not sure whether you are using the transaction manager or not, transaction need to take care.
--
In the 2nd case please remove the line...
entityManager.persist(temp);
as you already know this throws exception. keep it in the list for your further analysis. better put into any queue(ActiveMQ) upto you.
Best solution for this is again:
Validate all your data before persist...to minimize the exception. runtime things need your re-processing again and that should be manual.

"Element must contain value for attribute id" in Google Calendars API

I'm getting an exception when using the Java Google Calendar API that I can't make heads or tails of. What I'm doing is creating a connector to Google Calendar that inserts events. Some of these events are repeating, and some of those have exceptions to the repeat pattern. I've been very successful in creating events and repeating events, but am having these problems when trying to make exceptions.
The code I'm using is:
CalendarEventEntry gglAppt = new CalendarEventEntry();
OriginalEvent originallink = new OriginalEvent();
originallink.setOriginalId(repeatingEvent.getIcalUID());
When originalWhen = new When();
originalWhen.setStartTime(DateTime.parseDate("2011-05-01"));
originallink.setOriginalStartTime(originalWhen);
When exceptionWhen = new When();
exceptionWhen.setStartTime(DateTime.parseDate("2011-05-10"));
gglAppt.setOriginalEvent(originallink);
gglAppt.setStatus(EventStatus.CANCELED);
gglAppt.addTime(exceptionWhen);
try {
//I can vouch for this line, it works elsewhere in the code.
//CalendarServiceManager is a custom class if you didn't guess ;-)
CalendarServiceManager.getInstance().addNewEvent(gglAppt, http://www.google.com/calendar/feeds/default/calendars/testemail%40gmail.com);
} catch (IOException e) {
e.printStackTrace();
} catch (ServiceException e) {
e.printStackTrace();
}
The exception is:
com.google.gdata.util.InvalidEntryException: Bad Request
Element must contain value for attribute id
at com.google.gdata.client.http.HttpGDataRequest.handleErrorResponse(HttpGDataRequest.java:594)
at com.google.gdata.client.http.GoogleGDataRequest.handleErrorResponse(GoogleGDataRequest.java:563)
at com.google.gdata.client.http.HttpGDataRequest.checkResponse(HttpGDataRequest.java:552)
at com.google.gdata.client.http.HttpGDataRequest.execute(HttpGDataRequest.java:530)
at com.google.gdata.client.http.GoogleGDataRequest.execute(GoogleGDataRequest.java:535)
at com.google.gdata.client.Service.insert(Service.java:1409)
at com.google.gdata.client.GoogleService.insert(GoogleService.java:599)
at com.testapp.google.CalendarServiceManager.addNewEvent(CalendarServiceManager.java:138)
at com.testapp.google.GoogleAdapter.dealWithExceptions(GoogleAdapter.java:581)
...etc
My understanding from what I've seen around the interwebs is that an attribute ID is something you set for Google objects for you to keep track of them. I wouldn't know where to set an attribute ID, and I'm puzzled as to why I haven't had to set an attribute ID for any of the other events I've submitted.
What is this exception that's being thrown? What does it mean and what do I do about it?
Any help would be greatly appreciated as always.
Found the answer to my question here:
http://code.google.com/apis/calendar/community/forum.html?place=topic%2Fgoogle-calendar-help-dataapi%2FvD6xahZq8ms%2Fdiscussion
Turns out repeatingEvent didn't have an id yet. I had just created it and sent it off to the server, but hadn't updated the local object with the one returned from the server; the one with an id.

Categories

Resources