First of all the final purpose is that i'm trying to inject a DAO connection into an SMD context (Ajax) so i'll ensure that transactions are being Commited (or Rollback), my problem is that i'm not being able to know if the invoke() method throws an exception,
I have the following Interceptor:
public class SomeInterceptor implements Interceptor {
private static final long serialVersionUID = 1L;
#Override
public String intercept(ActionInvocation invocation) {
String result = "";
GenericDAO dao = new GenericDAO();
try {
dao.begin();
invocation.getInvocationContext().put("contextDao", dao);
result = invocation.invoke();
//attempt to solve
Object exception = invocation.getInvocationContext().getValueStack().findValue("exception");
if (exception != null && exception instanceof Exception){
dao.rollback();
} else {
dao.commit();
}
} catch (Exception ex) {
dao.rollback();
System.out.println("ROLLBACK!");
ex.printStackTrace();
} finally {
dao.close();
}
return result;
}
}
The line "attempt to solve" is based on this question. Inside the invoke i'm just throwing a NullPointerException, the result right now is that the exception is being catch before the catch at the Interceptor, however is not a catch that i had set,
#SMDMethod
public HashMap<String,String> someMethod() {
IGenericDAO dao = (IGenericDAO) ActionContext.getContext().get("contextDao");
//dao's deletes, updates that i want to rollback
HashMap<String,String> x = null;
x.put("x","x"); //<---- NPE!
return null;
}
I want ActionInvocation.invoke() to throw the exception so i'll know i need to rollback the DB session. Any approach who succeed this purpose is welcome,
Edit 1:
I've found this question that does almost the same as me but i dont understand how is using rollback (at my point of view is always doing rollback)
Greetings
I didn't found any way to achieve my goal as i wanted, instead i've solved the scenario by doing this:
public class SomeInterceptor implements Interceptor {
private static final long serialVersionUID = 1L;
#Override
public String intercept(ActionInvocation invocation) {
String result = "";
GenericDAO dao = new GenericDAO();
try {
dao.begin();
invocation.getInvocationContext().put("contextDao", dao);
result = invocation.invoke();
dao.rollback();
} catch (Exception ex) {
dao.rollback();
System.out.println("ROLLBACK!");
ex.printStackTrace();
} finally {
dao.close();
}
return result;
}
}
Yes... i removed "commit" instruction at interceptor, instead now im forced to do "commit" at the end of any call that uses the mentioned DAO,
#SMDMethod
public HashMap<String,String> someMethod() {
IGenericDAO dao = (IGenericDAO) ActionContext.getContext().get("contextDao");
//dao's deletes, updates that i want to rollback
HashMap<String,String> x = null;
x.put("x","x"); //<---- NPE!
dao.commit(); //<---- COMMIT!
return null;
}
I dont like this solution but it was all i was able to do. I came out with this like 1 day after posted the question, i waited for an answer until now,
Hope it helps someone,
Related
This question already has an answer here:
How to use mock in a private static final variable in Spock?
(1 answer)
Closed 5 months ago.
How to test the below java catch block where in catch() doesnt throw exception back.
class ErrorTransImpl {
private static final Logger logger = Logger.getLogger(ErrorTransImpl.class);
public int errorCatcher(ErrorTrans transError){
int ct = 0;
if (transError != null){
String query = "INSERT INTO tab_1 (rw1,rw2,rw3,rw4,rw5) VALUES (?,?,?,?,?)";
try {
ct = jdbcTemplate.update(query, new Object[] {transError.col1(),transError.col2(), transError.col3(),transError.col4(),transError.col5()});
}catch (DataAccessException ex) {
logger.error(ex);
}
}
return ct;
}
}
I tried testing as below, but:
1>Unable to get into catch block.
2> Unable to test catch() even if inside as it doesnt throw exception back.
def 'throw DataAccess Exception upon incorrect update'() {
given:
def log = Mock(Logger)
def originalLogger = ErrorTransImpl.logger
ErrorTransImpl.logger = log
ErrorTransImpl errTransImpl = Spy() {
jdbcTemplate >> {
throw new DataAccessException() {
#Override
String getMessage() {
return super.getMessage()
}
}
}
}
when:
errTransImpl.errorCatcher(new ErrorTrans())
then:
// thrown DataAccessException
//Not sure what to assert or test here ??
}
Can anyone help on how i test this?
You need to test the behaviour that
ct = jdbcTemplate.update(query, new Object[] {transError.col1(),transError.col2(), transError.col3(),transError.col4(),transError.col5()});
failed. Or, I don't really like this myself, you can check that the logger.error() was called.
I would like to annotate some of my test cases with KnownFault - which would do pretty much what expectedException does plus some magic using YouTrack's REST API. I would also like to have an IntermittentFailure attribute which would mean that I'm aware that the test might occasionally fail with [exception] [message] but I wouldn't want this to block the rest of my build chain.
After some research I found that my test class should implement IHookable, then I could have something like this:
#Override
public void run(IHookCallBack callBack, ITestResult result) {
callBack.runTestMethod(result);
if (result.getThrowable().getCause() instanceof IllegalArgumentException){
System.out.println("This is expected.");
result.setThrowable(null);
}
else{
System.out.println("Unexpected exception");
}
}
The problem with this is the actual implementation of invokeHookable:
final Throwable[] error = new Throwable[1];
IHookCallBack callback = new IHookCallBack() {
#Override
public void runTestMethod(ITestResult tr) {
try {
invokeMethod(thisMethod, testInstance, parameters);
} catch (Throwable t) {
error[0] = t;
tr.setThrowable(t); // make Throwable available to IHookable
}
}
#Override
public Object[] getParameters() {
return parameters;
}
};
hookable.run(callback, testResult);
if (error[0] != null) {
throw error[0];
}
Unfortunately that last line means that my test case is going to throw an exception no matter what as the error array is completely out of my hands in the run method.
So, what would be the proper way of intercepting an exception and handling it the way I want to?
What you are trying to do is really interesting. You should try to propose changes on https://github.com/cbeust/testng/pull/
But maybe IHookable is not the best listener you can use. Did you try IInvokedMethodListener?
void afterInvocation(IInvokedMethod method, ITestResult result) {
if (result.getThrowable().getCause() instanceof IllegalArgumentException) {
System.out.println("This is expected.");
result.setThrowable(null);
result.setStatus(SUCCESS); // If you want to change the status
} else {
System.out.println("Unexpected exception");
}
}
Here is my DataClientFactory class.
public class DataClientFactory {
public static IClient getInstance() {
return ClientHolder.INSTANCE;
}
private static class ClientHolder {
private static final DataClient INSTANCE = new DataClient();
static {
new DataScheduler().startScheduleTask();
}
}
}
Here is my DataClient class.
public class DataClient implements IClient {
private ExecutorService service = Executors.newFixedThreadPool(15);
private RestTemplate restTemplate = new RestTemplate();
// for initialization purpose
public DataClient() {
try {
new DataScheduler().callDataService();
} catch (Exception ex) { // swallow the exception
// log exception
}
}
#Override
public DataResponse getDataSync(DataKey dataKeys) {
DataResponse response = null;
try {
Future<DataResponse> handle = getDataAsync(dataKeys);
response = handle.get(dataKeys.getTimeout(), TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
// log error
response = new DataResponse(null, DataErrorEnum.CLIENT_TIMEOUT, DataStatusEnum.ERROR);
} catch (Exception e) {
// log error
response = new DataResponse(null, DataErrorEnum.ERROR_CLIENT, DataStatusEnum.ERROR);
}
return response;
}
#Override
public Future<DataResponse> getDataAsync(DataKey dataKeys) {
Future<DataResponse> future = null;
try {
DataTask dataTask = new DataTask(dataKeys, restTemplate);
future = service.submit(dataTask);
} catch (Exception ex) {
// log error
}
return future;
}
}
I get my client instance from the above factory as shown below and then make a call to getDataSync method by passing DataKey object. DataKey object has userId and Timeout values in it. Now after this, call goes to my DataTask class to call method as soon as handle.get is called.
IClient dataClient = DataClientFactory.getInstance();
long userid = 1234l;
long timeout_ms = 500;
DataKey keys = new DataKey.Builder().setUserId(userid).setTimeout(timeout_ms)
.remoteFlag(false).secondaryFlag(true).build();
// call getDataSync method
DataResponse dataResponse = dataClient.getDataSync(keys);
System.out.println(dataResponse);
Here is my DataTask class which has all the logic -
public class DataTask implements Callable<DataResponse> {
private DataKey dataKeys;
private RestTemplate restTemplate;
public DataTask(DataKey dataKeys, RestTemplate restTemplate) {
this.restTemplate = restTemplate;
this.dataKeys = dataKeys;
}
#Override
public DataResponse call() {
DataResponse dataResponse = null;
ResponseEntity<String> response = null;
int serialId = getSerialIdFromUserId();
boolean remoteFlag = dataKeys.isRemoteFlag();
boolean secondaryFlag = dataKeys.isSecondaryFlag();
List<String> hostnames = new LinkedList<String>();
Mappings mappings = ClientData.getMappings(dataKeys.whichFlow());
String localPrimaryAdress = null;
String remotePrimaryAdress = null;
String localSecondaryAdress = null;
String remoteSecondaryAdress = null;
// use mappings object to get above Address by using serialId and basis on
// remoteFlag and secondaryFlag populate the hostnames linked list
if (remoteFlag && secondaryFlag) {
hostnames.add(localPrimaryHostIPAdress);
hostnames.add(localSecondaryHostIPAdress);
hostnames.add(remotePrimaryHostIPAdress);
hostnames.add(remoteSecondaryHostIPAdress);
} else if (remoteFlag && !secondaryFlag) {
hostnames.add(localPrimaryHostIPAdress);
hostnames.add(remotePrimaryHostIPAdress);
} else if (!remoteFlag && !secondaryFlag) {
hostnames.add(localPrimaryHostIPAdress);
} else if (!remoteFlag && secondaryFlag) {
hostnames.add(localPrimaryHostIPAdress);
hostnames.add(localSecondaryHostIPAdress);
}
for (String hostname : hostnames) {
// If host name is null or host name is in local block host list, skip sending request to this host
if (hostname == null || ClientData.isHostBlocked(hostname)) {
continue;
}
try {
String url = generateURL(hostname);
response = restTemplate.exchange(url, HttpMethod.GET, dataKeys.getEntity(), String.class);
// make DataResponse
break;
} catch (HttpClientErrorException ex) {
// make DataResponse
return dataResponse;
} catch (HttpServerErrorException ex) {
// make DataResponse
return dataResponse;
} catch (RestClientException ex) {
// If it comes here, then it means some of the servers are down.
// Add this server to block host list
ClientData.blockHost(hostname);
// log an error
} catch (Exception ex) {
// If it comes here, then it means some weird things has happened.
// log an error
// make DataResponse
}
}
return dataResponse;
}
private String generateURL(final String hostIPAdress) {
// make an url
}
private int getSerialIdFromUserId() {
// get the id
}
}
Now basis on userId, I will get the serialId and then get the list of hostnames, I am suppose to make a call depending on what flag is passed. Then I iterate the hostnames list and make a call to the servers. Let's say, if I have four hostnames (A, B, C, D) in the linked list, then I will make call to A first and if I get the data back, then return the DataResponse back. But suppose if A is down, then I need to add A to block list instantly so that no other threads can make a call to A hostname. And then make a call to hostname B and get the data back and return the response (or repeat the same thing if B is also down).
I have a background thread as well which runs every 10 minutes and it gets started as soon we get the client instance from the factory and it parses my another service URL to get the list of block hostnames that we are not supposed to make a call. Since it runs every 10 minutes so any servers which are down, it will get the list after 10 minutes only, In general suppose if A is down, then my service will provide A as the block list of hostnames and as soon as A becomes up, then that list will be updated as well after 10 minutes.
Here is my background thread code DataScheduler-
public class DataScheduler {
private RestTemplate restTemplate = new RestTemplate();
private static final Gson gson = new Gson();
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
public void startScheduleTask() {
scheduler.scheduleAtFixedRate(new Runnable() {
public void run() {
try {
callDataService();
} catch (Exception ex) {
// log an error
}
}
}, 0, 10L, TimeUnit.MINUTES);
}
public void callDataService() throws Exception {
String url = null;
// execute the url and get the responseMap from it as a string
parseResponse(responseMap);
}
private void parseResponse(Map<FlowsEnum, String> responses) throws Exception {
// .. some code here to calculate partitionMappings
// block list of hostnames
Map<String, List<String>> coloExceptionList = gson.fromJson(response.split("blocklist=")[1], Map.class);
for (Map.Entry<String, List<String>> entry : coloExceptionList.entrySet()) {
for (String hosts : entry.getValue()) {
blockList.add(hosts);
}
}
if (update) {
ClientData.setAllMappings(partitionMappings);
}
// update the block list of hostnames
if (!DataUtils.isEmpty(responses)) {
ClientData.replaceBlockedHosts(blockList);
}
}
}
And here is my ClientData class which holds all the information for block list of hostnames and partitionMappings details (which is use to get the list of valid hostnames).
public class ClientData {
private static final AtomicReference<ConcurrentHashMap<String, String>> blockedHosts = new AtomicReference<ConcurrentHashMap<String, String>>(
new ConcurrentHashMap<String, String>());
// some code here to set the partitionMappings by using CountDownLatch
// so that read is blocked for first time reads
public static boolean isHostBlocked(String hostName) {
return blockedHosts.get().contains(hostName);
}
public static void blockHost(String hostName) {
blockedHosts.get().put(hostName, hostName);
}
public static void replaceBlockedHosts(List<String> blockList) {
ConcurrentHashMap<String, String> newBlockedHosts = new ConcurrentHashMap<>();
for (String hostName : blockList) {
newBlockedHosts.put(hostName, hostName);
}
blockedHosts.set(newBlockedHosts);
}
}
Problem Statement:-
When all the servers are up (A,B,C,D as an example) above code works fine and I don't see any TimeoutException happening at all from the handle.get but if let's say one server (A) went down which I was supposed to make a call from the main thread then I start seeing lot of TimeoutException, by lot I mean, huge number of client timeouts happening.
And I am not sure why this is happening? In general this won't be happening right since as soon as the server goes down, it will get added to blockList and then no thread will be making a call to that server, instead it will try another server in the list? So it should be smooth process and then as soon as those servers are up, blockList will get updated from the background thread and then you can start making a call.
Is there any problem in my above code which can cause this problem? Any suggestions will be of great help.
In general, what I am trying to do is - make a hostnames list depending on what user id being passed by using the mappings object. And then make a call to the first hostname and get the response back. But if that hostname is down, then add to the block list and make a call to the second hostname in the list.
Here is the Stacktrace which I am seeing -
java.util.concurrent.TimeoutException\n\tat java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:258)
java.util.concurrent.FutureTask.get(FutureTask.java:119)\n\tat com.host.client.DataClient.getDataSync(DataClient.java:20)\n\tat
NOTE: For multiple userId's, we can have same server, meaning server A can get resolve to multiple userId's.
In DataClient class, at the below line:
public class DataClient implements IClient {
----code code---
Future<DataResponse> handle = getDataAsync(dataKeys);
//BELOW LINE IS PROBLEM
response = handle.get(dataKeys.getTimeout(), TimeUnit.MILLISECONDS); // <--- HERE
} catch (TimeoutException e) {
// log error
response = new DataResponse(null, DataErrorEnum.CLIENT_TIMEOUT, DataStatusEnum.ERROR);
} catch (Exception e) {
// log error
response = new DataResponse(null, DataErrorEnum.ERROR_CLIENT, DataStatusEnum.ERROR);
----code code-----
You have assigned a timeout to handle.get(...), which is timing out before your REST connections can respond. The rest connections themselves may or may not be timing out, but since you are timing out of get method of future before the completion of the execution of the thread, the blocking of hosts has no visible effect, while the code inside the call method of DataTask may be performing as expected. Hope this helps.
You asked about suggestions, so here are some suggestions:
1.) Unexpected return value
Method returns unexpectedly FALSE
if (ClientData.isHostBlocked(hostname)) //this may return always false! please check
2.) Exception-Handling
Are you really sure, that a RestClientException occurs?
Only when this exception occured, the host will be added to blocked list!
Your posted code seems to ignore logging (it is commented out!)
...catch (HttpClientErrorException ex) {
// make DataResponse
return dataResponse;
} catch (HttpServerErrorException ex) {
// make DataResponse
return dataResponse;
} catch (RestClientException ex) {
// If it comes here, then it means some of the servers are down.
// Add this server to block host list
ClientData.blockHost(hostname);
// log an error
} catch (Exception ex) {
// If it comes here, then it means some weird things has happened.
// log an error
// make DataResponse
}
This is a very simple example of hibernate usage in java: a function that when it's called, it creates a new object in the database. If everything goes fine, the changes are stored and visible immediately (no cache issues). If something fails, the database should be restored as if this function was never called.
public String createObject() {
PersistentTransaction t = null;
try {
t = PersistentManager.instance().getSession().beginTransaction();
Foods f = new Foods(); //Foods is an Hibernate object
//set some values on f
f.save();
t.commit();
PersistentManager.instance().getSession().clear();
return "everything allright";
} catch (Exception e) {
System.out.println("Error while creating object");
e.printStackTrace();
try {
t.rollback();
System.out.println("Database restored after the error.");
} catch (Exception e1) {
System.out.println("Error restoring database!");
e1.printStackTrace();
}
}
return "there was an error";
}
Is there any error? Would you change / improve anything?
I don't see anything wrong with your code here. As #Vinod has mentioned, we rely on frameworks like Spring to handle the tedious boiler plate code. After all, you don't want code like this to exist in every possible DAO method you have. They makes things difficult to read and debug.
One option is to use AOP where you apply AspectJ's "around" advice on your DAO method to handle the transaction. If you don't feel comfortable with AOP, then you can write your own boiler plate wrapper if you are not using frameworks like Spring.
Here's an example that I crafted up that might give you an idea:-
// think of this as an anonymous block of code you want to wrap with transaction
public abstract class CodeBlock {
public abstract void execute();
}
// wraps transaction around the CodeBlock
public class TransactionWrapper {
public boolean run(CodeBlock codeBlock) {
PersistentTransaction t = null;
boolean status = false;
try {
t = PersistentManager.instance().getSession().beginTransaction();
codeBlock.execute();
t.commit();
status = true;
}
catch (Exception e) {
e.printStackTrace();
try {
t.rollback();
}
catch (Exception ignored) {
}
}
finally {
// close session
}
return status;
}
}
Then, your actual DAO method will look like this:-
TransactionWrapper transactionWrapper = new TransactionWrapper();
public String createObject() {
boolean status = transactionWrapper.run(new CodeBlock() {
#Override
public void execute() {
Foods f = new Foods();
f.save();
}
});
return status ? "everything allright" : "there was an error";
}
The save will be through a session rather than on the object unless you have injected the session into persistent object.
Have a finally and do a session close also
finally {
//session.close()
}
Suggestion: If this code posted was for learning purpose then it is fine, otherwise I would suggest using Spring to manage this boiler plate stuff and worry only about save.
I am writing a parser for csv-files, and sometimes I get NumberFormatException. Is there an easy way to print the argument value that caused the exception?
For the moment do I have many try-catch blocks that look like this:
String ean;
String price;
try {
builder.ean(Long.parseLong(ean));
} catch (NumberFormatException e) {
System.out.println("EAN: " + ean);
e.printStackTrace();
}
try {
builder.price(new BigDecimal(price));
} catch (NumberFormatException e) {
System.out.println("Price: " + price);
e.printStackTrace();
}
I would like to be able to write something like:
try {
builder.ean(Long.parseLong(ean));
} catch (NumberFormatException e) {
e.printMethod(); // Long.parseLong()
e.printArgument(); // should print the string ean "99013241.23"
e.printStackTrace();
}
Is there any way that I at least can improve my code? And do this kind of printing/logging more programmatically?
UPDATE: I tried to implement what Joachim Sauer answered, but I don't know if I got everything right or if I could improve it. Please give me some feedback. Here is my code:
public class TrackException extends NumberFormatException {
private final String arg;
private final String method;
public TrackException (String arg, String method) {
this.arg = arg;
this.method = method;
}
public void printArg() {
System.err.println("Argument: " + arg);
}
public void printMethod() {
System.err.println("Method: " + method);
}
}
The Wrapper class:
import java.math.BigDecimal;
public class TrackEx {
public static Long parseLong(String arg) throws TrackException {
try {
return Long.parseLong(arg);
} catch (NumberFormatException e) {
throw new TrackException(arg, "Long.parseLong");
}
}
public static BigDecimal createBigDecimal(String arg) throws TrackException {
try {
return new BigDecimal(arg);
} catch (NumberFormatException e) {
throw new TrackException(arg, "BigDecimal.<init>");
}
}
}
Example of use:
try {
builder.ean(TrackEx.createBigDecimal(ean));
builder.price(TrackEx.createBigDecimal(price));
} catch (TrackException e) {
e.printArg();
e.printMethod();
}
EDIT: Same question but for .NET: In a .net Exception how to get a stacktrace with argument values
You can easily implement such detailed information on custom-written exceptions, but most existing exceptions don't provide much more than a detail message and a causing exception.
For example you could wrap all your number parsing needs into a utility class that catches the NumberFormatException and throws a custom exception instead (possibly extending NumberFormatException).
An example where the some additional information is carried via the exception is SQLException which has
a getErrorCode() and a getSQLState() method.
Create a method such as private parse (String value, int type) which does the actual parsing work including exception handling and logging.
parse(ean, TYPE_LONG);
parse(price, TYPE_BIG_DECIMAL);
Where TYPE_ is just something to tell the method how it should parse the value.
Similar to another suggestion, you could extract Long.parseLong(ean) into it's own method (either privately within the class or public on another utility sort of class).
This new method would handle any custom logic AND you could test it in isolation. Yay!