Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??
Hello all,

I'm currently working on a module called OpenPlugin. It's a plugin manager for web applications. It allows you to make use of a number of plugins, each which can have any number of drivers. For example, the Log plugin has drivers for logging to STDERR, Files, Syslog, etc. The Session plugin has drivers for storing sessions in Files, DBI, etc. Changing drivers is easy, you just change the driver name in a config file.

OpenPlugin even has plugins for params, cookies, httpheaders, and uploads, which have drivers for Apache and CGI. These plugins abstract Apache::Request and CGI.pm, allowing you to build applications that can work seamlessly under mod_perl or CGI. If you want to move your application from one environment to another, you again can just change the driver being used in the config file.

Also in this config file, you can define whether a plugin loads at startup time, or only on demand.

My question though, it's regarding how you feel about it's interface. Currently, to access plugins under OpenPlugin, you use the syntax OpenPluginObject->PluginName->method. For example:
use OpenPlugin(); my $OP = OpenPlugin->new( config => { src => "somefile.conf" } ); $OP->session->fetch( $session_id ); $OP->param->get_incoming( "param_name" ); $OP->httpheader->send_outgoing();
This Obj->Plugin->method syntax was used for several reasons:

  • Simplicity of code

    The above syntax prevents us from saying, every time we want to use a plugin method for the first time:
    # This seems long my $session_obj = OpenPlugin::Session->new(); $session_obj->fetch( $id );
    Instead of all that, we just need to say:
    # This is short! $OP->session->fetch( $id );
    It's then OpenPlugin's job to make sure the plugin and it's driver are properly loaded, and to return an object of that particular plugin. fetch() is then called on that object.

    If you're just opposed to using the arrow operator twice on one line, you could always say:
    $session_obj = $OP->session; $session_obj->fetch();
  • Centralized Management

    As I mentioned, some plugins are not loaded at startup time, they are only loaded when they are accessed. If we know we won't be using 5 out of the currently 10 plugins, why bother loading them?

    With the above Obj->Plugin->method syntax, OpenPlugin receives a method call for Plugin. If Plugin doesn't exist, OpenPlugin can now do everything it wants/needs to in order to load that plugin, and make it available to the calling application.

    Are there other ways to implement this? Sure, we could have the application author load OpenPlugin::Session first, and then call it's new() constructor. I find this undesirable, I don't think the application author should have to worry about if and when to load a plugin. Another way to do it is to make use of Class::Factory (which OpenPlugin already does internally). Class::Factory would allow us to instanciate a new plugin by saying:
    $session_obj = OpenPlugin->new( 'session', $params ); $session_obj->fetch();
    Class::Factory handles loading the plugin. Much better. But it's still an extra line of code than the existing $OP->session->fetch() offers us.

    Just a little more nitty gritty.

    What happens when I call $OP->session->fetch for the first time? Well, if session wasn't loaded at startup, OpenPlugin has no 'session' method. In fact, OpenPlugin knows nothing about it's plugins, aside from a config file it is given with some configuration information in it.

    So, the first time $OP->session is called, AUTOLOAD ends up being called. AUTOLOAD invokes a method to look up the plugin name (session, in this case) in the config file, determine which driver to load, and then load it. OpenPlugin calls the plugin's constructor, and saves that plugin's object internally in a hash. Lastly, it creates a method called "session" in OpenPlugin's namespace. From here on out, whenever an application calls the "session" method, OpenPlugin returns the session object that we stored.

    The relationship of the various plugins and modules is like so:
    OpenPlugin::Plugin (baseclass for all plugins) | OpenPlugin::Session (session plugin, the parent of the session driver) | OpenPlugin::Session::File (session driver)
    Notice that OpenPlugin.pm is not in this heirarchy. OpenPlugin is a standalone class, it had no parents and no children. OpenPlugin simply offers a means of accessing plugins.

    I bring all this up because I'd like opinions on this interface. I had spoken at length with some folks in the chatterbox yesterday, who felt there might be a better way of doing the above. So, I wanted to explain as best I could what all was going on, and to see what the opinions are on this particular interface. I would very much like to make this available on CPAN, so I wanted to straighten this out first :-)

    For those who are interested, my scratchpad contains the full OpenPlugin.pm file, sample config file entries, and sample usage. Also, if you're interested in trying it out on your system, feel free to msg me and I'd be happy to send you an up to date copy of the full distribution.

    I look forward to any comments, ideas, and constructive criticism. Even though it seems longer, would you still prefer to call a new() method on each plugin? Is there something I didn't mention that you would like even better? And if you like it as is, please let me know that too :-) Thanks!

    -Eric

    --
    Lucy: "What happens if you practice the piano for 20 years and then end up not being rich and famous?"
    Schroeder: "The joy is in the playing."

    edited: Wed Oct 2 01:54:38 2002 by jeffa - added <readmore> tag


  • In reply to Request For Comment: Web Application Plugin Manager by andreychek

    Title:
    Use:  <p> text here (a paragraph) </p>
    and:  <code> code here </code>
    to format your post; it's "PerlMonks-approved HTML":



    • Are you posting in the right place? Check out Where do I post X? to know for sure.
    • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
      <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
    • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
    • Want more info? How to link or How to display code and escape characters are good places to start.
    Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Domain Nodelet?
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this?Last hourOther CB clients
    Other Users?
    Others chanting in the Monastery: (6)
    As of 2024-03-29 09:50 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      No recent polls found