I'm using EJB3.1 in my application which is running on JBoss AS 6. I'm working as integration developer and I have use case where as part of my transaction there are multiple calls to various external systems via REST, SOAP etc. If any of these calls throw exception I have to rollback changes to previously called systems.
Currently I'm having situation:
public class SystemAException extends RuntimeException {...}
public class SystemBException extends RuntimeException {...}
public class SystemCException extends RuntimeException {...}
System classes
public class SystemA{
public static makeChanges() throws SystemAException{...}
public static cancelChanges() {...}
}
public class SystemB{
public static makeChanges() throws SystemBException{...}
public static cancelChanges() {...}
}
public class SystemC{
public static makeChanges() throws SystemCException{...}
public static cancelChanges() {...}
}
Call
static makeChanges(Object o){
persist(o); //DB work
try {
SystemA.makeChange();
SystemB.makeChange();
SystemC.makeChange();
} catch(SystemBException eb){
SystemA.cancelChanges();
throw eb;
} catch(SystemCException ec){
SystemA.cancelChanges();
SystemB.cancelChanges();
throw ec;
}
update(o); //more DB work
}
I would like to get rid off try-catch and to instruct JBoss to call method cancelChanges() whenever RuntimeException occurs like it does when it rollback changes made to DB.
I'm aware that I could use Commander pattern to undo previously made changes, but I would like to know if container can do that for me.
If it is possible, I would like to accomplish following thing
static makeChanges(Object o){
persist(o); //DB work
SystemA.makeChange();
SystemB.makeChange();
SystemC.makeChange();
update(o); //more DB work
}
If you're calling non-XA external systems via REST/SOAP, what happens if your JVM/network crashes before you can undo the changes? That sounds like a fragile architecture.
Regardless, ther is no way to get the EJB container to do this for you automatically. The best idea I have is to have SystemA/SystemB/SystemC call TransactionSynchronizationRegistry.registerInterposedSynchronization, and then you can be notified when the transaction is rolling back (since the EJB container will roll back transactions automatically if a system exception or application with rollback=true is thrown), and then you can try to undo whatever. Of course, if the JVM crashes then your interposed synchronization listeners will be lost and you can't undo, so it still doesn't solve that problem.
Related
First of All I have to apologize for the semi-psuedo code as the classes I am going to reference are all too big and are pointless except for a few lines of each class to ask my question.
To Start off I am using
Jboss 6.3.2 EAP
Hibernate
EJB 3.0
I have two different EJB Classes
They are
Service Layer
#Stateless
#TransactionManagement
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class ServiceClass implements ILocalService
{
#EJB
ILocalDao localDao;
#Override
public myObject find(String id)
{
localDao.findByPK(id);
}
#TransactionalAttribute(TransactionAttributeType.REQUIRED)
#Override
public void create(myObject obj)
{
localDao.create(obj);
}
#TransactionalAttribute(TransactionAttributeType.REQUIRED)
#Override
public void update(myObject obj)
{
localDao.findByPK(obj.getId());
localDao.update(obj);
}
}
DAO Layer
#Stateless
#TransactionalAttribute(TransactionAttributeType.MANDATORY)
public class DaoClass extends AbstractDaoClass<myObject> implements ILocalDao
{
#Override
public myObject findByPK(String id)
{
super.find(id);
}
}
Okay with those two classes laid out. Trust me that everything else is correctly configured interface Classes, Abstract Class, persistence.xml, etc.
The question is How does the find method in the ServiceClass work? With the NOT_SUPPORTED being assigned to this method I would think that the DaoClass call would throw a Exception because no Transaction has been started yet and I am making the entire class MANDATORY. But my running app says otherwise.
To verify that no transaction is being created on the DaoClass.find method. I put in the #TransactionalAttribute(TransactionAttributeType.NEVER). And re-ran the application. Still works.
To verify that the NEVER works I call the ServiceClass's update method. Throws an exception as expected.
To round this all out I have looked at many online resources(http://docs.oracle.com/javaee/6/tutorial/doc/bncij.html, etc) I have looked into the source files for the EJB 3.0 and Jboss...I am not seeing anything.
So questions I have pondered
Is the TransctionAttributeType.MANDATORY on the class level not
working as I expect it to in the DaoClass?
TransactionManagement on the ServiceClass creating a Transaction on init of the ServiceClass and then the NOT_SUPPORTED suspending this transaction?
I am in the process of writing up some tests to hopefully log the transaction's behavior and see what is going on. But hopefully someone here can shed some light sooner and relieve this huge question mark I have.
Thanks in advance.
First, #TransactionManagement without parameters is useless, since default value is TransactionManagementType.CONTAINER and EJB uses TransactionManagementType.CONTAINER implicitly.
I have some code which (in production):
In one thread, primes a cache with data from the db
In another thread, grabs the data from the cache, and starts iterating it's properties.
This threw a LazyInitializationException.
While I know how to fix the problem, I want to get a test around this. However I can't figure out how to recreate the exception in the correct part of the test.
I have to prime the DB with some test data, therefore my test is annotated with #Transactional. Failing to do so causes the set-up to fail with... you guessed it... LazyInitializationException.
Here's my current test:
#Transactional
public class UpdateCachedMarketPricingActionTest extends AbstractIntegrationTest {
#Autowired
private UpdateCachedMarketPricingAction action;
#Autowired
private PopulateMarketCachesTask populateMarketCachesTask;
#Test #SneakyThrows
public void updatesCachedValues()
{
// Populate the cache from a different thread, as this is how it happens in real life
Thread updater = new Thread(new Runnable() {
#Override
public void run() {
populateMarketCachesTask.populateCaches();
}
});
updater.start();
updater.join();
updateMessage = {...} //ommitted
action.processInstrumentUpdate(updateMessage);
}
So, I'm priming my cache in a separate thread, to try to get it outside of the current #Transaction scope. Additionally, I'm also calling entityManager.detatch(entity) inside the cache primer, to try to ensure that the entities that exist within the cache can't lazy-load their collections.
However, the test passes... no exception is thrown.
How can I forcibly get an entity to a state that when I next try to iterate it's collections, it will throw the LazyInitializationException?
You need to ensure that the transactions for each operation are committed, independent of each other. Annotating your test method or test class with #Tranactional leaves the current test transaction open and then rolls it back after execution of the entire test.
So one option is to do something like the following:
#Autowired
private PlatformTransactionManager transactionManager;
#Test
public void example() {
new TransactionTemplate(transactionManager).execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
// add your code here...
}
});
}
You could invoke your first operation in its own callback, and then invoke the second operation in a different callback. Then, when you access Hibernate or JPA entities after the callbacks, the entities will no longer be attached to the current unit of work (e.g., Hibernate Session). Consequently, accessing a lazy collection or field at that point would result in a LazyInitializationException.
Regards,
Sam
p.s. please note that this technique will naturally leave changes committed to your database. So if you need to clean up that modified state, consider doing so manually in an #AfterTransaction method.
Sorry I am new to Spring and Java and this may be covered lots of times but I wanted to get some advice.
I'm creating a Spring web application which needs to retrieve user data from an existing REST based XML web service. I am going to create a domain object, service and DAO which uses the Spring REST template to invoke the web service.
In the DAO I was going to create a method like this:
public User getUser(String userId)
If there is a problem (for example if the user account is locked or been deleted), the web service returns a 200 response and puts an error code in the XML response. These errors should be displayed in the application and I will need to be able to identify the error so I can show custom error message to the user. What is the recommended way to handle these error, should I:
Define different exceptions (runtime) for each of the error response codes and add these to the method signature
Use a single exception (e.g. UserException) and use different messages.
Do something else
Any help would be highly appreciated.
You want to use different exception for each error type by extending Extension. if you have many different ones, try to group them using class inheritance. An example would make it simpler. Suppose you have these 2 kinds of errors, account deleted and account locked, you would do :
class AccountException
extends Exception {
}
then you extend Account extension for all the errors involving account problems, eg:
class AccountLockedException
extends AccountException {
}
and
class AccountDeletedException
extends AccountException {
}
etc... This way you make it crystal clear and don't have to look through all your exceptions. Not sure I'm clear enough, It's my first answer here. GL!
I would create a single Exception class for a category. For instance, for all user related exceptions, you can create something like below:
This way, it will be clean to catch one exception and verify the error code to find what caused the exception.
public class MyException extends Exception{
public static final int ERR_USER_NOT_FOUND = 101;
public static final int ERR_DB_ACCESS_ERR = 500;
private int errorCode;
public MyException(int errCode){
this.errorCode = errCode;
}
public int getErrorCode() {
return errorCode;
}
}
How can I detect when an Exception has been thrown anywhere in my application?
I'm try to auto-magically send myself an email whenever an exception is thrown anywhere in my Java Desktop Application. I figure this way I can be more proactive.
I know I could just explicitly log and notify myself whenever an exception occurs, but I'd have to do it everywhere and I might(more likely will) miss a couple.
Any suggestions?
You probobly don't want to mail on any exception. There are lots of code in the JDK that actaully depend on exceptions to work normally. What I presume you are more inerested in are uncaught exceptions. If you are catching the exceptions you should handle notifications there.
In a desktop app there are two places to worry about this, in the event-dispatch-thread (EDT) and outside of the EDT. Globaly you can register a class implementing java.util.Thread.UncaughtExceptionHandler and register it via java.util.Thread.setDefaultUncaughtExceptionHandler. This will get called if an exception winds down to the bottom of the stack and the thread hasn't had a handler set on the current thread instance on the thread or the ThreadGroup.
The EDT has a different hook for handling exceptions. A system property 'sun.awt.exception.handler' needs to be registerd with the Fully Qualified Class Name of a class with a zero argument constructor. This class needs an instance method handle(Throwable) that does your work. The return type doesn't matter, and since a new instance is created every time, don't count on keeping state.
So if you don't care what thread the exception occurred in a sample may look like this:
class ExceptionHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
handle(e);
}
public void handle(Throwable throwable) {
try {
// insert your e-mail code here
} catch (Throwable t) {
// don't let the exception get thrown out, will cause infinite looping!
}
}
public static void registerExceptionHandler() {
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler());
System.setProperty("sun.awt.exception.handler", ExceptionHandler.class.getName());
}
}
Add this class into some random package, and then call the registerExceptionHandler method and you should be ready to go.
The new debugging hooks in Java 1.5 let you do this. It enables e.g. "break on any exception" in debuggers.
Here's the specific Javadoc you need.
Check out Thread.UncaughtExceptionHandler. You can set it per thread or a default one for the entire VM.
This would at least help you catch the ones you miss.
If you're using a web framework such as Spring then you can delegate in your web.xml to a page and then use the controller to send the email. For example:
In web.xml:
<error-page>
<error-code>500</error-code>
<location>/error/500.htm</location>
</error-page>
Then define /error/500.htm as a controller. You can access the exception from the parameter javax.servlet.error.exception:
Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception");
If you're just running a regular Java program, then I would imagine you're stuck with public static void main(String[] args) { try { ... } catch (Exception e) {} }
If you are using java 1.3/1.4, Thread.UncaughtExceptionHandler is not available.
In this case you can use a solution based on AOP to trigger some code when an exception is thrown. Spring and/or aspectJ might be helpful.
In my current project I faced the similar requirement regarding the errors detection. For this purpose I have applied the following approach: I use log4j for logging across my app, and everywhere, where the exception is caught I do the standard thing: log.error("Error's description goes here", e);, where e is the Exception being thrown (see log4j documentation for details regarding the initialization of the "log").
In order to detect the error, I use my own Appender, which extends the log4j AppenderSkeleton class:
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
public class ErrorsDetectingAppender extends AppenderSkeleton {
private static boolean errorsOccured = false;
public static boolean errorsOccured() {
return errorsOccured;
}
public ErrorsDetectingAppender() {
super();
}
#Override
public void close() {
// TODO Auto-generated method stub
}
#Override
public boolean requiresLayout() {
return false;
}
#Override
protected void append(LoggingEvent event) {
if (event.getLevel().toString().toLowerCase().equals("error")) {
System.out.println("-----------------Errors detected");
this.errorsOccured = true;
}
}
}
The log4j configuration file has to just contain a definition of the new appender and its attachement to the selected logger (root in my case):
log4j.rootLogger = OTHER_APPENDERS, ED
log4j.appender.ED=com.your.package.ErrorsDetectingAppender
You can either call the errorsOccured() method of the ErrorsDetectingAppender at some significant point in your programs's execution flow or react immidiately by adding functionality to the if block in the append() method. This approach is consistent with the semantics: things that you consider errors and log them as such, are detected. If you will later consider selected errors not so important, you just change the logging level to log.warn() and report will not be sent.
In this case I think your best bet might be to write a custom classloader to handle all classloading in your application, and whenever an exception class is requested you return a class that wraps the requested exception class. This wrapper calls through to the wrapped exception but also logs the exception event.
I assume you don't mean any Exception but rather any uncaught Exception.
If this is the case this article on the Sun Website has some ideas. You need to wrap your top level method in a try-catch block and also do some extra work to handle other Threads.
Sending an email may not be possible if you are getting a runtime exception like OutOfMemoryError or StackOverflow. Most likely you will have to spawn another process and catch any exceptions thrown by it (with the various techniques mentioned above).
There is simply no good reason to be informed of every thrown exception. I guess you are assuming that a thrown exception indicates a "problem" that your "need" to know about. But this is wrong. If an exception is thrown, caught and handled, all is well. The only thing you need to be worried about is an exception that is thrown but not handled (not caught). But you can do that in a try...catch clause yourself.
I have a test class that extends AbstractTransactionalDataSourceSpringContextTests.
I did not write this class, and need to make a small change. I'd like to see what would happen if i prevented the recreation of the test database (using DbUnit) after each test.
I have tried playing with the following lines:
#Override
protected void onSetUpBeforeTransaction() throws Exception {
initialisingTables.create("Init");
}
#Override
protected void onTearDownAfterTransaction() throws Exception {
deleteTables(true);
deleteTables(false);
}
But nothing seems to help.
I guess you just have to annotate your test methods with
#Rollback(false)
or the test class with sometjing like this:
#TransactionConfiguration(transactionManager="txMgr", defaultRollback=false)
See: 10.3.3. JDBC Testing Support