[Saga-devel] Context question

Hartmut Kaiser hkaiser at cct.lsu.edu
Wed Jan 21 07:59:19 CST 2009


Paul,

> This is a fairly open question to those in the know.
> 
> An adaptor we're writing is going to need a specialized context class.
> As far as I can tell writing a new context is easy enough as what we
> need to do is not too difficult.
> The bit that I'm not sure about is how I get my new context used, i.e.
> only in my one specific adaptor.
> What's the procedure for this?
> 
> I'll try to explain the problem with an example.  The SD has two
> constructors, one takes a session and one doesn't.
> For the constructor that doesn't take a session it create a default
> session.
> One adaptor needs to create a default session with a context in it that
> contains certain adaptor specific information, based on the user, the
> rest can just use the standard default session and standard context
> class.
> So how do I make sure that our special adaptor always gets the session
> and context that it expects?

You don't need to implement a new saga::context, all you need to do is to
write a context CPI (adaptor). This is fairly lightweight. Look at the
default advert adaptor, for instance (context.hpp/context.cpp). Basically,
you need to implement several things:

1) Come up with a unique context type, here: "default_advert_db", document
that and all other specific attributes of your context for your users.

2) implement the constructor of your context CPI. This needs to check for
the context type you're implementing:

context_cpi_impl::context_cpi_impl (proxy* p, cpi_info const& info,
        saga::ini::ini const& glob_ini, saga::ini::ini const& adap_ini,
        TR1::shared_ptr<saga::adaptor> adaptor)
  : base_cpi (p, info, adaptor, cpi::Noflags)
{
    saga::adaptors::attribute attr(this);
    if (attr.attribute_exists(saga::attributes::context_type) &&
        "default_advert_db" !=
attr.get_attribute(saga::attributes::context_type))
    {
        SAGA_OSSTREAM strm;
        strm << "Can't handle context types others than 'default_advert_db'
"
             << "(got: " <<
attr.get_attribute(saga::attributes::context_type) 
             << ")";
        SAGA_ADAPTOR_THROW(SAGA_OSSTREAM_GETSTRING(strm),
saga::BadParameter);
    }
}

3) implement the sync_set_defaults function in your CPI. This needs to check
for the correct context type again and additionally complement any existing
information in the context by setting any missing entries to sensible
default values:

void context_cpi_impl::sync_set_defaults(saga::impl::void_t&)
{
    saga::adaptors::attribute attr(this);
    if (attr.attribute_exists(saga::attributes::context_type))
    {
        if ("default_advert_db" !=
attr.get_attribute(saga::attributes::context_type))
        {
            SAGA_OSSTREAM strm;
            strm << "Can't handle context types others than
'default_advert_db' "
                 << "(got: " <<
attr.get_attribute(saga::attributes::context_type) 
                 << ")";
            SAGA_ADAPTOR_THROW(SAGA_OSSTREAM_GETSTRING(strm),
saga::BadParameter);
        }

        if (!attr.attribute_exists(saga::attributes::context_userid))
            attr.set_attribute(saga::attributes::context_userid, "SAGA");
        if (!attr.attribute_exists(saga::attributes::context_userpass))
            attr.set_attribute(saga::attributes::context_userpass,
"SAGA_client");
    }
}

4) Create a proto-context of your type in the constructor of the adaptor
instance (not the CPI!), see default_advert_adaptor.cpp. This has to be done
only if the session is the default one (only default sessions are filled
with default contexts). Use sensible defaults for all attributes:

    // create a default security context, if needed
    if (s->is_default_session())
    {
        typedef std::pair<std::string, std::string> entry_type;
        using namespace boost::assign;
        std::vector<entry_type> entries;

        entries += 
            entry_type(saga::attributes::context_type, "default_advert_db"),
            entry_type(saga::attributes::context_userid, "SAGA"),
            entry_type(saga::attributes::context_userpass, "SAGA_client")
        ;
        s->add_proto_context(entries);
    }

That's it. All what's left now is in your adaptor to check for your context
in the current session when you need the related information:

    std::vector<saga::context> ctxs(s.list_contexts());
    std::vector<saga::context>::iterator end = ctxs.end();
    for (std::vector<saga::context>::iterator it = ctxs.begin(); it != end;
++it) 
    {
        if ((*it).attribute_exists("saga::attributes::context_type") && 
            "default_advert_db" ==
(*it).get_attribute(saga::attributes::context_type))
        {
            ...= (*it).get_attribute(saga::attributes::context_userid));
            ...= (*it).get_attribute(saga::attributes::context_userpass));
            break;
        }
    }

Users will have to create a new context using your type, filling in their
attributes, and adding this to the sessions object used to create your API
object:

    saga::context ctx("default_advert_db");
    ctx.set_attribute(saga::attributes::context_userid, "...");
    ctx.set_attribute(saga::attributes::context_userpass, "...");

    saga::session s;
    s.add_context(ctx);

    saga::advert::entry adv(s, ...);

HTH
Regards Hartmut





More information about the saga-devel mailing list