12 Replies Latest reply on Aug 19, 2008 3:05 PM by Adam Cameron

    How to get the page call stack

    Abram Adams Level 1
      Is there any way to get a list of files used in building a single page? What I need is to be able to see what page called the custom tag from within that custom tag. Using getBaseTemplatePath doesn't work because it only shows the top level page, not the actual file that called the custom tag. Take the following structure for instance:
      /webroot/mydir/myfile.cfm
      /webroot/mydir/myincludes/includefile.cfm
      /webroot/customtags/thecustomtag.cfm

      If myfile.cfm cfincludes includedfile.cfm and then includefile.cfm calls thecustomtag.cfm, thecustomtag.cfm thinks myfile.cfm called it. Which is wrong, and a bit stupid.

      I've tried the back door method:
      <cfset objFactory = CreateObject( "java", "coldfusion.server.ServiceFactory" ) />
      <cfset objDebugging = objFactory.GetDebuggingService() />
      <cfset qEvents = objDebugging.GetDebugger().GetData() />
      <cfdump var="#qEvents#">

      But found out later that this only works with debugging turned on in CF admin AND no IP restrictions are set (unless the IPs for the clients are listed there).

      This should be a very simple task, one would think. Any suggestions?
        • 1. Re: How to get the page call stack
          Scatterblak
          We CFInclude the following snippet into all project files when this functionality is needed:

          <CFScript>
          //////////////////////////////////////////////////////////////////////////
          //
          // Init Template Management
          //
          myName = getFileFromPath(getCurrentTemplatePath());
          if(NOT isDefined('TemplateManagement')){
          TemplateManagement = structNew();
          TemplateManagement.cnt = 0;
          }
          else{
          TemplateManagement.cnt = TemplateManagement.cnt + 1;
          }
          if(NOT structKeyExists(TemplateManagement, myName)){
          TemplateManagement[myName] = structNew();
          }
          //
          // Versioning:
          //
          TemplateManagement[myName].App.Version.Major = 1;
          TemplateManagement[myName].App.Version.Minor = 1;
          //
          // License:
          //
          TemplateManagement[myName].License.SerialNumber = '';
          TemplateManagement[myName].License.Owner = '';
          //
          //
          //////////////////////////////////////////////////////////////////////////
          </CFScript>


          ...at the end of the http request, usually in onRequestEnd.cfm, you can grab the 'TemplateManagement' struct and take a look.
          • 2. Re: How to get the page call stack
            Abram Adams Level 1
            Hmmm... not sure what you mean. Your snippet creates a structure key using the filename with version/license info. What I'm looking for is how to grab the path of the real calling file.

            The problem is that cfincluded files don't expose the real calling page, but thinks it was called from the top level requested page. In your snippet, if you add :

            TemplateManagement[myName].path = getCurrentTemplatePath();
            TemplateManagement[myName].basepath = getBaseTemplatePath();

            Then cfinclude that file from a cfincluded file you'll see what I mean.
            • 3. Re: How to get the page call stack
              Abram Adams Level 1
              anyone? Is this not possible?
              • 4. Re: How to get the page call stack
                Level 7
                solutionfinder wrote:
                > anyone? Is this not possible?

                I assume it must be possible, because CF itself can output it in an
                error page, but I have no idea how us lowly developers can get access to
                the information.

                To add a bit to the the <cfinclude...> question. You are complaining
                that is works exactly as documented how it will work. A include is to
                be logically considered as part of the page that included it thus
                sharing all variables and such that belong to the page.

                • 5. Re: How to get the page call stack
                  Abram Adams Level 1
                  CF uses coldfusion.server.ServiceFactory.GetDebuggingService() to output the error page, if turned on in the CF admin. I am currently using that for this case but I need to find a way to do it without the debugger turned on.

                  I understand that it is to be logically considered part of the page that included it, but it sure would be nice to be able to determine the *real* path not just the logical one. I'm not complaining that this isn't working as designed, I'm just saying the design leaves much to be desired n this respect.

                  Though like you said, were just "lowly developers" so why do we need that kind of control :).
                  • 6. Re: How to get the page call stack
                    Level 7
                    solutionfinder wrote:
                    > CF uses coldfusion.server.ServiceFactory.GetDebuggingService() to output the
                    > error page, if turned on in the CF admin. I am currently using that for this
                    > case but I need to find a way to do it without the debugger turned on.

                    I'm not in a place to experiment at the moment, but does the 'debugger'
                    have to be turned on? I mean does CF not display the file stack on an
                    error page even if 'debugging' is not turned on? I would have thought
                    it does, but I have never tried to identify this before.
                    • 7. Re: How to get the page call stack
                      Abram Adams Level 1
                      It displays it as long as the "Enable Robust Exception Information" option is on. However, if the debugging is off (or and IP filter is used) then only CF can access the data. With debugging off if you do this:
                      <cfset objFactory = CreateObject( "java", "coldfusion.server.ServiceFactory" ) />
                      <cfset objDebugging = objFactory.GetDebuggingService() />
                      <cfset qEvents = objDebugging.GetDebugger().GetData() />
                      <cfdump var="#qEvents#">

                      you get a null pointer error.
                      • 8. Re: How to get the page call stack
                        Level 7
                        solutionfinder wrote:
                        > However, if the debugging is off (or and IP filter is used) then only CF
                        > can access the data.

                        I wonder, in the case of debugging is off, that the information is just
                        someplace else in the service factory, only known to Adobe nee
                        Macromedia nee Allaire engineers. I would speculate that the debugging
                        objects in the factory might just acquire the information from this
                        other place. But I have no advice on how to find it, if it is at all
                        available. I have never had need to mess with the service factory.

                        • 9. Re: How to get the page call stack
                          Abram Adams Level 1
                          probably. I don't like using the service factory at all. I don't think its even supported (unless that's changed). But to date it is the only way I can find the real include path.

                          I'll probably have to pass this info in as a variable, though that breaks the dynamic nature of things (and sort of defeats the purpose).
                          • 10. Re: How to get the page call stack
                            Level 7
                            solutionfinder wrote:
                            >
                            > I'll probably have to pass this info in as a variable, though that breaks the
                            > dynamic nature of things (and sort of defeats the purpose).
                            >

                            Could you build your own stack dynamically? I can imagine where a line
                            or two of code in each template adds something to a global structure at
                            the beginning and removes the node at the end. It would be manual to
                            make sure that this code exists in all templates since there is no way
                            to do this automatically that I can think of. But that maybe a bit
                            better then nothing.

                            • 11. Re: How to get the page call stack
                              Level 7
                              I've tried to work out the same thing as you previously, but pretty much
                              covered the same ground you're reporting.

                              If you throw an exception and catch it, the catch struct has the template
                              stack in it. It's not a very performant practice though, as CF error
                              handling seems to add quite an over to processing.

                              You could possibly create a very small template doing just the try / throw
                              / catch, compile it and then decompile the class file to see what Java is
                              being called under the hood. It might point you in the right direction.

                              --
                              Adam
                              • 12. Re: How to get the page call stack
                                Cool, I found it. Well: I read someone's blog and they mentioned something related, which got me experimenting.

                                All one needs to do is to create an Exception object, thus:

                                {code}
                                oException = createObject("java","java.lang.Exception").init();
                                {code}

                                Dump that, and you'll see there's a tagContext array...

                                --
                                Adam