Announcement Announcement Module
Collapse
No announcement yet.
Conceptual: context information Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • #16
    so your proposal would be to add contexual information to the exception but not resolve those errors e.g in the DAO layer with some errors texts from the DB, as those messages are ment for the Developer and not the users outside.

    A better approach would catch/throw your exceptions and add your message and context information into it and throw again, so no information from the error stack gets lost...correct me if im wrong ;-)

    Comment


    • #17
      Originally posted by uenluena View Post
      so your proposal would be to add contexual information to the exception but not resolve those errors e.g in the DAO layer with some errors texts from the DB, as those messages are ment for the Developer and not the users outside.

      A better approach would catch/throw your exceptions and add your message and context information into it and throw again, so no information from the error stack gets lost...correct me if im wrong ;-)
      Always keep in mind that an exception is meant to be a vehicle that efficiently transports the error information (as full as possible, for debugging and diagnostics purposes, not for user consumption) from the origin of the error to the designated handler - without imposing the error handling burden on any modules in between where it is not relevant. (Hence, checked exceptions are a nuisance.) It is not the job of the exception to carry any application-specific task (such as offering a presentation tier message that the app should display to the user.) It is up to the application itself to interpret the error type and map it to any appropriate application-specific action. A clean design must separate these two concepts.

      Add your technical/debug message + context explicitly in the code that throws the exception. Don't modify that exception any more - unless you can add even more useful debugging info to it between the originating code and the designated handler. In most cases, the latter is not necessary. However, in the case of your specific requirements, it is what you will do with your service-tier exceptions: you will intercept all Throwables that originated underneath the service at the service boundary (public method) with your aspect, add the service-specific context, and re-throw. Let it fly to the designated handler that will log it and transform it into the appropriate application action. If you need to map that exception to a specific presentation-tier message shown to the user, have the handler invoke the special resolver in the presentation tier that will do that. You will have to implement that resolver/mapper as a separate independent module injectable into your controllers. That resolver could be configured (through Spring) to map certain exception types to particular message keys. In other words, the resolver would store a map of "exception-class->msg-key" entries. You will be able to look up the key and drop it into the request object. if your resolver is aware of your request context, it may do it for you. The JSP would use the key to display the appropriate message from the message resource - as I showed you in an earlier post. Note that here I am talking about your specific case when you need to direct all your system exceptions to the same view but with distinct end-user messages. In a more generic solution, you will be mapping different exception classes to different views as well. However, in most real-world applications, you should have very few of such distinct conditions, while most your system exceptions would still need to result in the same generic error page.

      The bottom line: maintain/resolve your presentation tier messages in the front-end only. If you do store your user-friendly messages (that the app displays to the end user in its pages) in the database, then have a mechanism that loads and resolves them in the front end. I prefer to maintain such messages in the message resources rather than the database. But if you have to store them in the DB, you may, for example, cache them all at once in the PT when the application starts; or do a separate data-tier trip each such message. I would certainly try to avoid the latter.
      Last edited by constv; Nov 26th, 2008, 09:28 AM.

      Comment


      • #18
        Im going through the different use cases at the moment to cover all of them in the exception handling concept.

        When i look at the exceptions that can occur in my application layers i have the following cases:

        DAO Layer
        Im using the support classes of Spring, so my DAO's are all throwing unchecked exceptions.

        There's nothing to do here. Those runtime exceptions shuld be catched late

        Service Layer
        As my DAO's are throwing unchecked exceptions, there's nothing i need to catch from my DAO's. There might be cases, where a DAO exception should be transformed to a checked exception but this is done in the try/catch where i will catch a runtime exception and throw a ServiceException.

        The specific exception which is thrown here is ServiceException. The service exception has an additional methode addContextualInformation(Object o) to add more context information to the service exception.

        Does it make sense to declare a throws ServiceException for each Service Method?

        Presentation Layer
        We're using JSF as the presentation technology. Managed/Backed beans that are doing calls to the Service methods can catch ServiceExceptions.


        Now with AOP i could catch RuntimeExceptions with a interceptor. My problem is that on JSF level there's also the possibility of raised RuntimeExceptions...so i need to catch those errors even higher....Any recommendations?

        Comment


        • #19
          DAO Layer
          Im using the support classes of Spring, so my DAO's are all throwing unchecked exceptions.

          There's nothing to do here. Those runtime exceptions shuld be catched late
          That's correct. Just focus on your DA logic and let any errors bubble up to be caught later where the application knows what to do with them.

          Service Layer
          As my DAO's are throwing unchecked exceptions, there's nothing i need to catch from my DAO's. There might be cases, where a DAO exception should be transformed to a checked exception but this is done in the try/catch where i will catch a runtime exception and throw a ServiceException.

          The specific exception which is thrown here is ServiceException. The service exception has an additional methode addContextualInformation(Object o) to add more context information to the service exception.

          Does it make sense to declare a throws ServiceException for each Service Method?
          Why do you need to convert anything into a checked exception in the service tier? Only catch those types of exceptions in the service tier that you feel you need to update with useful information. For such exceptions, catch them (perhaps using an aspect, as we have discussed), add a clarifying message and context parameters, wrap it into a service-tier Runtime exception and re-throw. Do not force the immediate caller of the service method to implement a try-catch. If your client code is written properly, a public method on your action/controller/managed bean/whatever class probably calls one or more private methods one of which eventually makes the service call. Do yo want to unnecessarily force that poor private method to mess with your service exception? Of course not. Let it propagate to the single handler that handles service exceptions - - for all your controllers/backed beans. Read below...

          Presentation Layer
          We're using JSF as the presentation technology. Managed/Backed beans that are doing calls to the Service methods can catch ServiceExceptions.
          I am not an expert on JSF at all, I haven't touched it in years, and I have never used it seriously. So I can't tell you how to do it specifically in JSF. But here's the generic approach that you can use with any presentation tier framework, such as Struts, Spring MVC, or, I'm sure, JSF. You can write an abstract front-end action class (call it controller, managed bean, whatever) that would implement the actual service execution method in the following way:

          Code:
          // your abstract action pseudo-code to invoke the view-specific service call...
          
          executeServiceMethod:
          {   
            try {
                 doExecute(...); // call the abstract execute method that each specific action will implement to call the action specific business service API
            } catch (Throwable t) {
                 // do your generic handling of any system errors that ocurred in servic tier
                logger.error(t);
                if (t instance of ContextAwareException) {
                     logger.error(t.getContextinfo()); 
                }
                String msgKey = msgResolver.resolve(t); // call your PT resolver that maps exceptions to specific PT messages, if some exceptions require a specific message
                 
                 - place messageKey into request
                 - return generic error view (that will display a msg using msgKey, or default message)
           }
          Make all your actions implement that abstract class and provide their versions of the "doExecute" method, or whatever you call it. In most cases, you should not implement any try/catch's in the action-specific "doExecute"s, However, for those use cases/actions that require you to do something different from displaying the error page - and only for those cases! - implement separate try/catch blocks in the related action implementations. If those cases are not based on the actions but on the types of the thrown exceptions, then simply insert the catches for those specific exceptions before the "catch Throwable" in your abstract action's code above. You should be all set in the front-end on the server side. Now, exceptions may still be thrown in your JSPs, in tags. To take care of those, put this filter into your web.xml:

          Code:
              <error-page>
                  <exception-type>java.lang.Throwable</exception-type>
                  <location>/WEB-INF/jsp/error.jsp</location>
              </error-page>
          Obviously, replace "/jsp/error.jsp" with your actual error page name and location. You are all set!

          And don't catch exceptions anywhere else. Your code will be completely error-proof and junk-free! (I mean error-handling junk; I can't speak for any other junk you might put in there. Try not to. ) And you won't lose any valuable error information whenever an exception is thrown. Isn't it beautiful? Compare this to the thousands of meaningless try/catchs and throws your project probably has now... Brrrr!

          HTH.
          Good luck!

          Comment


          • #20
            The problem is that JSF is a component based technology...so each button click can have a code piece behind that button which would be doButtonClick() which calls the service method. There's no generic request/response behavour but much more component based action/response behavour.

            So having one doExecute() method wouldnt really help here as different services might be called and not all in the doExecute method. But im not sure if i understood you correctly.

            Your idea would be to a have a CommonAbstractManagedBean that would have an abstract method doExecute(). My Concrete SearchManagedBean would then implement doExecute() and in different places in the managed bean, like in the doSearchButton() method i would call the doExecute() method. Was that correct?

            Comment


            • #21
              Originally posted by uenluena View Post
              Your idea would be to a have a CommonAbstractManagedBean that would have an abstract method doExecute(). My Concrete SearchManagedBean would then implement doExecute() and in different places in the managed bean, like in the doSearchButton() method i would call the doExecute() method. Was that correct?
              Something like that, yes. Unfortunately, I am not qualified to advise on JSF-specific solutions. But the idea is to find a single place where you can implement a global catch for every single uncaught exception originated anywhere within the code that is invoked by the UI component submission - to handle the error and redirect the application to the standard error view. In Struts (at least the old one, I haven't used it since then), the best place to do that would be a base abstract action class - exactly how I described it. In Spring MVC, it is much easier: you only need to implement and register an exception resolver that will be invoked by Spring if any RT exception bubbles up from the controllers or below. So, Spring listens for the exceptions for you. I showed you how to implement and register such handler in one of my earlier posts in this thread. Check if JFS has some generic exception-listening mechanism. If it doesn't, there you have another reason not to use JSF...
              Last edited by constv; Dec 1st, 2008, 01:53 PM.

              Comment


              • #22
                Sooo, constv....i really enjoyed exchanging ideas with you and i had after some time of tests, implementations...conceptual work my first discussion with my (IT) manager, that came with additional requirements because of the scope of our project that has been widened...

                I think we both share the same idea about exceptions that are catched at DAO level, namely SQLExceptions...Until today all of those exceptions were wrapped to Unchecked exceptions and went up the ladder...

                Today i got introduced to some legacy systems, where 99.9999~ of the whole business logic is in the DB and they have this special java-like-stacktrace concept that they build into PL/SQL.

                This stack trace actually more a "message"-stack-trace as it has a structure like that:

                Error-Code1 - Context information
                Error-Code2 - Context information

                e.g
                3234 - Couldn't search for the contract
                3466 - The end date is before start date


                You can clearly see that NONE of this so called "exceptions" are really exceptions but much more validations. Whatever, i tried to justfy my point for over 3hours but it's hard to explain them my point when they are actually a part of the problem and mainly those who build up such a structure...

                So the idea would be that i would have a strategy before wrapping those runtime exceptions, where i have to decide because of the error code if it's an DB-Technical exception or a Business Exception coming from the DB.

                My idea would be to throw Runtime Exceptions anyway and do check for the type only for throwing two different Runtime Exceptions. One would be a DBException, which is a technical rte and a DBBusinessException rte for business specific DB exceptions.

                With the those two rte's, the technical exceptions would go up the ladder and at controller level i would catch them and act properly and the business exceptions would be catched at service layer.

                The reason why we need to catch them at service level is because my manager put another constraint in place, as he saw use cases where a service could call different PL/SQL procedures, through different DAO methods and act according the so called "business exceptions". So for him the existance of the service layer was vital (which was the case for me from the beginning).

                So i have my multi tier application having business logic in a seperate Service layer + business logic in the PL/SQL world. We agreed on a solution where all commonly used functionalities should be encapsulated in Web Services and provided through contract to the consumers...

                What do you think about that? I mean..i really came out of the room with lots of headache as he was not able to understand and every sentence ended with "....yeaaaah you java developers just dont see the real business", which made me really raging and most of the concepts i defended are commonly accepted practices put in place in different companies and are widely known as correct (btw. i bought and read your recommended book Clean Code and enjoyed every single page of it ;-) - i was just not able to force him to look at it ;-D)

                Comment


                • #23
                  any input to my last post?

                  Comment


                  • #24
                    Hi uenluena,
                    sorry for the delay, and sorry to hear about your situation. I know how frustrating it may feel when you are working with people like that. Since there is not much you can do to change that, you have to find the most elegant solution to deal with that while abstracting your application from the stupid things that other people have done. It sounds you are on the right track. I agree, you need to catch those crazy DB-originated checked exceptions, distinguish the two types (system/programming error or validation cases) and re-throw them as two distinct RTEs to ensure that they don't stink up any of your application code - until the point they reach your handler on the front end. I am not sure why you are suggesting catching the data field validation cases like your "end date before start date" - in the service. Why? What can your service do about that? It seems to me that this information should freely propagate to the front end where a message would be resolved (or extracted, if it is already in the exception created by the DB developer - which is bad, as I had explained!) and presented to the user. As I have said before, an exception instance must never carry any messages intended for the end user. If your co-workers are doing that they are incompetent, or, at least, seriously misinformed on exceptions. Exception-stored (hard-wired) info is for diagnostics only. Exceptions must be mapped to application-specific user-friendly messages separately!

                    That said, I would put the catching and re-throwing of your exceptions into an aspect, which would consolidate that logic and make your DAOs "unaware" of the ugliness. Also, introduce an aspect on the front-end that would catch and handle them - without exposing them to the controllers.

                    HTH. Good luck,
                    Constantine

                    Comment


                    • #25
                      Im back!


                      After several weeks of holidays and some military (yeah...in switzerland we're still forced to do military each year ;-D) i found again some time to work on the problem.

                      We have some progress...

                      At first the leader of another development group introduced a Java Exception Stack-like concept to the DB which most of the DB-developers use now...

                      So, when i work with some Business Logic inside the DB, the exception from the PL/SQL procedure call stack comes through JDBC as a SQLException.

                      Im using the SQLErrorCodeTranslator in Spring to get our Business Specific Oracle Error Code (must be between 20000-29999) and wrap them to a DatabaseBusinessException...

                      What i get from the DB is actually XML holding exception entries in it, with error codes and context parameters. I parse them one by one and transform them to DatabaseBusinessException (rte) which are resulting in a Java Exception Stack and not the original " Error at line 5 of the blah package" message.

                      Every other exception coming from the DB is rethrown as a DataAccessException (rte)

                      My first idea was to stick to the idea that the DatabaseBusinessException is not catched as you proposed in the Service Layer...i face the problem that i can try to explain in an example:

                      my service method does insert a user which results in several PL/SQL procedure calls. Now, the 6. of this calls raises an exception and each of the caller are adding or propagating to this exception in the DB.

                      So, when the exception comes up to my exception "barrier" in my web level, i have 6-7 exception stack elements and as i have business logic in the PL/SQL procedures i cant do a generic try/catch as i do with normal rte's.

                      I would have to give the user a quiet specific error message like "sorry, but your username already exists".

                      Maybe the first or the last stack element has this information in the stack, so i would have to get this first/last message and translate it to the user...

                      Do you see any possibilities to solve such a problem?

                      Comment


                      • #26
                        Hi, uenluena,

                        my service method does insert a user which results in several PL/SQL procedure calls. Now, the 6. of this calls raises an exception and each of the caller are adding or propagating to this exception in the DB.
                        I am not sure I clearly understand what you are describing. Are you saying that those several SP calls are executed in a sequence - regardless of whether any of them fails and throws an exception? So, depending on the combination of the results of those calls, your UI must produce the appropriate error message to the user? Did I understand you correctly?

                        Assuming that's exactly what your situation is (and setting aside any questions about the validity of the original design that is out of your control), here's a thought... At the point where you are translating the SQL exceptions and parsing the whatever stuff is inside them - since you are doing that anyway - you might want to construct a "business condition code" out of all the codes of the underlying exceptions you have extracted. These exceptions, as you have stated, represent real business conditions, like "username already exists." So, if someone had come up with such a crazy deign that a legitimate business condition is represented by a certain combination of SQLExceptions (again, if I understood you correctly, and if so, your system was designed by maniacs!!!) - then, it seems, the best thing you can do is consolidate that bizarre bunch of error codes into a single code and map it to a UI message on the front-end. You could:

                        1) Create some com.yourcompany.commons.BusinessException (RTE) - whose constructor takes the message, and cause, and the business use case regex. (The only reason for that is because your organization uses DB-born exceptions to signal business conditions. Otherwise, you know I don't like the idea of passing any kind of codes in exceptions, or using exceptions for legitimate business use cases all together.)

                        2) Extract all individual error codes (at the very first line of defense, where you do the SQL exceptions translation) and construct, say, a regular expression out of them that would uniquely identify each use case;

                        2) Wrap the original SQLException (with all the stacked crap that is in it - so you don't lose any valuable info for logging) into your new custom service-specific business RTE that extends your com.yourcompany.commons.BusinessException.

                        3) On the application level, provide a configuration file and a mapper class that would map those regex's to user-friendly UI messages.

                        4) Let the business exception freely propagate to your handler at the very top, in the front-end. That handler, before catching Throwable, would catch any instances of your BusinessException, extract that stupid use case code, run it through the code resolver and retrieve the appropriate message that would be passed to the view.

                        I wouldn't put any notion of a legitimate business use case into a DataAccessException. A DataAccessException should only mean one thing: something is really not working with your data access, not that the user name already exists, etc. You get my point... So, that's why, I think you will need a service-specific "business" RTE to communicate those conditions. I don't know much about your system, but, generally, I would prefer to return such use case code as some kind of status code inside the object returned by the service API, and use exceptions to only indicate errors. The client may inspect the returned object's status, e.g. insertUser(...) would return an object, like an update User object. You could have a status property on that object that would indicate "newly created", "approved", whatever, or "error/code". It may be not applicable to your particular use cases/system, I don't know, but I always consider such possibilities before I decide to use an exception for a business case.

                        HTH,
                        Constantine

                        Comment


                        • #27
                          i get your point :-)

                          An idea would also be to transform all the stack elements from the XML into "PlSqlStackElement"' objects which are encapsulating each stack element.

                          I could then put all this elements to the DatabaseBusinessException (rte) with an addPlStackElements() as part of the Exception object.

                          This exception would be thrown in the custom SQLErrorCode Translator class and be catched in the Service layer or at the exception barrier and the developer would have the choice between adding a custom error message into the ErrorMessage object, which is displayed in the UI or picking the first/last stack element from the PL/SQL Stack element list and translate it with the right language (as we know the language setting at the web layer).

                          So the PL/SQL stack elements would be transported inside the DatabaseBusinessException object up the ladder...

                          What do you think?


                          p.s i really enjoy discussing my ideas with you as i think that they are more then constructive and im really thankful for all your support so far :-)

                          Comment


                          • #28
                            really getting mad here...

                            Now i have my DatabaseBusinessException where i have the PL/SQL exception stack elements attached with an ArrayList.

                            So when i first get the error stack from the DB i do the following:


                            Code:
                                private DataBaseBusinessException handleDBBusinessException(String errorMessage) {
                            	List plStackTrace = PlSqlStackTraceParser.parse(errorMessage);
                            
                            	DataBaseBusinessException dbbe = new DataBaseBusinessException("Some Business Errors happened in the DB - Please check the PL/SQL Stack trace") ;
                            	dbbe.setPlsqlExceptionStack(plStackTrace);
                            	
                            	return dbbe;
                                }
                            So the only stack element i see in the java exception stack is this message, which is just read by the developers.

                            Now comes the problem....after throwing this runtimeexception it gets caught by a JSF based class, that is trying to resolve the Expression Language element in my jsp.

                            To make it understandable...to have a better i18n i have created an annotation with a custom Property/Variable resolver in JSF that is able translate the following syntax.

                            MySimpleService.myBean.myattribute

                            JSF then calls the service method getMyBean() and resolves the myattribute attribute

                            As an exception is happening in the SQLErrorCodeTranslation the EL-Resolver of JSF is automatically throwing the javax.faces.el.EvaluationException
                            and the portlet PortletException etc.

                            That just means that i can never be sure that my exception that i threw is the last one or not and have to iterate programaticall through the error
                            stack and do some instanceof's to get my DatabaseBusinessException. Im i dreaming or do i really have to get that far? ;-D

                            I just wanted to show you the error stack (shortened as it exceeded the character limit):

                            Code:
                            [12.02.09 14:16:51:718 CET] 00000083 jsf           W com.sun.faces.application.ViewHandlerImpl getFacesMapping Unable to determine FaceServlet mapping for servlet path '/portlet'.
                            [12.02.09 14:16:51:734 CET] 00000083 jsf           W com.sun.faces.application.ViewHandlerImpl getFacesMapping Unable to determine FaceServlet mapping for servlet path '/portlet'.
                            [12.02.09 14:16:51:734 CET] 00000083 jsf           W com.sun.faces.application.ViewHandlerImpl getFacesMapping Unable to determine FaceServlet mapping for servlet path '/portlet'.
                            [12.02.09 14:16:57:359 CET] 00000083 PropertyAware I   Setting up the connection for further use...
                            [12.02.09 14:16:57:406 CET] 00000083 ServletWrappe E   SRVE0068E: Die Methode service() für das Servlet /XPOPublicSampleView.jsp konnte nicht aufgerufen werden. Ausgelöste Ausnahme: javax.servlet.ServletException: javax.faces.el.EvaluationException: Error getting property 'sampleBean' from bean of type pagecode.sample.XPOPublicSampleView: ch.xxxxxxx.xnet.fwk.exception.DataBaseBusinessException: Some Business Errors happened in the DB - Please check the PL/SQL Stack trace
                            	at org.apache.jasper.runtime.PageContextImpl.handlePageException(PageContextImpl.java:648)
                            	at com.ibm._jsp._XPOPublicSampleView._jspService(_XPOPublicSampleView.java:117)
                            	at com.ibm.ws.jsp.runtime.HttpJspBase.service(HttpJspBase.java:93)
                            	at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
                            	at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1696)
                            	at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:825)
                            	at com.ibm.wsspi.webcontainer.servlet.GenericServletWrapper.handleRequest(GenericServletWrapper.java:121)
                            	at com.ibm.ws.jsp.webcontainerext.JSPExtensionServletWrapper.handleRequest(JSPExtensionServletWrapper.java:216)
                            	at com.ibm.ws.webcontainer.webapp.WebAppRequestDispatcher.include(WebAppRequestDispatcher.java:670)
                            	at org.apache.pluto.core.impl.PortletRequestDispatcherImpl.include(PortletRequestDispatcherImpl.java:112)
                            	at com.ibm.faces.portlet.httpbridge.PortletRequestDispatcherWrapper.include(PortletRequestDispatcherWrapper.java:61)
                            	at com.ibm.faces.portlet.httpbridge.PortletRequestDispatcherWrapper.forward(PortletRequestDispatcherWrapper.java:35)
                            	at com.sun.faces.context.ExternalContextImpl.dispatch(ExternalContextImpl.java:325)
                            	at com.ibm.faces.portlet.httpbridge.PortletExternalContextWrapper.dispatch(PortletExternalContextWrapper.java:83)
                            	at com.sun.faces.application.ViewHandlerImpl.renderView(ViewHandlerImpl.java:262)
                            	at com.ibm.faces.portlet.PortletViewHandlerImpl.renderView(PortletViewHandlerImpl.java:74)
                            	at com.ibm.faces.portlet.PortletViewHandlerImpl.renderView(PortletViewHandlerImpl.java:74)
                            
                            
                            
                            ---- Begin backtrace for Nested Throwables
                            javax.faces.el.EvaluationException: javax.faces.el.EvaluationException: Error getting property 'sampleBean' from bean of type pagecode.sample.XPOPublicSampleView: ch.xxxxxxx.xnet.fwk.exception.DataBaseBusinessException: Some Business Errors happened in the DB - Please check the PL/SQL Stack trace
                            	at com.sun.faces.el.ValueBindingImpl.getValue(ValueBindingImpl.java:186)
                            	at com.sun.faces.el.ValueBindingImpl.getValue(ValueBindingImpl.java:137)
                            	at javax.faces.component.UIOutput.getValue(UIOutput.java:147)
                            	at com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getValue(HtmlBasicInputRenderer.java:84)
                            	at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.getCurrentValue(HtmlBasicRenderer.java:211)
                            	at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeEnd(HtmlBasicRenderer.java:171)
                            	at com.ibm.faces.renderkit.DefaultAjaxRenderer.encodeEnd(DefaultAjaxRenderer.java:83)
                            	at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:762)
                            	at javax.faces.webapp.UIComponentTag.encodeEnd(UIComponentTag.java:604)
                            	at javax.faces.webapp.UIComponentTag.doEndTag(UIComponentTag.java:527)
                            	at com.sun.faces.taglib.html_basic.OutputTextTag.doEndTag(OutputTextTag.java:202)
                            	at com.ibm._jsp._XPOPublicSampleView._jspx_meth_h_outputText_0(_XPOPublicSampleView.java:178)
                            	at com.ibm._jsp._XPOPublicSampleView._jspx_meth_h_form_0(_XPOPublicSampleView.java:399)
                            	at com.ibm._jsp._XPOPublicSampleView._jspx_meth_hx_scriptCollector_0(_XPOPublicSampleView.java:449)
                            
                            
                            Caused by: javax.faces.el.EvaluationException: Error getting property 'sampleBean' from bean of type pagecode.sample.XPOPublicSampleView: ch.xxxxxxx.xnet.fwk.exception.DataBaseBusinessException: Some Business Errors happened in the DB - Please check the PL/SQL Stack trace
                            	at com.sun.faces.el.PropertyResolverImpl.getValue(PropertyResolverImpl.java:90)
                            	at com.ibm.faces.databind.SelectItemsPropResolver.getValue(SelectItemsPropResolver.java:41)
                            	at ch.xxxxxxx.xnet.fwk.jsf.resolver.CommonPropResolver.getValue(CommonPropResolver.java:47)
                            	at com.sun.faces.el.impl.ArraySuffix.evaluate(ArraySuffix.java:167)
                            	at com.sun.faces.el.impl.ComplexValue.evaluate(ComplexValue.java:151)
                            	at com.sun.faces.el.impl.ExpressionEvaluatorImpl.evaluate(ExpressionEvaluatorImpl.java:243)
                            	at com.sun.faces.el.ValueBindingImpl.getValue(ValueBindingImpl.java:156)
                            	at com.sun.faces.el.ValueBindingImpl.getValue(ValueBindingImpl.java:137)
                            	at javax.faces.component.UIOutput.getValue(UIOutput.java:147)
                            	at com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getValue(HtmlBasicInputRenderer.java:84)
                            	at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.getCurrentValue(HtmlBasicRenderer.java:211)
                            	at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeEnd(HtmlBasicRenderer.java:171)
                            	at com.ibm.faces.renderkit.DefaultAjaxRenderer.encodeEnd(DefaultAjaxRenderer.java:83)
                            	at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:762)
                            	at javax.faces.webapp.UIComponentTag.encodeEnd(UIComponentTag.java:604)
                            	at javax.faces.webapp.UIComponentTag.doEndTag(UIComponentTag.java:527)
                            	at com.sun.faces.taglib.html_basic.OutputTextTag.doEndTag(OutputTextTag.java:202)
                            	at com.ibm._jsp._XPOPublicSampleView._jspx_meth_h_outputText_0(_XPOPublicSampleView.java:178)
                            	at com.ibm._jsp._XPOPublicSampleView._jspx_meth_h_form_0(_XPOPublicSampleView.java:399)
                            	at com.ibm._jsp._XPOPublicSampleView._jspx_meth_hx_scriptCollector_0(_XPOPublicSampleView.java:449)
                            	at com.ibm._jsp._XPOPublicSampleView._jspx_meth_f_view_0(_XPOPublicSampleView.java:476)
                            	at com.ibm._jsp._XPOPublicSampleView._jspService(_XPOPublicSampleView.java:110)
                            
                            
                            
                            
                            Caused by: ch.xxxxxxx.xnet.fwk.exception.DataBaseBusinessException: Some Business Errors happened in the DB - Please check the PL/SQL Stack trace
                            	at ch.xxxxxxx.xnet.fwk.exception.CommonSQLErrorCodeTranslator.handleDBBusinessException(CommonSQLErrorCodeTranslator.java:28)
                            	at ch.xxxxxxx.xnet.fwk.exception.CommonSQLErrorCodeTranslator.customTranslate(CommonSQLErrorCodeTranslator.java:19)
                            	at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.translate(SQLErrorCodeSQLExceptionTranslator.java:230)
                            	at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:212)
                            	at org.springframework.orm.ibatis.SqlMapClientTemplate.update(SqlMapClientTemplate.java:411)
                            	at org.springframework.orm.ibatis.SqlMapClientTemplate.update(SqlMapClientTemplate.java:405)
                            	at ch.xxxxxxx.xnet.sample.dao.SampleDAO.getBusinessException(SampleDAO.java:20)
                            	at ch.xxxxxxx.xnet.sample.service.SampleService.getBusinessException(SampleService.java:22)
                            	at pagecode.sample.XPOPublicSampleView.getSampleBean(XPOPublicSampleView.java:39)
                            	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                            	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:85)
                            	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:58)
                            	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:60)
                            	at java.lang.reflect.Method.invoke(Method.java:391)
                            	at com.sun.faces.el.PropertyResolverImpl.getValue(PropertyResolverImpl.java:80)
                            	at com.ibm.faces.databind.SelectItemsPropResolver.getValue(SelectItemsPropResolver.java:41)
                            	at ch.xxxxxxx.xnet.fwk.jsf.resolver.CommonPropResolver.getValue(CommonPropResolver.java:47)

                            Comment


                            • #29
                              Hi uenluena,

                              I have to admit I am reluctant to even try to understand what exactly is going on there. However, as I have said before, one should not use any data inside an exception class to handle business cases. It is just incorrect. That is not what exceptions are for. Such data is for diagnostics only. And exceptions are not meant to signal use cases in general. They should be used to transport the error data and nature to the designated handler. (Hence, checked exceptions are nonsense because they do not allow to transport anything - by stopping the exception immediately.) It may be ok for the handler to redirect to a certain business use case based on the nature of the error, but not based on the error detail/ID/Key/description/stack trace/etc. encapsulated within the exception. The latter is bad design and misuse of exceptions. The fact that many people do that, and many books advocate that, doesn't make it right. Most books focus on explaining other things and error handling in their examples is nothing more than an afterthought, something of little importance, something they just add at the last moment. Unfortunately, I have not seen a single Java book that has a good chapter on exceptions or error handling. The better frameworks (e.g. Spring) that implement proper exception management do not go to a great length explaining the rationale. It's not their job really. It's a framework, not a Java tutorial. Most Internet articles on exceptions are extremely misguiding and only help to spread confusion and misconceptions.

                              Sadly, most new programmers these days start by learning technologies instead of understanding the basic principles first - or ever. Such approach, unfortunately, has an implication that the technology should be taken as a given, almost as a flawless concept. That, in turn, results in many people (SEs and managers) mistakenly viewing programming as a process reduced to using the given set of technologies and recommended recipes (patterns) - rarely questioning the validity of the technologies themselves. Such people may debate whether a specific technology is applicable to the given project or not, but only the best few actually go as far as analyzing the technology itself and the fundamental principles it is built upon, whether its complexity is justified, etc. That's why the industry was stuck with horrendous things like EJB, JSP, checked exceptions, etc - for so long. All those things were designed so that they all but enforced complexity, poor programming practices, and guaranteed mistakes to be made left and right. And yet, the majority of Java programmers have been blindly following the suit - like cattle to the slaughter. Not all, fortunately. That's why we have Spring, for one...

                              Back to your issue. See what's been happening? Instead of programming your business logic, you have already spent several months struggling with exception handling! The design those people have imposed on you is a great example of how hugely error handling is misunderstood. Considering that you are dealing with someone else's design that you can't change, you should focus on isolating the bad design and abstracting it from the rest of the application - not propagating it all the way. This means the following...

                              1) If some of the DB exceptions in your application in reality mean legitimate use cases, catch those exceptions as early as possible - i.e. in your data access tier, and translate them into meaningful [to the business tier] things. It's up to you to decide what it would be. As we have discussed, you may parse each exception (each combination of that horrendous "stack" of exceptions you mention) and map each combination to an enum type that represents a legitimate status of a db operation. Return that status [as part of the returned object, perhaps] from your service API call. Don't let any such "exceptions" propagate. On your front-end, analyze the status and act appropriately - without dealing with exceptions in such cases at all.

                              2) If the DB exception means a real data access error, wrap it into a RTE and re-throw all the way. Don't bother with details, just display a generic error message but log the whole exception stack trace. There's nothing else you can do.

                              When you create a new exception that will wrap an original exception, always use a constructor that takes the cause! I see you are creating a new exception ignoring the cause and then just add the stack trace retrieved from the cause. That's not good.

                              And finally, keep in mind that nothing in the front-end should ever even know about the existence of the data tier. The words like SQL or DB should not show in any front-end class names. Your front-end is only exposed to the business tier that may or may not have a database underneath - for all you care. So, your front-end catch blocks must not specifically bother with any exceptions that have "SQL" in their class names. (Anything of that sort should be cought by your "catch Throwable".) Just look for some instances of your business exceptions - if you really need and can do something different about those, and, ultimately, any Throwable. That brings us back to my point: any use cases represented - foolishly! - by DB exceptions absolutely must be converted into meaningful "business" (non-DB) concepts before they reach the client.

                              BTW, unless we discuss general architecture issues that may be of interest to other people, I think it may be more appropriate to use "private messages" or emails if the conversation gets too focused on one particular project.

                              Cheers,
                              Constantine
                              Last edited by constv; Feb 12th, 2009, 11:06 AM.

                              Comment


                              • #30
                                I did a personal text memo, for my own use, that I have not published anywhere. It is made of the excellent posts of Constv in this thread.
                                It is mostly copy paste with some rewording of the above posts among others. Credits for its value go to Constv. Potential mistakes are mine.

                                I had edited this text before finding out about the blog article of Constantin Vasilyev on the subject:
                                http://articles.vconst.com/2009/08/e...s-in-java.html
                                which does a much better job at explaining the history, rationale and best practice with error handling than my cheap text memo.

                                But there you are, my text memo:

                                An exception is not an error code, but rather a mechanism designed to ease error handling, without having to deal with the error until it gets to its dedicated exception handler, often away from the origin of the error.

                                There are two types of exceptions, checked exceptions and unchecked exceptions.

                                Checked exceptions need to be caught or re-thrown. This polutes the application with unnecessary source code.
                                With a checked exception, the compiler forces an implementation, as the source code will not compile if a checked exception is not caught or re-thrown.
                                This results in the exception being exposed in places it has nothing to do, exposing implementation details that should remain hidden, and with the risk of the exception being swallowed or mishandled.
                                Checked exceptions have another side effect. They imply that those checked exceptions that must be handled, are the only ones that will ever occur. To think that no other unchecked exceptions will ever happen is a risky bet. This misconception that only these checked exceptions should be handled, results in the actual handling of a subset of all the possible exceptions, and makes the application less safe.

                                Unchecked exceptions do not need to be caught nor re-thrown. With an unchecked exception, the application developer can decide if, where and how to react to the exception. The exception is only exposed when needed. It is not exposed through out the methods of the call stack, in some source code that has no business in doing anything about the exception, like mishandling it instead of letting it bubble up to its appropriate handler.

                                So, use unchecked exceptions and avoid checked exceptions !

                                Implement the exception handler where it belongs to, that is, in the component that actually knows what to do with the error, and let the exception freely bubble up to the exception handler.

                                Have few centralized exception handlers, and no error handling code anywhere else in the application. Errors must travel freely through the call stack, up to the exception handler.

                                Exceptions must keep the complete information. Never discard the stack trace and never replace it with a custom error messages.

                                The controller is a good place to have the exception handler, as it has all the context to know what to do with the exception. It catches all bubbled-up unchecked exceptions, it can handle some of them based on some business cases of the application, and redirect the rest of them to a system error page, displaying just a user friendly message.

                                The front-end controller is a good place for the generic exception handler that handles all exceptions and logs them in a text file. The only responsibility the generic exception handler has, is to log the data, whatever it is, without inspecting it, and let the application proceed whichever way is appropriate for a system error. It is the responsibility of the service that threw these exceptions to supply any information that should be logged by the generic exception handler that waits up the call stack. The front-end controller must therefore have a catch on the base contextual exception class, that will catch all exceptions extended from the base contextual exception class.

                                The exception handler can also be in a service or even in a data access tier (Dao). For example, if the Dao has enough knowledge to interpret a specific sql error, then it's okay for the Dao to catch that checked or unchecked exception. The Dao must then wrap it into a more meaningful unchecked exception with a readable message. But the Dao cannot recover from the exception. It can only help clarify the error. The new unchecked exception must contain the nested original exception, and it must reach the exception handler in the controller. The user is not interested in what exactly happened, if there is no business case for that condition. The user must simply be redirected to an error page and the exception logged. The complete stack trace with all the additional information supplied by the Dao that wrapped the original exception can then be logged.

                                If some exception represents some legitimate business condition, then the service or Dao must catch that exception, and reflect the condition in the state of some business object. Alternatively, it may re-throw a business specific unchecked exception, which the controller must catch so as to redirect to take appropriate action. In that latter case, do not add any kind of data, like some error code, into the exception for later handling by an exception handler in the controller. Exceptions are not error codes and their handlers must expect at most a particular type of exception class and they should not need to check for anything else. If a handler catches a certain type of exception, it may expect to be able to call certain methods on the caught exception, but it should do it blindly without worrying what data is actually stored inside the exception. For example, the handler may retrieve the message or the stack trace, but it would be very risky to inspect the message string for some specific content and act upon it.

                                The exception handler must always log the full exception stack trace. The exception handler should also log some application context. The context usually is in the user session, accessible by the controller. To avoid having additional contract between the controller and the service and not pass the application context back and forth between them, the application context must be stored in the exception. The exception then extends a base contextual exception class that can accept any arbitrary object so as to store the application context. The service can throw some unchecked exception that extends that base contextual exception class. When throwing an exception in the service, some application context available in the service can be stored in the exception. And some additional application context can later be stored on the exception by the controller.

                                The base contextual exception class has a method that simply writes out a string representation of the context stored on the exception, and is placed in some common package.

                                The only factor that should determine where to handle errors in the application is the specific requirements of the application. In other way, based on what behavior of the application is needed, in case of any error, decide which source code in the application has sufficient contextual knowledge to handle the error. This generally means that all exceptions in the middle tier, that is, the service and Dao, must freely propagate to the controller, that would ultimately handle them. To ensure this behavior, all the exceptions must be unchecked. This means that any checked exception in the service must be caught, wrapped into some clarifying unchecked exceptions with added messages, and re-thrown, only to be caught and handled by the designated handler in the controller, since only the latter would know what exactly the application needs to do with those errors. In some cases, an unchecked exception may be caught, wrapped and re-thrown if this can add valuable information to it on the way. But no matter what, never discard the original exception, and never replace the valuable stack trace with an error message. Always keep the full original stack trace and nested exception, because they provide the most important infomtionabout the source of the error.

                                As for Dao exceptions, ideally, these should not be caught in the Dao but in the service, where more contextual data can be added, before being re-thrown. A service specific unchecked exception, wraps the original exception that came from the Dao and adds the service specific context to it. Any Dao exception is a system exception, something that should not happen. So, if it happens, from the standpoint of handling, it carries no business condition, it's bad, and its handled by the generic exception handler. The service, before re-throwing it, will add whatever information is appropriate to it, so as to be read by the developer. This is a good case for an aspect, to automatically place all the service method's arguments into the exception as context. That allows for a single aspect around every public method of every service to ensure that any throwable inside the method will be caught, wrapped into an instance of a service exception, augmented with the method's input arguments, and re-thrown. The generic exception handler will have a catch for the base contextual exception, log everything, and redirect to the error page. If the context needs to be more specific for a particular service method, then a try/catch/throw must be implemented in the service, but that would not be very pretty.

                                Comment

                                Working...
                                X