# = Handlers # # code: gmosx # # (c) 2002-2003 Navel, all rights reserved. # $Id: handlers.rb 71 2004-10-18 10:50:22Z gmosx $ require "n/utils/cache" require "n/server/filter" module N; module App # = App server handlers handle requests to specific resources. # # === Design: # # Handlers are NOT singleton classes. This way we can assign one handler # class to multiple resources, and keep statistics and metrics for # each resource. # class Handler < N::ServerFilter def process(request) # nop # walk the filter pipeline @next_filter.process(request) if @next_filter end #--------------------------------------------------------------------- # Testing/Metrics support methods end # class # Handler Error. # raise this if an error happens when handling a request class HandlerError < StandardError; end # = Script Handler # # Base handler for scripts. class ScriptHandler < Handler # cache the compiled page scripts to optimize future references. # use a thread safe cache. @@compiled_script_cache = N::SafeHash.new() # dont allow 2 threads to compile the same script. In fact dont allow # two threads to compile in parallel. @@compile_sync = Sync.new # Overload the path. # FIXME: better name and much better documentation. # def overload_path(path) path.gsub!(/\/\//, '/') if ::File.exists?("#$root_dir/#{path}") return path else $log.debug "OVERLOAD: '#{path}' -> 'p/#{path}'" if $DBG return "p/#{path}" end end # the compiler returns a singleton class customized for rendering the # input script. The original idea was to define render() as a static # method and return the class, but we will use a singleton object to # keep custom data structures (sub-page-graph, metrics, etc) # # script_path is used as key in the Dynamic class creation and for # caching # # === Design: # we use __ for out too to avoid nasty collisions. # def compile_script(script) compiled_script = nil # dont allow 2 threads to compile the same script. In fact dont # allow two threads to compile in parallel. # gmosx: SOS this eval assigns the variable compiled_script! @@compile_sync.synchronize { eval(script) } return compiled_script end def compiled_script_cache return @@compiled_script_cache end # Log a rendering error # def log_error(request, ex) request.log_error "--------" request.log_error "#{request.path}:" request.log_error "#{ex.class}: #{ex}" request.log_error ex.backtrace() raise ScriptHandlerError.new(0, "error") end end # Handler Error. # raise this if an error happens when handling a request class ScriptHandlerError < HandlerError attr_reader :error_line def initialize(error_line, message = nil) @error_line, @message = error_line, message end end end; end # module