I want to rollback a transaction in function say xyz()
This xyz calls another function say abc() within it that has its own transaction tx. If due to an exception Abc() rolls back its transaction,hence transaction in xyz() should also get rolled back.
How can i rollback transaction in xyz() ?
This is my code.
public String execute() throws Exception {
// viewReadOnly();
Session sf=null;
Transaction tx=null;
try {
sf = HibernateUtil.getSessionFactory().getCurrentSession();
tx = sf.getTransaction();
tx.begin();
//sosFile.setCmaId(1);
//sosFile.setSosFileId(1);
//sosFile.setHeadImage(new ImageService().readImageOldWay(headFile));
//sosFile.setFootImage(new ImageService().readImageOldWay(footFile));
//if(new ImageService().readImageOldWay(headFile) != null)
System.out.println("FLAG="+flag);
if(headFile!=null)
{
for (int i = 0; i < headFile.length; i++) {
if (headFile != null) {
sosOrder = new SOSCustomerOrderFile();
sosOrder.setCmaId(cmaId);
sosOrder.setFileData(new ImageService().readImageOldWay(headFile[i]));
sosOrder.setFileName(new File(sosorderfilename[i]).getName());
sosOrder.setSosStage(flag);
sf.saveOrUpdate(sosOrder);
}
}
}
if(footFile!=null)
{
for (int i = 0; i < footFile.length; i++) {
if (footFile != null) {
sosCheque.setCmaId(cmaId);
sosCheque.setFileData(new ImageService().readImageOldWay(footFile[i]));
sosCheque.setFileName(new File(soschequefilename[i]).getName());
sosCheque.setSosStage(flag);
sf.saveOrUpdate(sosCheque);
}
}
}
// tx.begin();
// sf.close();
/*Session sf1 = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction tx1 = sf1.getTransaction();
tx1.begin();*/
if (cheque_no_hidden != null || cheque_amount_hidden != null || cheque_bank_hidden != null || cheque_date_hidden != null) {
for (int i = 0; i < chequeCounter; i++) {
cheque_no = cheque_no_hidden.split(",");
cheque_amount = cheque_amount_hidden.split(",");
cheque_bank = cheque_bank_hidden.split(",");
cheque_date = cheque_date_hidden.split(",");
SOSChequeDetails sosChequeD = new SOSChequeDetails();
sosChequeD.setChequeNo(cheque_no[i]);
sosChequeD.setChequeAmount(cheque_amount[i]);
sosChequeD.setChequeBank(cheque_bank[i]);
sosChequeD.setChequeDate(cheque_date[i]);
sosChequeD.setCmaId(cmaId);
sosChequeD.setSosStage(flag);
sf.saveOrUpdate(sosChequeD);
// tx1.begin();
// sf1.close();
}
}
if(saveSOSValue.saveSOS(sosValues, cmaId,flag,sf,tx))
{
sosValues.setFlag(1);
}
else
{
sosValues.setFlag(2);
}
if(flag.equalsIgnoreCase("sosSUBMIT"))
{
CmaDetails cmaD = (CmaDetails) sf.get(CmaDetails.class, cmaId);
/* for(int j=0;j<5;j++){
LeaveManagementManager manager=new LeaveManagementManager();
Userinfo userinfoLeave=manager.getUserInfoObjforsos(sosWorkflow_status);
workflow.setFromDesignation(userinfoLeave.getWorkflowdesignation().getWorkflowDesignationId());
List<Workflow> workflowListTemp=new ArrayList<Workflow>();
workflowListTemp=(new WorkflowService().performAction(workflow));
if(userinfoLeave.getOutOfOffice()!=null && userinfoLeave.getOutOfOffice().equals("OOO")){
date.setSeconds(date.getSeconds()+1);
wfs=makeEntryInWorkflow(sdm,formater,now, date, workflowListTemp, cmaDetails, query, i, ToEmailIdTemp, ToEmailId,wfs,null);
}else{
j=5;
}
}*/
boolean decideRollback=approveSOSvalue.ApprovalSOSWorkflow(sosWorkflow_status,sosValues,cmaD,"create",1,"flag");
if(decideRollback==false){
tx.rollback();
}
}
} catch (Exception e) {
if (tx!=null) tx.rollback();
e.printStackTrace();
}
viewDocuments();
viewCheques();
/* ComplianceCMA complianceCMA = new ComplianceCMA();
cmaDetails = complianceCMA.getCma(cmaId);
cmaDetails.setStage(Constants.STAGE_SOS_UPLOAD);
UpdateCMA updateStage = new UpdateCMA();
updateStage.performAction(cmaDetails);*/
ViewSOSDetails viewsos=new ViewSOSDetails();
viewsos.home();
return SUCCESS;
}
This function calls
public boolean ApprovalSOSWorkflow(SOSWorkflow_status sosWorkflowstatuscomment,SOSValues sosValues,CmaDetails cmaId,String Action,int bpaID,String flag)
function.
Please help.
Best way to solve this is to not use a new transaction in abc(). Start the transaction in xyz and use transaction prorogation required in abc(). That way Tx in abc() will lap onti the the Tx which xyz() started and if abc throws an exception catch it and rollback the Tx so that the Tx in Xyz also rolls back. Are you using Spring? If not then you should Spring makes solving such cases very easy using annotations.
You could have transaction Abc() return a boolean stating whether it had to roll itself back, and then use that boolean in xyz() to determine whether to roll itsel back.
Related
Can someone tell me why my entityTransaction doesn't works?
rollback() has no effect, commit() too, i think also begin(). I tried to disable autocommit:
spring.datasource.auto-commit=false
spring.datasource.hikari.auto-commit=false
but there is no effect after that, still that transactions don't work. Here is my service:
#Service
public class MyService {
...
#Autowired
private final JdbcTemplate jdbcTemplate;
...
#Autowired
private EntityManagerFactory entityManagerFactory;
...
#Transactional
public ArrayList<String> executeSQL(String[] split) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction entityTransaction = entityManager.getTransaction();
ArrayList<String> listException = new ArrayList<String>();
boolean flag = false;
for (int i = 0; i < split.length; ++i) {
String query = split[i];
try {
entityTransaction.begin();
mapList = jdbcTemplate.queryForList(query);
entityTransaction.commit();
listException.add("Success!");
} catch (Exception e1) {
entityTransaction.rollback();
try {
entityTransaction.begin();
int rows = jdbcTemplate.update(query);
entityTransaction.commit();
listException.add("Sucesss! { [" + rows + "] <-- affected rows }");
} catch (Exception e2) {
entityTransaction.rollback();
flag = true;
listException.add(e2.getCause().getMessage());
}
}
}
entityManager.close();
if(flag){
mapList = emptyMapList;
updateFlag = false;
}
else{
updateFlag = true;
}
return listException;
}
...
When I am trying to save a new object using create case method..error is coming at session .saveORUpdate(createcasevalueentity)... I.E. illegal attempt to associate a collection with two open session
#Override
public Map createCase(Patientcase createCase, Integer patientID, String userName
// changes by sahil.sharma08 start here
/* ,List surgeonsID,
List anesthesiologistID, Integer specialityID, Integer operationTheaterNoID
// changes by sahil.sharma08 start here
*/) throws Exception
{
LOGGER.info("Logger Name: " + LOGGER.getName());
Session session = null;
Map<String, String> result = new HashMap<String, String>();
Patient createPatientEntity;
try
{
// opens a new session from the session factory
SessionFactory sessionFactory = HibernateUtilities.createSessionFactory();
// For logging audit record
AuditLogInterceptor interceptor = new AuditLogInterceptor();
session = sessionFactory.withOptions().interceptor(interceptor).openSession();
interceptor.setSession(session);
interceptor.setUserName(userName);
session.getTransaction().begin();
createPatientEntity = (Patient) session.get(Patient.class, patientID);
createCase.setPatient(createPatientEntity);
if (createPatientEntity == null)
{
result.put("Error", "Patient ID does not Exist");
return result;
}
// changes by sahil.sharma08 start here
//Long caseID = createCase.getCaseId();
// changes by sahil.sharma08 end here
Query query = session.createQuery("delete FROM Casevalues cve WHERE cve.patientcase.caseId = ?");
// changes by sahil.sharma08 start here
//query.setParameter(0, caseID);
query.setParameter(0, createCase.getCaseId());
// changes by sahil.sharma08 end here
query.executeUpdate();
if(createCase.getSpeciality()!=null && !createCase.getSpeciality().equals(""))
{
Casevalues createCaseValuesEntity = new Casevalues();
createCaseValuesEntity.setPatientcase(createCase);
Entityvalues valuesEntity =(Entityvalues) session.get(Entityvalues.class, new Integer(createCase.getSpeciality()));
createCaseValuesEntity.setEntityvalues(valuesEntity);
session.saveOrUpdate(createCaseValuesEntity);
createCase.setSpeciality(valuesEntity.getEntityValue());
}
// changes by sahil.sharma08 end here
session.saveOrUpdate(createCase); // Persisting createCase Entity in database
// changes by sahil.sharma08 end here
result.put("patientId", createCase.getPatient().getPatientId().toString());
result.put("caseId", createCase.getCaseId().toString());
session.getTransaction().commit(); // Session commit
}
catch (Exception e)
{
if (session != null && session.getTransaction() != null)
{
// If transaction is open,rollback
session.getTransaction().rollback();
}
LOGGER.log(Level.INFO, "Exception occur", e);
throw e;
}
finally
{
if (session != null)
{
session.close(); // Session close
}
}
return result;
}
I have a method to unit test called addSong(song,userId) in service class. I am calling three methods inside it from Dao class. I am using Easy mock to mock dao class. In the setup I first mock all the methods I am calling in addSong(song,userId), and then calling the service.addsong(song,userId) method fot test.
But I am getting the following error:
Java.lang.IllegalStateException: missing behavior definition for the preceding method call:
MusicPlayerDao.addSong(song)
Usage is: expect(a.foo()).andXXX()
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:42)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:94)
at org.easymock.internal.ClassProxyFactory$MockMethodInterceptor.intercept(ClassProxyFactory.java:97)
at service.MusicPlayerDao$$EnhancerByCGLIB$$45bc3ca1.addSong(<generated>)
at service.MusicPlayerServiceImpl.addSong(MusicPlayerServiceImpl.java:43)
at AddSongTest.addSongs(AddSongTest.java:90)
Here is my code:
private void addSongSetup() throws SQLException{
this.album = new Album();
album.setAlbumName("album");
this.genre = new Genre();
genre.setGenreName("genre");
this.song = new Song("song",this.album,3,"artist","composer",this.genre);
EasyMock.expect(this.dao.addSong(song)).andReturn(1).anyTimes();
EasyMock.expect(this.dao.addGenre(genre, 1)).andReturn(1).anyTimes();
EasyMock.expect(this.dao.addAlbum(album, 1)).andReturn(1).anyTimes();
EasyMock.expect(this.dao.userIdSongsMapping(1,1)).andReturn(1).anyTimes();
}
#Test
public void addSongs(){
this.album = new Album();
album.setAlbumName("album");
this.genre = new Genre();
genre.setGenreName("genre");
this.song = new Song("song",this.album,3,"artist","composer",this.genre);
try {
System.out.println(this.dao.addSong(song));
boolean status = this.service.addSong(song, 1);
assertEquals(true,status);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
My addSong method in service class:
public boolean addSong(Song song, int userId) throws Exception {
MusicPlayerDaoInterface musicPlayerDao = MusicPlayerDao.getInstance();
boolean status = false;
int songId = 0;
TransactionManager transactionManager = TransactionManagerImpl
.getInstance();
try {
if (song != null) {
if (song.getTitle() != null) {
transactionManager.begin();
songId = musicPlayerDao.addSong(song);
song.setSongId(songId);
if (song.getGenre() != null
&& song.getGenre().getGenreName() != null) {
musicPlayerDao.addGenre(song.getGenre(),
song.getSongId());
}
if (song.getAlbum() != null
&& song.getAlbum().getAlbumName() != null) {
musicPlayerDao.addAlbum(song.getAlbum(),
song.getSongId());
}
if (userId != 0 && songId != 0) {
musicPlayerDao.userIdSongsMapping(userId,
song.getSongId());
}
transactionManager.commit();
status = true;
}
}
} catch (SQLException | RollbackException | HeuristicMixedException
| HeuristicRollbackException e) {
transactionManager.rollback();
status = false;
throw e;
}
return status;
}
I don't know were I am going wrong. Please help.
I think you are missing a EasyMock.replay statement after you record the expected behaviour. Something like
EasyMock.replay(this.dao);
From the EasyMock guide:
To get a Mock Object, we need to
create a Mock Object for the interface we would like to simulate
record the expected behavior
switch the Mock Object to replay state
try removing the following lines from the addSongs test case:
this.album = new Album();
album.setAlbumName("album");
this.genre = new Genre();
genre.setGenreName("genre");
this.song = new Song("song",this.album,3,"artist","composer",this.genre);
I assume that addSongSetup is invoked before addSongs (e.g.; #Before). You are reassigning values to your variables album, genre and song in addSong, which, I suppose, EasyMock cannot match to your mock setup in addSongSetup as (depending on how EasyMock implemented this)
you forgot to implement hashcode or equals in Song, Album, Genre or,
EasyMock uses Object identity (i.e., reference comparison)
I guess it's 1.
I've got a custom exception called "LoginException". It might be thrown from any class. So I want to make an advice to do something(for example, print "Ooops") after throwing. So I decided to use AOP. Something like this:
#Aspect
public class LogoutAdvice {
#AfterThrowing(throwing = "e")
public void myAfterThrowing(JoinPoint joinPoint, LoginException e) {
System.out.println("IDS HABBENING");
}
}
Code:
#Transactional
public DynamicTable getTable(int status_id, HttpServletRequest request)
throws HibernateException, LoginException, SQLException {
try {
ResultSet rs = requestDAO.getRequestResultSet(
cookieDAO.get(SESS_ATTR, request), status_id);
DynamicTable dt = new DynamicTable();
String[] columnArray;
LinkedList<String[]> dataList = new LinkedList<String[]>();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
columnArray = new String[columnCount - META_COLUMNS_COUNT];
for (int i = 0; i < columnArray.length; i++) {
columnArray[i] = rsmd.getColumnName(META_COLUMNS_COUNT + i + 1);
}
dt.setTitleArray(columnArray);
while (rs.next()) {
String[] dataArray = new String[columnArray.length];
for (int i = 0; i < columnArray.length; i++) {
dataArray[i] = ParamUtil.toString(rs
.getObject(META_COLUMNS_COUNT + i + 1));
}
dataList.add(dataArray);
}
dt.setDataList(dataList);
return dt;
} catch (SQLException e) {
String message = e.getMessage();
String[] errorsArray = AuthErrorsConst.ERROR;
for (int i = 0; i < errorsArray.length; i++) {
if (message.contains(errorsArray[i])) {
throw new LoginException(); // LOOK AT THIS
}
}
throw e;
}
}
How can I do that?
Be sure the exception is being thrown
catch (SQLException e) {
String message = e.getMessage();
String[] errorsArray = AuthErrorsConst.ERROR;
for (int i = 0; i < errorsArray.length; i++) {
if (message.contains(errorsArray[i])) {
System.out.println("throwing LoginException")// NEW
throw new LoginException(); // LOOK AT THIS
}
}
throw e;
}
About
#Aspect
public class LogoutAdvice {
#AfterThrowing(throwing = "e")
public void myAfterThrowing(JoinPoint joinPoint, LoginException e) {
System.out.println("IDS HABBENING");
}
}
Be sure Spring has enable to work with #Aspect and furthermore it be able to scan your LogoutAdvice aspect, normally I declare them how
#Aspect
#Component// to be scanned by Spring
public class LogoutAdvice {
Change your #AfterThrowing to
#AfterThrowing(pointcut = "execution(* *.*(..))",throwing = "e")
Use a point cut in your #AfterThrowing annotation
Therefore your annotation will need to look something like below
#AfterThrowing(pointcut = "execution(public * *(..))",throwing = "e")
Please refer to below link for elaborate explanation:
http://www.compiletimeerror.com/2013/05/spring-aop-after-throwing-advice.html#.VCAnsvmSw2c
1) Check you LoginException class as it should be a proper exception class.
2) throw the exception object "e" in catch block
3)
#Aspect
#Component
public class LogoutAdvice {
#AfterThrowing(pointcut = "execution (* * com..*(..)", throwing = "e")
public void myAfterThrowing(JoinPoint joinPoint, LoginException e) {
System.out.println("IDS HABBENING");
}
}
4) in spring configuration file
<aop:aspectj-autoproxy/>
thats enough.
My code throwing java.lang.ClassCastException exception error, Why this error will get?. I am using com.android.internal.telephony API's. i.e You can find classes I am using here Call.java<http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/1.5_r4/com/android/internal/telephony/Call.java>, CallManger.java <http://hi-android.info/src/com/android/internal/telephony/CallManager.java.html> I have created a Subclaas of Call.java like this:
public class MyCall extends Call{
CallManager cm = CallManager.getInstance();
Phone.State state;
Connection c;
Phone mDefaultPhone;
private final ArrayList<Connection> emptyConnections = new ArrayList<Connection>();
MyCall ringingCall;
#Override
public List<Connection> getConnections() {
state = cm.getState();
ringingCall = (MyCall) cm.getRingingCalls();
System.out.println("**inside getConnections="+ringingCall);
if ( ringingCall != null && !ringingCall.isIdle()) {
System.out.println("**call is not null***");
return ((MyCall) ringingCall).getConnections();
}
else
{
System.out.println("**list is null***");
return emptyConnections;
}
}
#Override
public Phone getPhone() {
// TODO Auto-generated method stub
return null;
}
#Override
public void hangup() throws CallStateException {
// TODO Auto-generated method stub
}
#Override
public boolean isMultiparty() {
// TODO Auto-generated method stub
return false;
}
public Connection
getEarliestConnection() {
System.out.println("inside EarliestConnection");
List l;
long time = Long.MAX_VALUE;
Connection c;
Connection earliest = null;
l = getConnections();
if (l == null) {
return null;
}else if ( l.size() == 0)
{
return null;
}
System.out.println("value of connection is=="+l);
for (int i = 0, s = l.size() ; i < s ; i++) {
c = (Connection) l.get(i);
long t;
t = c.getCreateTime();
if (t < time) {
earliest = c;
time = t;
}
}
return earliest;
}
}
I called CallManger.java like this in my own class
CallManager cm = CallManager.getInstance();
My another class is CallUpdate, it should give me a OutgoingCall states (i.e other side phone is Busy, Power-off, not-reachable etc.) The code is like this:
public class CallUpdate {
Call myCall = new MyCall();
Connection myConn = new MyConnection();
CallManager cm = CallManager.getInstance();
public Object getCallFailedString(){
myConn = myCall.getEarliestConnection();
System.out.println("myConn is ******"+myConn);
System.out.println("myCall is ******"+myCall);
if(myConn == null){
System.out.println("myConn is null ******");
return null;
}
else
{
Connection.DisconnectCause cause = myConn.getDisconnectCause();
System.out.println("myconn is not null ******"+cause);
switch(cause){
case BUSY :
System.out.println("inside busy");
break;
case NUMBER_UNREACHABLE :
System.out.println("inside un-reachable");
break;
case POWER_OFF :
System.out.println("inside power off");
break;
}
}
return myConn;
}
I called this class in BroadCastReceiver(). But i am getting connection is null. My code is not getting inside else part. So that I added some code in getConnection method of MyCall class like this:
public List<Connection> getConnections() {
state = cm.getState();
ringingCall = (MyCall) cm.getRingingCalls();
System.out.println("**inside getConnections="+ringingCall);
if ( ringingCall != null && !ringingCall.isIdle()) {
System.out.println("**call is not null***");
return ((MyCall) ringingCall).getConnections();
}
else
{
System.out.println("**list is null***");
return emptyConnections;
}
}
But I am getting java.lang.ClassCastException: on Line:
ringingCall = (MyCall) cm.getRingingCalls();
And also on l = getConnection();
How to solve this ??
Thx in advance.
Change your code as below
List<MyCall> ringingCall = cm.getRingingCalls();
I believe your cm.getRingingCalls(); returning ArrayList of Call / MyCall
getRingingCalls returns a List<Call> i.e. a list of Call objects. You're trying to cast it to a single MyCall, instead of a List, so you get a ClassCastException.
You need to correct your type to a List:
List<MyCall> ringingCall;
ringingCall = cm.getRingingCalls();
or, use the first element in the list:
MyCall ringingCall;
if(!cm.getRingingCalls().isEmpty()){
ringingCall = cm.getRingingCalls().get(0);
}