Ns adp include

From AOLserver Wiki
Jump to navigation Jump to search

Man page: http://aolserver.com/man/4.0/tcl/ns_adp_include.html


NAME

ns_adp_include - Parse an ADP file with the generated output written to the adp buffer

SYNOPSIS

ns_adp_include ?-cache seconds |-nocache? file ?arg arg ...?

DESCRIPTION

This command reads file and parses its contents as an ADP with the generated output written to the adp buffer and returns the adp return value (i.e. from return, ns_adp_return or the last tcl command in the adp) to the caller. file is relative to the caller's directory unless an absolute pathname is used. Tcl commands in the ADP are evaluated in a new scope one level below the caller just like when calling a proc. Optional arguments can be passed which are accessed using ns_adp_argc, ns_adp_argv and ns_adp_bind_args commands in the callee.
The optional -cache seconds argument specifies the time to cache the results of execution (i.e. the output written to the adp buffer). Output generated by any scripts and included ADPs is saved for subsequent requests except ns_adp_included blocks that specify the -nocache switch as part of the ns_adp_include command. The use of -cache and -nocache can be used to increase performance of ADP used to generated a mix of personalized, non-cacheable, content and shared content which changes more slowly. Under high load, the performance improvement can be substaintial, especially in cases where the cached content is the result of accessing a slow databases or web services. See the EXAMPLES section for an example of using cached output.
Note that ADP streaming cannot be turned on using ns_adp_stream from within an ADP executed with the ns_adp_include command.
ADPs can be nested by including each other up to the maximum of 256 levels deep.
This command is only available from an ADP page or script. Use ns_adp_parse to parse ADPs from outside the context of an ADP.

EXAMPLES

    ###
    ### Example #1: Callee writes the output directly to ADP output buffer, also using passed arguments.
    ###

    # In a.adp:
    <% ns_adp_include b.adp Bob%>

    # In b.adp:
    <% ns_adp_puts "Hello, [ns_adp_argv 1 world]!" %>

    ###
    ### Example #2: Caller writes the adp return value to ADP buffer.
    ###

    # In a.adp:
    <% ns_adp_puts [ns_adp_include b.adp] %>

    # In b.adp:
    <% return "Hello, [ns_adp_argv 1 world]!" %>

    ###
    ### Example #3: The following example demonstrates using the -cache and -nocache options to enhance
    ###             performance through caching execution output. 

    # In top.adp:
    <% ns_adp_include -cache 60 cached.adp %>

    # In cached.adp:
    <%
      ns_adp_puts "Time at cache: [ns_time]"
      ns_adp_include -nocache nocache.adp
    %>

    # In nocache.adp:
    <% ns_adp_puts "Time now: [ns_time]" %>

    # The output of cached.adp will only update once every 60 seconds except for the portion
    # that is the output of nocache.adp, which will be executed on each request,
    # even though it's included within cached.adp.

NOTES

With the new output caching in AOLserver 4.5, there is now a three-tier caching system for adp files - cache of static text blocks, cache of parsed adp scripts and resulting tcl byte-code and cache of execution/output - implemented as follows:
  • Each thread/interpreter maintains a cache of ADP code which includes the result of parsing adp tags and byte-code compiling (but not executing) the resulting tcl code
  • Plus the per-interpreter cache includes pointers to text regions in a shared area (tied to a specific virtual server). When all threads no longer point to the shared text, it's free'd from memory.
  • When enabled, the output cache is simply the replacement of what would have been per-interp byte code blocks with pointers to combined runs of text. The output cache is shared.
  • Files on disk are checked on each request, whether output caching is enabled or not, via a stat call. On Unix the key in the cache is device/inode (which allows the same file pointed by multiple symlinks to be only read once) and on Windows it's the filename.
  • If the file on disk has changed, byte-code, text regions and output caches are flushed and regenerated.
  • The cache is keyed to both the inode/filename and the adp arguments in the ns_adp_include call.
  • It is not possible to change the time-to-live (ttl) for a cache entry once it is generated - if you have two files that include the same adp with different ttl, the first file to be accessed will determine the ttl. -cache 0 will still use the previously cached output if the previously set ttl hasn't expired (it might be helpful if a value of 0 would actually flush the cache without recreating it, so that database-change-triggered code could invalidate the cache without having to know how long it should be cached for again). If you omit -cache or use -nocache, then the previously cached output is not used (it might be helpful to support a value of -1 to mean the same as omitting -cache)
  • You can force a given request to ignore all cache directives and execute all includes with ns_adp_ctl cache 0 (or ns_adp_ctl nocache 1 in NaviServer).
Since ns_adp_include adp caching is rather useful outside of adp pages as well, the following wrapper procedure can be used both in an adp and outside of one to include an adp file with output caching
    proc am_adp_include {args} {
    #
    # Last Modified:    2010-06-13
    # Last Modified By: Alex Hisen
    # Original Author:  Alex Nisenboim
    #
    # Usage :  am_adp_include ?-cache ttl | -nocache? adpfile ?arg1? ?arg2? ...
    #        
    # Synopis: Works like ns_adp_include, but can be called outside of an ADP. Also there is 
    #          a new option for ttl parameter that could be convenient (see below).
    #          This proc automatically determines whether it's being executed inside an ADP
    #          and if so, it works as a drop-in replacement for ns_adp_include - i.e. it
    #          returns the return value of the adp file and writes the parsed result to the adp buffer.
    #          If executed outside of an ADP, the return value is discarded and the
    #          parsed result is returned.
    # 
    # Input  : 
    #          ?-cache ttl | -nocache?   -  optional switch. Opting for -cache will cause using the cached 
    #                                       value unless it is older then ttl. Note that providing ttl == -1 
    #                                       effectively means -nocache,  but otherwise ttl must be positive 
    #                                       integer, just like in ns_adp_include. If cache is disabled for 
    #                                       duration of the current connection (with am_adp_disableCache),
    #                                       the specified -cache value will be ignored.
    #
    #          adpfile                   -  mandatory parameter which is the ADP filename. 
    #                                       It could have absolute or relative path. If 
    #                                       called from an ADP  it is assumed to be relative to 
    #                                       the adp current working directory.
    #                                       If called not from an ADP and has a relative or volumerelative 
    #                                       path then adpfile is assumed to be relative to the  
    #                                       pageroot i.e. the output of ns_url2file command. 
    #         
    #          ?arg1? ?arg2? ...         -  optional parameters that are to be passed to the ADP.             
    #      
    #
    
        
        # manually parse args for improved performance 
        set nargs [llength $args]       
        if { $nargs == 0 } {
            error "wrong # args: should be \"am_adp_include ?-cache ttl | -nocache? adpfile ?arg1? ?arg2? ...  \"" "" ""
        } else {
            if {[string match "-cache*" $args]} {
                set inputSwitch "-cache"
                set ttl [lindex $args 1]
                if {[string equal "-1" $ttl]} {
                    set inputSwitch "-nocache"
                    set ttl ""
                }
                set filename [lindex $args 2]
                if {[string equal "" $filename]} {
                    error "wrong # args:  should be \"am_adp_include ?-cache ttl | -nocache? adpfile ?arg1? ?arg2? ... \"" "" ""
                } else {
                    set adpfile [am_normalizeFileName $filename] 
                }
                set adpargs [lrange $args 3 end] 
            } elseif {[string match "-nocache*" $args]} {
                set inputSwitch "-nocache"
                set adpfile [am_normalizeFileName [lindex $args 1]] 
                set adpargs [lrange $args 2 end] 
                set ttl ""
            } else {
                set inputSwitch ""
                set adpfile [am_normalizeFileName [lindex $args 0]] 
                set adpargs [lrange $args 1 end]
                set ttl ""
            }
        }
        
        set parsedResult [ns_adp_parse -savedresult returnValue -string "<% ns_adp_include $inputSwitch $ttl [list $adpfile] $adpargs %>"]
        if {![catch {ns_adp_argc}]} {
            #meaning we are in an ADP
            ns_adp_puts -nonewline $parsedResult
            return $returnValue
        }
        return $parsedResult
    }

    proc am_normalizeFileName {filename} {
    #
    # Last Modified:    2009-09-15
    # Last Modified By: Alex Nisenboim
    # Original Author:  Alex Nisenboim
    # 
    # Usage  :  am_normalizeFileName $filename 
    #
    # Synopis: 
    #       If filename has an absolute path then we just normalize it.
    #       If am_normalizeFileName is called from an ADP then the filename  
    #       is expected to be relative to adp current working directory. 
    #       Otherwise (called not from an ADP) and the filename does not
    #       have an absolue path the command acts like "file normalize" 
    #       with 2 differences:
    #           1. Absolute path is created by making the filename relative 
    #              to the pageroot directory rather then to the home one.        
    #           2. Volumerelative path is also transformed into absolute one
    #              by making them relative to the pageroot. 
    #
    #       Filename with an absolute and normalized path is returned.
    #
    # Note: 
    #       This proc was originally meant to mimic the following piece of code of 
    #          AdpRun function in adpeval.c:
    #           /*
    #            * Construct the full, normalized path to the ADP file.
    #            */
    #
    #            if (Ns_PathIsAbsolute(file)) {
    #                 Ns_NormalizePath(&path, file);
    #            } else {
    #                 Ns_MakePath(&tmp, itPtr->adp.cwd, file, NULL);
    #                 Ns_NormalizePath(&path, tmp.string);
    #                 Ns_DStringTrunc(&tmp, 0);
    #            }
    #        but it evolved into this more elaborate version. 
    
    
        set normalizedFilename "" 
        set pathtype [file pathtype $filename]
        
        switch -exact -- $pathtype {
        
            absolute       {   
                               set normalizedFilename [file normalize $filename]                                                              
                           } 
            relative       { 
                               # This mimics the value of adp.cwd in the tcl interp
                               # structure. If we are inside an ADP then ns_adp_dir will 
                               # return it. Otherwise it returns [ns_info pageroot]  
                               # in AOLserver 4.5, "/" in AOLserver 4.0 or throws an error
                               # in earlier versions.    
                               if {[catch {set adp_cwd [ns_adp_dir]}] || [string equal "/" $adp_cwd] || [string equal [ns_info pageroot] $adp_cwd]} {
                                   # This means we are not in ADP.
                                   # Using ns_url2file to normalize the filename.
                                   set normalizedFilename [ns_url2file $filename]
                               } else {
                                   # This means we are inside ADP and cwd is available.
                                   # In this case we join the current adp working directory 
                                   # path and the filename and then normalize it.
                                   set normalizedFilename [file normalize [file join $adp_cwd $filename]]
                               }
                           }
            volumerelative {
                               set normalizedFilename [ns_url2file $filename]
                           } 
        }
        
        # This is to mimic char *Ns_NormalizePath(Ns_DString *dsPtr, char *path)
        # function in pathname.c. Relevant only under Windows platform and
        # should not matter under Linux.
        return [string tolower $normalizedFilename 0 0]
    }

SEE ALSO

ns_adp_abort, ns_adp_append, ns_adp_argc, ns_adp_argv, ns_adp_bind_args, ns_adp_break, ns_adp_debug, ns_adp_debuginit, ns_adp_dir, ns_adp_dump, ns_adp_eval, ns_adp_exception, ns_adp_mime, ns_adp_mimetype, ns_adp_parse, ns_adp_puts, ns_adp_registeradp, ns_adp_registerproc, ns_adp_registertag, ns_adp_return, ns_adp_safeeval, ns_adp_stats, ns_adp_stream, ns_adp_tell, ns_adp_trunc