SPOPS::LDAP::MultiDatasource -- SPOPS::LDAP functionality but fetching objects from multiple datasources
# In your configuration my $config = { class => 'My::LDAPThings', datasource => [ 'main', 'secondary', 'tertiary' ], isa => [ ... 'SPOPS::LDAP::MultiDatasource' ], ..., }; # Fetch an object and see where it came from my $object = My::LDAPThings->fetch( 'superuser' ); print "My DN is ", $object->dn, " and I came from $object->{_datasource}";
This class extends SPOPS::LDAP with one purpose: be able to fetch objects from multiple datasources. This can happen when you have got objects dispersed among multiple directories -- for instance, your 'Accounting' department is on one LDAP server and your 'Development' department on another. One class can (more or less -- see below) link the two LDAP servers.
Every object is tagged with the datasource it came from (in the _datasource property, if you ever need it), and any calls to save() or remove() will use this datasource to retrieve the proper connection for the object.
_datasource
save()
remove()
The fetch() method is the only functional method overridden from SPOPS::LDAP. The fetch_group() or fetch_iterator() methods will only use the first datasource in the listing, whatever datasource you pass in with the parameter 'connect_key' or whatever LDAP connection handle you pass in with the parameter 'ldap'. If you want to retrieve objects from multiple datasources using the same filter, use the fetch_group_all() method.
fetch()
fetch_group()
fetch_iterator()
fetch_group_all()
The fetch_iterator() method is not supported at all for multiple datasources -- use fetch_group_all() in conjunction with SPOPS::Iterator::WrapList if your implementation expects an SPOPS::Iterator object.
There are a number of items to configure and setup to use this class. Please see SPOPS::Manual::Configuration for the configuration keys used by this module.
connection_info( $connect_key )
This method should look at the $connect_key and return a hashref of information used to connect to the LDAP directory. Keys (hopefully self-explanatory) should be:
$connect_key
host ($)
base_dn ($)
Other keys are optional and can be used in conjunction with a connection/resource manager (example below).
port ($) (optional, default is '389')
bind_dn ($) (optional, will use anonymous bind without)
bind_password ($) (optional, only used if 'bind_dn' specified)
For example:
package My::ConnectionManage; use strict; my $connections = { main => { host => 'localhost', base_dn => 'dc=MyCompanyEast,dc=com' }, accounting => { host => 'accounting.mycompany.com', base_dn => 'dc=MyCompanyWest,dc=com' }, development => { host => 'dev.mycompany.com', base_dn => 'dc=MyCompanyNorth,dc=com' }, etc => { host => 'etc.mycompany.com', base_dn => 'dc=MyCompanyBranch,dc=com' }, }; sub connection_info { my ( $class, $connect_key ) = @_; return \%{ $connections->{ $connect_key } }; }
Then put this class into the 'isa' for your SPOPS class:
my $spops = { class => 'My::Person', isa => [ 'My::ConnectionManage', 'SPOPS::LDAP::MultiDatasource' ], };
global_datasource_handle( $connect_key )
You will need an implementation that deals with multiple configurations. For example:
package My::DSManage; use strict; use Net::LDAP; my %DS = (); sub global_datasource_handle { my ( $class, $connect_key ) = @_; unless ( $connect_key ) { SPOPS::Exception->throw( "Cannot retrieve handle without connect key" ); } unless ( $DS{ $connect_key } ) { my $ldap_info = $class->connection_info( $connect_key ); $ldap_info->{port} ||= 389; my $ldap = Net::LDAP->new( $ldap_info->{host}, port => $ldap_info->{port} ); unless ( $ldap ) { SPOPS::Exception->throw( "Cannot create LDAP connection: $@" ); } my ( %bind_params ); if ( $ldap_info->{bind_dn} ) { $bind_params{dn} = $ldap_info->{bind_dn}; $bind_params{password} = $ldap_info->{bind_password}; } my $bind_msg = $ldap->bind( %bind_params ); if ( $bind_msg->code ) { SPOPS::Exception::LDAP->throw( "Cannot bind to directory: " . $bind_msg->error, { code => $bind_msg->code, action => 'global_datasource_handle' } ); $DS{ $connect_key } = $ldap; } return $DS{ $connect_key }; }
my $spops = { class => 'My::Person', isa => [ 'My::DSManage', 'SPOPS::LDAP::MultiDatasource' ], };
Someone with a thinking cap on might put the previous two items in the same class :-)
fetch( $id, \%params )
Given the normal parameters for fetch(), tries to retrieve an object matching either the $id or the 'filter' specified in \%params from one of the datasources. When it finds an object it is immediately returned.
$id
\%params
If you pass in the key 'ldap' in \%params, this functions as the fetch() does in SPOPS::LDAP and multiple datasources are not used.
Returns: SPOPS object (if found), or undef.
fetch_group_all( \%params )
Given the normal parameters for fetch_group(), retrieves all objects matching the parameters from all datasources. Use with caution.
Returns: Arrayref of SPOPS objects.
save( \%params )
Just pass along the right handle to the actual save() method in SPOPS::LDAP.
remove( \%params )
Just pass along the right handle to the actual remove() method in SPOPS::LDAP.
base_dn( $connect_key )
Returns the full base DN associated with $connect_key.
get_partial_dn( $connect_key )
Retrieves the partial base DN associated with $connect_key.
get_connect_key()
If called, returns either the value of the config key 'default_datasource' or the value of the class constant 'DEFAULT_CONNECT_KEY', which is normally 'main'.
None known.
Test some more.
SPOPS::LDAP
Example in SPOPS distribution: eg/ldap_multidatasource.pl
Copyright (c) 2001-2004 MSN Marketing Service Nordwest, GmbH. All rights reserved.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Chris Winters <chris@cwinters.com>
To install SPOPS, copy and paste the appropriate command in to your terminal.
cpanm
cpanm SPOPS
CPAN shell
perl -MCPAN -e shell install SPOPS
For more information on module installation, please visit the detailed CPAN module installation guide.