App-Context

 view release on metacpan or  search on metacpan

lib/App/Context.pm  view on Meta::CPAN


    if ($App::DEBUG >= 2) {
        my (@str, $key);
        push(@str,"Context->new(): conf=$conf_class\n");
        foreach $key (sort keys %options) {
            push(@str, "   $key => $options{$key}\n");
        }
        $self->dbgprint(join("",@str));
    }

    ##############################################################
    # initialize conf
    ##############################################################
    my $conf = {};

    eval {

        # Initialize from "app.pl" or other file/source specified by the class
        $conf = App->new($conf_class, "new", \%options);

        # Override any values which are supplied in "app.conf" (the "deployment descriptor")
        foreach my $var (keys %options) {
            if ($var =~ /^app\.(.+)/) {
                $conf->set($1, $options{$var});
            }
        }
    };
    $self->add_message($@) if ($@);

    $self->{conf} = $conf;

    ##############################################################
    # Include and Overlay $conf with additional files
    ##############################################################
    my ($includes);
    $includes = $conf->{global}{include} if ($conf->{global});
    if ($includes && ref($includes) eq "ARRAY") {
        my $options = $self->{options};
        my $prefix  = $options->{prefix};
        my (@include_files, $cond, $include_files, $matches);
        for (my $i = 0; $i <= $#$includes; $i += 2) {
            $cond = $includes->[$i];
            $include_files = $includes->[$i+1];
            $matches = $self->cond_matches_options($cond, $options);
            if ($matches) {
                if (ref($include_files) eq "ARRAY") {
                    @include_files = @$include_files;
                }
                elsif (ref($include_files) eq "") {
                    @include_files = ( $include_files );
                }
                foreach my $conf_file (@include_files) {
                    $conf_file = "$prefix/etc/app/$conf_file" if ($conf_file !~ m!^/!);
                    if ($self->{conf_included}{$conf_file}) {
                        print STDERR "Conf global include: [$cond][$conf_file] already included\n" if ($options{debug_conf});
                        next;
                    }
                    if (-r $conf_file) {
                        $options{conf_file} = $conf_file;
                        my $aux_conf = $conf_class->create({ %options });
                        $conf->overlay($aux_conf);
                        print STDERR "Conf global include: [$cond][$conf_file] included (overlayed)\n" if ($options{debug_conf});
                    }
                    else {
                        print STDERR "Conf global include: [$cond][$conf_file] not readable\n" if ($options{debug_conf});
                    }
                    $self->{conf_included}{$conf_file} = 1;
                }
            }
            print STDERR "Conf global include: [$cond] did not match options\n" if (!$matches && $options{debug_conf});
        }
    }

    ##############################################################
    # misc
    ##############################################################
    if (defined $options{debug_conf} && $options{debug_conf} >= 2) {
        $self->dbgprint($self->{conf}->dump());
    }

    $self->{events} = [];      # the event queue starts empty
    $self->{returntype} = "default";  # assume default return type

    $self->{scheduled_events} = [];
    $self->{scheduled_event} = {};

    $self->{event_loop_extensions} = [];

    $self->_init(\%options);   # allows the subclass to do initialization

    $self->set_current_session("default");

    if ($options{authentication_class}) {
        $self->authentication("default", class => $options{authentication_class});
    }

    &App::sub_exit($self) if ($App::trace);
    return $self;
}

sub _default_session_class {
    &App::sub_entry if ($App::trace);
    &App::sub_exit("App::Session") if ($App::trace);
    return("App::Session");
}

# NOTE: This is very similar logic to some logic in App::Options to see if sections
#       of app.conf are active.
sub cond_matches_options {
    &App::sub_entry if ($App::trace);
    my ($self, $cond_str, $options) = @_;
    my ($var, $value, $regexp, $cond, $cond_value);
    my $matches = 1;                      # assume the condition matches
    my @cond = split(/;/,$cond_str);      # separate the conditions that must be satisfied
    foreach $cond (@cond) {  # check each condition
        if ($cond =~ /^([^=]+)=(.*)$/) {  # i.e. city=ATL or name=/[Ss]tephen/
            $var = $1;
            $cond_value = $2;
        }
        else {              # i.e. [go] matches the program (app) named "go"
            $var = "app";
            $cond_value = $cond;

lib/App/Context.pm  view on Meta::CPAN


  2. optional conf of the service's service_type (in Conf)
     i.e. $conf->{RepositoryType}{$repository_type}

  3. named parameters to the service() call

All service configuration happens before instantiation
this allows you to override the "service_class" in the configuration
in time for instantiation

=cut

sub service {
    &App::sub_entry if ($App::trace);
    my ($self, $type, $name, %named) = @_;
    $self->dbgprint("Context->service(" . join(", ",@_) . ")")
        if ($App::DEBUG && $self->dbg(3));
    my $options = $self->{options};

    my ($args, $new_service, $override, $lightweight, $attrib);
    my ($service, $conf, $class, $session);
    my ($service_store, $service_conf, $service_type, $service_type_conf);
    my ($default);

    # $type (i.e. SessionObject, Session, etc.) must be supplied
    if (!defined $type) {
        App::Exception->throw(
            error => "cannot create a service of unknown type\n",
        );
    }

    if (%named) {
        $args = \%named;
    }
    else {
        $args = {};
    }

    if (! defined $name || $name eq "") {    # we need a name!
        $name = "default";
    }

    $session = $self->{session};
    $service = $session->{cache}{$type}{$name};  # check the cache
    $conf = $self->{conf};
    $service_conf = $conf->{$type}{$name};
    my $temporary = ($name eq "temporary") || $args->{temporary};
    my $service_initialized = ($service && ref($service) ne "HASH");
    #print "$type($name): SERVICE=$service INIT=$service_initialized\n";

    ##############################################################
    # Load extra conf on demand
    ##############################################################
    if (!$service_initialized && !$service_conf && $name !~ /-/) {   # if it's not a contained widget, try the file system
        my $prefix = $options->{prefix};
        my $conf_type = $options->{conf_type} || "pl";
        my $conf_file = "$prefix/etc/app/$type.$name.$conf_type";
        if (!$self->{conf_included}{$conf_file} && -r $conf_file) {
            $options->{conf_file} = $conf_file;
            my $aux_conf = App::Conf::File->create({ %$options });
            $conf->overlay($aux_conf);
            $service_conf = $conf->{$type}{$name};
        }
        $self->{conf_included}{$conf_file} = 1;
    }

    ##############################################################
    # conf includes
    ##############################################################
    if (!$service_initialized && $service_conf && $service_conf->{include}) {
        my $prefix = $options->{prefix};
        my (@include_files);
        my $include_files = $service_conf->{include};
        if (ref($include_files) eq "ARRAY") {
            @include_files = @$include_files;
        }
        elsif (ref($include_files) eq "") {
            @include_files = ( $include_files );
        }
        foreach my $conf_file (@include_files) {
            $conf_file = "$prefix/etc/app/$conf_file" if ($conf_file !~ m!^/!);
            next if ($self->{conf_included}{$conf_file});
            if (-r $conf_file) {
                $options->{conf_file} = $conf_file;
                my $aux_conf = App::Conf::File->create({ %$options });
                $conf->overlay($aux_conf);
            }
            $self->{conf_included}{$conf_file} = 1;
        }
    }

    ##############################################################
    # Detect Deprecated Services
    ##############################################################
    if (!$service_initialized && $service_conf) {
        if ($service_conf->{deprecated}) {
            my $message_suffix = $service_conf->{deprecated};
            my $message = "WARNING: $type($name) deprecated";
            $message .= ": $message_suffix" if ($message_suffix ne "1");
            my $deprecated_action = $options->{"app.Context.deprecated_action"};
            if (!$deprecated_action || $deprecated_action eq "none") {
                # do nothing
            }
            elsif ($deprecated_action eq "die") {
                confess $message;
            }
            else {
                $self->log(shortmess($message));
            }
        }
    }

    ##############################################################
    # aliases
    ##############################################################
    if (!$service_initialized && $service_conf) {
        my $alias = $service_conf->{alias};
        if ($alias && $alias ne $name) {
            $service = $session->{cache}{$type}{$alias};
	    $service = $self->service($type, $alias) if (!$service);
            $service_conf = $conf->{$type}{$alias};
            $name = $alias;
        }
        elsif ($type ne "Authorization" && ($service_conf->{clone} || $service_conf->{auth_clone})) {
            my $clone = $self->get_auth_attrib_value($service_conf, $type, $name, "clone");
            if ($clone) {
                $service_conf = $conf->{$type}{$clone};
            }
        }
    }

    $new_service = 0;

    #   NEVER DEFINED     OR   NON-BLESSED HASH (fully defined services are blessed into classes)
    if ($temporary || !defined $service || ref($service) eq "HASH") {
        $service = {} if (!defined $service);  # start with new hash ref
        $service->{name} = $name;
        $service->{context} = $self;

        $service_store = $session->{store}{$type}{$name};
        if ($temporary) {
            $service_store = undef;
            $service->{temporary} = 1;
        }

        if ($App::DEBUG && $self->dbg(6)) {
            $self->dbgprint("Context->service(): new service. conf=$conf svc=$service sconf=$service_conf sstore=$service_store");
            $self->dbgprint("Context->service():              sconf={",join(",",%$service_conf),"}") if ($service_conf);
            $self->dbgprint("Context->service():              sstore={",join(",",%$service_store),"}") if ($service_store);
        }
    
        $new_service = 1;

        ################################################################
        # start with runtime store for the service from the session
        ################################################################
        if ($service_store) {
            foreach $attrib (keys %$service_store) {
                if (!defined $service->{$attrib}) {
                    $service->{$attrib} = $service_store->{$attrib};
                }
            }
        }

        ################################################################
        # overlay with attributes from the conf file
        ################################################################
        if ($service_conf) {
            foreach $attrib (keys %$service_conf) {
                # include conf attributes only if not set already
                if (!defined $service->{$attrib}) {
                    $service->{$attrib} = $service_conf->{$attrib};
                }
            }
        }

        ################################################################
        # overlay with attributes from the "service_type"
        ################################################################
        $service_type = $service->{type}; # i.e. "session_object_type"
        if ($service_type) {
            $service_type_conf = $conf->{"${type}Type"}{$service_type};
            if ($service_type_conf) {
                foreach $attrib (keys %$service_type_conf) {
                    # include service_type confs only if not set already
                    if (!defined $service->{$attrib}) {
                        $service->{$attrib} = $service_type_conf->{$attrib};
                    }
                }
            }
        }
    }

    ################################################################
    # take care of all %$args attributes next
    ################################################################

    # A "lightweight" service is one which never stores its attributes in
    # the session store.  It assumes that all necessary attributes will
    # be supplied by the conf or by the code.  As a result, a "lightweight"
    # service can usually never handle events.
    #   1. its attributes are only ever required when they are all supplied
    #   2. its attributes will be OK by combining the %$args with the %$conf
    # This all saves space in the Session store, as the attribute values can
    # be relied upon to be supplied by the conf file and the code (and
    # minimal reliance on the Session store).
    # This is really handy when you have something like a huge spreadsheet
    # of text entry cells (usually an indexed variable).

    if ($temporary) {                            # may be specified implicitly
        $lightweight = 1;
    }
    elsif (defined $args->{lightweight}) {       # may be specified explicitly
        $lightweight = $args->{lightweight};
    }
    else {
        $lightweight = ($name =~ /[\{\}\[\]]/);  # or implicitly for indexed variables
    }
    $override = $args->{override};

    if ($new_service || $override) {
        foreach $attrib (keys %$args) {
            # don't include the entry which says whether we are overriding or not
            next if ($attrib eq "override");

            # include attrib if overriding OR attrib not provided in the session_object confs already
            if (!defined $service->{$attrib} ||
                ($override && $service->{$attrib} ne $args->{$attrib})) {
                $service->{$attrib} = $args->{$attrib};
                $session->{store}{$type}{$name}{$attrib} = $args->{$attrib} if (!$lightweight);
            }
            $self->dbgprint("Context->service() [arg=$attrib] name=$name lw=$lightweight ovr=$override",
                " service=", $service->{$attrib},
                " service_store=", $service_store->{$attrib},
                " args=", $args->{$attrib})
                if ($App::DEBUG && $self->dbg(6));
        }
    }



( run in 1.074 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )