18 Replies Latest reply: Mar 26, 2013 5:14 PM by Aegis Kleais RSS

    How to handle errors if error component doesn't exist yet

    Aegis Kleais Community Member

      Traditionally, when I encapsulate code in a <CFTRY> block, I have it use the 'APPLICATION.coms.fw.error' component to handle processing of that error.

       

      This is all well and fine, but during the first call to the application, where everything is starting up, lots of processing is done reading configuration files to get pathing, etc.  And that code has <CFTRY> blocks, but the thing is, they wouldn't be able to all the error component (because it hasn't yet been instantiated).

       

      So should I just do something like:

       

      <cfif isDefined( 'APPLICATION.coms.fw.error' )>
      <!--- Handle Error Via Component. --->
      <cfelse>
      <!--- Output message to screen, use CFLOG to log error and the CFABORT to halt further processing. --->
      </cfif>
      
        • 1. Re: How to handle errors if error component doesn't exist yet
          saurav Pandit Community Member

          Hi Aegis Kleais,

           

          "And that code has <CFTRY> blocks, but the thing is, they wouldn't be able to all the error component (because it hasn't yet been instantiated)"

           

          -- What if if you use only try catch to handle it. I am not sure about the purpose of using "APPLICATION.coms.fw.error" but it seems that you can try simple try catch to handle it.

           

          <cftry>

          //your code here

          <cfcatch type="any">

          </cfcatch>

          </cftry>

          • 3. Re: How to handle errors if error component doesn't exist yet
            Aegis Kleais Community Member

            @saurav

             

            The APPLICATION.coms.fw.error is a component that has been instantiated into the APPLICATION scope (so that it is available to all user across the application) and is designed to handle errors that we've "handled" via CFTRY/CFCATCH blocks.  You don't need the TYPE attribute if you want to use "any" as it is the default action.

             

            @BKBK

             

            I read the entire article and it goes into basic tools that ColdFusion has for handling errors (CFTRY/CFCATCH) using the onError() method in the application.cfc, etc.  But it doesn't seem to address the issue I'm having.  I want to be able to call my error handler component stored in APPLICATION.coms.fw.error, but I don't know if it exists yet.

             

            What I've taken to trying is to using the CFMODULE tag inside my CFCATCH tags.  It points to a 'handled-exceptions.cfm' module that has code in it which does the following:

             

            <cfif THISTAG.executionMode eq 'start'>
                 <cfif isNull( APPLICATION.coms.fw.error )>
                      <!--- The error-handling component isn't yet instantiated. --->
                      <cflog file="#ATTRIBUTES.logFilename#" text="#ATTRIBUTES.logMessage#" type="#ATTRIBUTES.logSeverity#" />
                      <cfdump var="#ATTRIBUTES.logMessage#" abort="true" />
                 <cfelse>
                      <!--- The error-handling component exists, so let's use it instead. --->
                      <cfset APPLICATION.coms.fw.error.processHandledException(
                           message = "#ATTRIBUTES.logMessage#"
                      ,     catchData = ATTRIBUTES.catchData
                      ) />
                 </cfif>
            <cfelse>
            
            </cfif>
            

             

            That way, whenever I need to determine if the error component exists AND call it at the same time, I can do something like:

             

            <cftry>
            
                 <!--- Do something here that causes an error. --->
            
                 <cfcatch>
                      <cfmodule
                           template="/path/to/handled-exceptions.cfm"
                           attributecollection="#{
                                message = 'This is a message about the error we caught'
                           ,     catchData = CFCATCH
                           }#" />
                 </cfcatch>
            
            </cftry>
            

             

            This has been about the best implementation I've found.

            • 4. Re: How to handle errors if error component doesn't exist yet
              BKBK MVP

              Aegis Kleais wrote:

               

              I read the entire article and it goes into basic tools that ColdFusion has for handling errors (CFTRY/CFCATCH) using the onError() method in the application.cfc, etc.  But it doesn't seem to address the issue I'm having.

              If your requirement falls outside those standard error-handling methods, then it is very likely that the requirement involves some over-designing.

               

              The APPLICATION.coms.fw.error is a component that has been instantiated into the APPLICATION scope (so that it is available to all user across the application)

              It is unclear to me whether APPLICATION.coms.fw.error is an application variable (in which you've stored an instance of a CFC created, for example, using createObject) or the path to error.cfc in dotted notation(that is, the path /application/coms/fw/error.cfc).

              • 5. Re: How to handle errors if error component doesn't exist yet
                Aegis Kleais Community Member

                Sorry I wasn't clear on that.  'APPLICATION.coms.fw.error' is a CFC that was instantiated and stored into the APPLICATION scope (at that structure name location) so that it could be called by any request to the application.

                 

                I had a variable called COMS that I iterated over and create instances out of like

                 

                <cfloop query="coms">

                     <cfset structInsert( APPLICATION.coms.fw, name, 'path.to.fw.coms.' & name, true ) />

                </cfloop>

                 

                Doing so gives me an APPLICATION-stored component that I can call like:

                 

                APPLICATION.coms.fw.data

                APPLICATION.coms.fw.error

                APPLICATION.coms.fw.template

                etc.

                 

                I basically just didn't want to have to place code that checked if these CFC's existed each time I did a CFTRY/CFCATCH (because there is error-handling done before those CFC's are put into the APPLICATION scope) so I think using the CFMODULE to "compartmentalize" the existence-checking code was the best course of action.

                • 6. Re: How to handle errors if error component doesn't exist yet
                  BKBK MVP

                  Aegis Kleais wrote:

                   

                  I basically just didn't want to have to place code that checked if these CFC's existed each time I did a CFTRY/CFCATCH (because there is error-handling done before those CFC's are put into the APPLICATION scope)

                  That answers your question! Instantiate the CFC and store the instance in the application scope just before this particular error-handling. You will then know, in all the code that follows, that the application variable exists.

                  • 7. Re: How to handle errors if error component doesn't exist yet
                    Aegis Kleais Community Member

                    In my application.cfc I have some constructor code (that runs, I presume, before the onApplicationStart() fires off)  I had to error check it as well, but now that you mention it, I can just move the checks it's doing when the application is NOT yet created into the beginning actions in the onApplicationStart().

                     

                    With that addressed, let me ask a followup question if I may.

                     

                    The application.cfc runs on every request right?  I have code in the "constructor" (area outside the functions, right)  This is code which runs an if-check on isNull( APPLICATION ) to determine if the APPLICATION scope has been initialized.  If it has, it takes a structure I created called APPLICATION.appServer.appVars and iterates through it, setting its keys into the THIS scope.  (This structure only exists AFTER the application starts up and this is how I can store values defined by the application's processed config file into the THIS scope dynamically)

                     

                    So, on the first startup, the onApplicationStart() (oAS()) runs.  When it is done, there will be an APPLICATION.coms.fw.error object, but during the running of the oAS() I need to do some error handling.  By using the <CFMODULE> tag pointed to an error-handler.cfm file during the oAS() that tag runs some encapuslated coded which checks if the APPLICATION.coms.fw.error component exists yet, and if so uses it, and if not, logs and outputs a specified error message to the user, then aborting the request.

                     

                    Does this sound like a viable method?  Or am I taking the non-simplistic approach?

                    • 8. Re: How to handle errors if error component doesn't exist yet
                      BKBK MVP

                      As a rule, you should avoid any elaborate code logic, such as if-then-else, in the pseudo-constructor area. In fact, I think the design is only getting more complex.

                       

                      Originally, you wished to ensure a variable in the application scope exists, before you could do something else. My suggestion was, why not set the application variable right at the beginning. As you have now revealed, onApplicationStart is the ideal place to initialize the application variables. Such variables will then be available anywhere in the application, and throughout the life of the application. Voila! Original question answered.

                      • 9. Re: How to handle errors if error component doesn't exist yet
                        Adam Cameron. Community Member

                        Get rid of any logic like that. Initialise your application in onApplicationStart. There. Done. It's initialised. No need to do tests like "is it initialised?", because you know the answer will be yes.

                         

                        Limit any logic in the pseudo consrtuctor to that dealing with this-scoped variables. Don't mess with variables of any other scope in there, because it's the wrong place to do it. Set application-scoped variables in onApplicationStart(), session ones in onSessionStart(), and request ones in onRequestStart(). They're there for a reason.

                         

                        Also perhaps read this:

                        http://adamcameroncoldfusion.blogspot.co.nz/2012/08/more-on-applicationcfc-when-things-run .html

                         

                        --

                        Adam

                        • 10. Re: How to handle errors if error component doesn't exist yet
                          Aegis Kleais Community Member

                          Don't the THIS-scope ColdFusion Application variables have to be set in the constructor area of the application.cfc?

                           

                          My applications, as they are built now, process a config file in order to allow for custom ColdFusion application variables.  So my current solution is that I cannot just hard-code the THIS-scope variables statically.  The only solution I had to this was to use constructor-code conditional checking if the variable that stores these values after application initialization existed, and if so, it iterates through it and creates the THIS-scope variables on the fly (and if it doesn't exist, ie, the application hasn't started up yet) then it just sets the minimum THIS-scope values (a randomized value placed into the THIS.name variable)

                           

                          I'm not trying to be complex, but I'm trying to develop my applications to run off a framework that I am developing, and a configuration file seemed like a nice modular method to achieve this.

                          • 11. Re: How to handle errors if error component doesn't exist yet
                            Adam Cameron. Community Member

                            Aegis Kleais wrote:

                             

                            Don't the THIS-scope ColdFusion Application variables have to be set in the constructor area of the application.cfc?

                             

                             

                            Well... yes. Which is what I said.

                             

                            --

                            Adam

                            • 12. Re: How to handle errors if error component doesn't exist yet
                              Aegis Kleais Community Member

                              Well, then, knowing that I have applications with configuration XML files that are loaded up and can specify the application's unique CF application variables, wouldn't it be OK for me to have out-of-onApplicationStart() code in my constructor that checks if the application exists or not, and if so, creates those THIS-scope vars each time the application.cfc is called? 

                               

                              In other words, "Is aight, right?"  I was confused because I saw BKBK's comment that stated "As a rule, you should avoid any elaborate code logic, such as if-then-else, in the pseudo-constructor area."

                               

                              Maybe he meant it's more of a "guideline" than a hard rule?

                              • 13. Re: How to handle errors if error component doesn't exist yet
                                BKBK MVP

                                Aegis Kleais wrote:

                                 

                                I was confused because I saw BKBK's comment that stated "As a rule, you should avoid any elaborate code logic, such as if-then-else, in the pseudo-constructor area."

                                 

                                Maybe he meant it's more of a "guideline" than a hard rule?

                                By 'rule' I of course meant guideline. It is clear from the example.

                                 

                                Well, then, knowing that I have applications with configuration XML files that are loaded up and can specify the application's unique CF application variables, wouldn't it be OK for me to have out-of-onApplicationStart() code in my constructor that checks if the application exists or not, and if so, creates those THIS-scope vars each time the application.cfc is called?

                                You're perhaps confusing application-scope variables with application.cfc's public instance variables. Application-scoped variables are of the form application.someVar, and are usually initialized in onApplicationStart. They apply to the entire application, and so can be referenced directly in any ColdFusion page or CFC.

                                 

                                Application.cfc's public instance variables are usually of the form this.someVar, and are set in Application.cfc's pseudo-constructor area. They apply to just Application.cfc. You cannot reference them directly in a ColdFusion page or CFC.

                                • 14. Re: How to handle errors if error component doesn't exist yet
                                  Aegis Kleais Community Member

                                  @BKBK

                                   

                                  Would that mean that in the APPLICATION.CFC's pseudo constructor, that the THIS-scope and VARIABLES-scope are the same thing?

                                   

                                  As you stated, I have APPLICATION-scoped variables stored in locations like 'APPLICATION.variablename' as well as more detailed structures under the APPLICATION scope like 'APPLICATION.coms.fw' (which holds all framework components).

                                   

                                  I am finding that in my onApplicationStart(), any VARIABLES-scoped variables that I have has to be provided along with the call to components in order for them to have access to that value (without going through component extension)

                                   

                                  ie, in my application.cfc I have instances like this:

                                   

                                  <cftry>

                                   

                                       <cfset APPLICATION.coms.fw.template.generateCode(

                                            logFile = VARIABLES.logFile,

                                            argument = value,

                                            etc.

                                       ) />

                                   

                                       <cfcatch>

                                            <!--- Handle an error. --->

                                       </cfcatch>

                                   

                                  </cftry>

                                   

                                  I mean, I guess I could just send it the VARIABLES scope as a structure rather than specify individual variables, but I get the feeling that would be sloppy of me.

                                  • 15. Re: How to handle errors if error component doesn't exist yet
                                    BKBK MVP

                                    Aegis Kleais wrote:

                                     

                                    Would that mean that in the APPLICATION.CFC's pseudo constructor, that the THIS-scope and VARIABLES-scope are the same thing?

                                    No. This.someVar is public, wheres variables.someVar is private.

                                     

                                     

                                    As you stated, I have APPLICATION-scoped variables stored in locations like 'APPLICATION.variablename' as well as more detailed structures under the APPLICATION scope like 'APPLICATION.coms.fw' (which holds all framework components).

                                     

                                    I am finding that in my onApplicationStart(), any VARIABLES-scoped variables that I have has to be provided along with the call to components in order for them to have access to that value (without going through component extension)

                                    The way to go is, application-scoped - not variables-scoped - variables, defined in onApplicationStart().

                                    • 16. Re: How to handle errors if error component doesn't exist yet
                                      Aegis Kleais Community Member

                                      Oh man, I forgot all about the THIS/VARIABLES public/private thing.  Thanks for pointing that out BKBK

                                      • 17. Re: How to handle errors if error component doesn't exist yet
                                        Adam Cameron. Community Member

                                        Over and above the scope accessibility thing, in Application.cfc, the only real reason to use this-scoped variables are to set the predefined application settings (eg: this.name, this.sessionManagement etc). And variables-scoped variables would simply be for the reason one might usually have variables-scoped variables within a CFC.  At the end of the day Application.cfc is still just a CFC, so all the scoping and usage rules are the same. Except that some this-scoped variables have special meaning as far as the application framework is concerned.

                                         

                                        --

                                        Adam

                                        • 18. Re: How to handle errors if error component doesn't exist yet
                                          Aegis Kleais Community Member

                                          Well said, Adam.

                                           

                                          I had recently stopped myself from making components inheit from application.cfc just so it had access to the VARIABLES scope.  Instead, I've been passing the variables into the components as needed.  Code seems much cleaner that way, so I'm happy.