File Coverage

blib/lib/Bio/Das.pm
Criterion Covered Total %
statement 230 354 64.9
branch 58 160 36.2
condition 23 79 29.1
subroutine 42 56 75.0
pod 21 34 61.7
total 374 683 54.7


line stmt bran cond sub pod time code
1             package Bio::Das;
2             # $Id: Das.pm,v 1.55 2010/06/29 19:42:48 lstein Exp $
3              
4             # prototype parallel-fetching Das
5              
6 1     1   25013 use strict;
  1         3  
  1         39  
7 1     1   2702 use Bio::Root::Root;
  1         244381  
  1         40  
8 1     1   922 use Bio::DasI;
  1         4785  
  1         56  
9 1     1   1781 use Bio::Das::HTTP::Fetch;
  1         4  
  1         39  
10 1     1   536 use Bio::Das::TypeHandler; # bring in the handler for feature type ontologies
  1         3  
  1         30  
11 1     1   478 use Bio::Das::Request::Dsn; # bring in dsn parser
  1         3  
  1         26  
12 1     1   461 use Bio::Das::Request::Sequences; # bring in sequence parser
  1         3  
  1         30  
13 1     1   499 use Bio::Das::Request::Types; # bring in type parser
  1         3  
  1         27  
14 1     1   5 use Bio::Das::Request::Dnas;
  1         31  
  1         22  
15 1     1   497 use Bio::Das::Request::Features;
  1         3  
  1         31  
16 1     1   615 use Bio::Das::Request::Feature2Segments;
  1         2  
  1         28  
17 1     1   445 use Bio::Das::Request::Entry_points;
  1         2  
  1         37  
18 1     1   468 use Bio::Das::Request::Stylesheet;
  1         3  
  1         27  
19 1     1   413 use Bio::Das::FeatureIterator;
  1         3  
  1         26  
20 1     1   5 use Bio::Das::Util 'rearrange';
  1         2  
  1         36  
21 1     1   5 use Carp;
  1         2  
  1         52  
22              
23 1     1   4 use IO::Socket;
  1         2  
  1         11  
24 1     1   2348 use IO::Select;
  1         1638  
  1         46  
25              
26 1     1   6 use vars '$VERSION';
  1         1  
  1         32  
27 1     1   4 use vars '@ISA';
  1         1  
  1         3714  
28             @ISA = ('Bio::Root::Root','Bio::DasI');
29             $VERSION = '1.17';
30              
31             *feature2segment = *fetch_feature_by_name = \&get_feature_by_name;
32             my @COLORS = qw(cyan blue red yellow green wheat turquoise orange);
33              
34             sub new {
35 3     3 1 2627 my $package = shift;
36              
37             # compatibility with 0.18 API
38 3         7 my ($timeout,$auth_callback,$url,$dsn,$oldstyle_api,$aggregators,$autotypes,$autocategories,$proxy);
39 3         7 my @p = @_;
40              
41 3 50 33     37 if (@p >= 1 && $p[0] =~ /^http/) {
    100          
42 0         0 ($url,$dsn,$aggregators) = @p;
43             } elsif ($p[0] =~ /^-/) { # named arguments
44 2         31 ($url,$dsn,$aggregators,$timeout,$auth_callback,$autotypes,$autocategories,$proxy)
45             = rearrange([['source','server'],
46             'dsn',
47             ['aggregators','aggregator'],
48             'timeout',
49             'auth_callback',
50             'types',
51             'categories',
52             'proxy',
53             ],
54             @p);
55             } else {
56 1         4 ($timeout,$auth_callback) = @p;
57             }
58              
59 3         13 $oldstyle_api = defined $url;
60              
61 3         36 my $self = bless {
62             'sockets' => {}, # map socket to Bio::Das::HTTP::Fetch objects
63             'timeout' => $timeout,
64             default_server => $url,
65             default_dsn => $dsn,
66             oldstyle_api => $oldstyle_api,
67             aggregators => [],
68             autotypes => $autotypes,
69             autocategories => $autocategories,
70             },$package;
71 3 50       11 $self->proxy($proxy) if $proxy;
72 3 50       8 $self->auth_callback($auth_callback) if defined $auth_callback;
73 3 50       9 if ($aggregators) {
74 0 0       0 my @a = ref($aggregators) eq 'ARRAY' ? @$aggregators : $aggregators;
75 0         0 $self->add_aggregator($_) foreach @a;
76             }
77 3         9 return $self;
78             }
79              
80             sub name {
81 0     0 0 0 my $url = shift->default_url;
82             # $url =~ tr/+-//d;
83 0         0 $url;
84             }
85              
86             # holds the last error when using the oldstyle api
87             sub error {
88 0     0 1 0 my $self = shift;
89 0         0 my $d = $self->{error};
90 0 0       0 $self->{error} = shift if @_;
91 0         0 $d;
92             }
93              
94             sub add_aggregator {
95 0     0 1 0 my $self = shift;
96 0         0 my $aggregator = shift;
97 0 0       0 warn "aggregator = $aggregator" if $self->debug;
98              
99 0   0     0 my $list = $self->{aggregators} ||= [];
100 0 0       0 if (ref $aggregator) { # an object
    0          
101 0         0 @$list = grep {$_->get_method ne $aggregator->get_method} @$list;
  0         0  
102 0         0 push @$list,$aggregator;
103             }
104              
105             elsif ($aggregator =~ /^(\w+)\{([^\/\}]+)\/?(.*)\}$/) {
106 0         0 my($agg_name,$subparts,$mainpart) = ($1,$2,$3);
107 0         0 my @subparts = split /,\s*/,$subparts;
108 0         0 my @args = (-method => $agg_name,
109             -sub_parts => \@subparts);
110 0 0       0 push @args,(-main_method => $mainpart) if $mainpart;
111 0         0 require Bio::DB::GFF::Aggregator;
112 0         0 push @$list,Bio::DB::GFF::Aggregator->new(@args);
113             }
114              
115             else {
116 0         0 my $class = "Bio::DB::GFF::Aggregator::\L${aggregator}\E";
117 0         0 eval "require $class";
118 0 0       0 $self->throw("Unable to load $aggregator aggregator: $@") if $@;
119 0         0 push @$list,$class->new();
120             }
121             }
122              
123             sub aggregators {
124 2     2 1 4 my $self = shift;
125 2         4 my $d = $self->{aggregators};
126 2 50       6 if (@_) {
127 0         0 $self->clear_aggregators;
128 0         0 $self->add_aggregator($_) foreach @_;
129             }
130 2 50       5 return unless $d;
131 2         6 return @$d;
132             }
133              
134 0     0 1 0 sub clear_aggregators { shift->{aggregators} = [] }
135              
136             sub default_dsn {
137 10     10 0 18 my $self = shift;
138 10         53 my $d = $self->{default_dsn};
139 10 100       25 if (@_) {
140 2         4 my $new_dsn = shift;
141 2 100       16 $self->{default_dsn} = UNIVERSAL::isa($new_dsn,'Bio::Das::DSN') ?
142             $new_dsn->id : $new_dsn;
143             }
144 10         46 $d;
145             }
146              
147 9     9 0 40 sub default_server { shift->{default_server} }
148              
149 8     8 0 43 sub oldstyle_api { shift->{oldstyle_api} }
150              
151             sub default_url {
152 4     4 0 10 my $self = shift;
153 4 50 33     13 return unless $self->default_server && $self->default_dsn;
154 4         13 return join '/',$self->default_server,$self->default_dsn;
155             }
156              
157             sub auth_callback{
158 0     0 1 0 my $self = shift;
159 0 0       0 if(defined $_[0]){
160 0 0       0 croak "Authentication callback routine to set is not a reference to code"
161             unless ref $_[0] eq "CODE";
162             }
163              
164 0         0 my $d = $self->{auth_callback};
165 0 0       0 $self->{auth_callback} = shift if @_;
166 0         0 $d;
167             }
168              
169             sub no_rfc_warning {
170 6     6 0 11 my $self = shift;
171 6         12 my $d = $self->{no_rfc_warning};
172 6 50       14 $self->{no_rfc_warning} = shift if @_;
173 6         67 $d;
174             }
175              
176             sub proxy {
177 6     6 1 11 my $self = shift;
178 6         13 my $d = $self->{proxy};
179 6 50       18 $self->{proxy} = shift if @_;
180 6         43 $d;
181             }
182              
183             sub timeout {
184 6     6 1 9 my $self = shift;
185 6         15 my $d = $self->{timeout};
186 6 50       19 $self->{timeout} = shift if @_;
187 6         14 $d;
188             }
189              
190             sub debug {
191 6     6 1 10 my $self = shift;
192 6         25 my $d = $self->{debug};
193 6 50       18 $self->{debug} = shift if @_;
194 6         17 $d;
195             }
196              
197             sub make_fetcher {
198 6     6 0 9 my $self = shift;
199 6         11 my $request = shift;
200 6   50     48 return Bio::Das::HTTP::Fetch->new(
201             -request => $request,
202             -headers => {'Accept-encoding' => 'gzip',
203             'Cache-Control' => 'no-cache'},
204             -proxy => $self->proxy || '',
205             -norfcwarn => $self->no_rfc_warning,
206             );
207             }
208              
209             # call with list of base names
210             # will return a list of DSN objects
211             sub dsn {
212 2     2 1 8 my $self = shift;
213 2 50       6 return $self->default_dsn(@_) if $self->oldstyle_api;
214 0         0 return $self->_dsn(@_);
215             }
216              
217             sub _dsn {
218 1     1   3 my $self = shift;
219 1         1 my @dsns;
220 1 50       5 if ($_[0] =~ /^-/) {
221 0         0 my($dsn) = rearrange([['dsn','dsns']],@_);
222 0 0       0 @dsns = ref($dsn) eq 'ARRAY' ? @$dsn : ($dsn);
223             }
224             else {
225 1         3 @dsns = @_;
226             }
227 1         3 my @requests = map { Bio::Das::Request::Dsn->new($_) } @dsns;
  1         17  
228 1         5 $self->run_requests(\@requests);
229             }
230              
231             sub sources {
232 1     1 1 369 my $self = shift;
233 1 50       5 my $default_server = $self->default_server or return;
234 1         4 return $self->_dsn($default_server);
235             }
236              
237             sub entry_points {
238 0     0 1 0 my $self = shift;
239 0         0 my ($dsn,$ref,$callback) = rearrange([['dsn','dsns'],
240             ['ref','refs','refseq','seq_id','name'],
241             'callback',
242             ],@_);
243 0   0     0 $dsn ||= $self->default_url;
244 0 0       0 croak "must provide -dsn argument" unless $dsn;
245 0 0       0 my @dsn = ref $dsn ? @$dsn : $dsn;
246 0         0 my @request;
247 0         0 for my $dsn (@dsn) {
248 0         0 push @request,Bio::Das::Request::Entry_points->new(-dsn => $dsn,
249             -ref => $ref,
250             -callback => $callback);
251             }
252 0         0 $self->run_requests(\@request);
253             }
254              
255             sub stylesheet {
256 1     1 1 498 my $self = shift;
257 1         10 my ($dsn,$callback) = rearrange([['dsn','dsns'],
258             'callback',
259             ],@_);
260 1   33     12 $dsn ||= $self->default_url;
261 1 50       5 croak "must provide -dsn argument" unless $dsn;
262 1 50       7 my @dsn = ref $dsn ? @$dsn : $dsn;
263 1         3 my @request;
264 1         3 for my $dsn (@dsn) {
265 1         26 push @request,Bio::Das::Request::Stylesheet->new(-dsn => $dsn,
266             -callback => $callback);
267             }
268 1         8 $self->run_requests(\@request);
269             }
270              
271              
272             # call with list of DSN objects, and optionally list of segments and categories
273             sub types {
274 1     1 1 3 my $self = shift;
275 1         19 my ($dsn,$segments,$categories,$enumerate,$callback) = rearrange([['dsn','dsns'],
276             ['segment','segments'],
277             ['category','categories'],
278             'enumerate',
279             'callback',
280             ],@_);
281 1   33     14 $dsn ||= $self->default_url;
282 1 50       4 croak "must provide -dsn argument" unless $dsn;
283 1 50 33     8 my @dsn = ref $dsn && ref $dsn eq 'ARRAY' ? @$dsn : $dsn;
284 1         2 my @request;
285 1         3 for my $dsn (@dsn) {
286 1         15 push @request,Bio::Das::Request::Types->new(-dsn => $dsn,
287             -segment => $segments,
288             -categories => $categories,
289             -enumerate =>$enumerate,
290             -callback => $callback,
291             );
292             }
293 1         4 $self->run_requests(\@request);
294             }
295              
296             # call with list of DSN objects, and a list of one or more segments
297             sub sequence {
298 0     0 0 0 my $self = shift;
299 0         0 my ($dsn,$segments,$callback) = rearrange([['dsn','dsns'],
300             ['segment','segments'],
301             'callback',
302             ],@_);
303 0   0     0 $dsn ||= $self->default_url;
304 0 0       0 croak "must provide -dsn argument" unless $dsn;
305 0 0 0     0 my @dsn = ref $dsn && ref $dsn eq 'ARRAY' ? @$dsn : $dsn;
306 0         0 my @request;
307 0         0 for my $dsn (@dsn) {
308 0         0 push @request,Bio::Das::Request::Sequences->new(-dsn => $dsn,
309             -segment => $segments,
310             -callback => $callback);
311             }
312 0         0 $self->run_requests(\@request);
313             }
314              
315             # call with list of DSN objects, and a list of one or more segments
316             sub dna {
317 1     1 1 3 my $self = shift;
318 1         8 my ($dsn,$segments,$callback) = rearrange([['dsn','dsns'],
319             ['segment','segments'],
320             'callback',
321             ],@_);
322 1   33     15 $dsn ||= $self->default_url;
323 1 50       4 croak "must provide -dsn argument" unless $dsn;
324 1 50 33     6 my @dsn = ref $dsn && ref $dsn eq 'ARRAY' ? @$dsn : $dsn;
325 1         2 my @request;
326 1         3 for my $dsn (@dsn) {
327 1         13 push @request,Bio::Das::Request::Dnas->new(-dsn => $dsn,
328             -segment => $segments,
329             -callback => $callback);
330             }
331 1         5 $self->run_requests(\@request);
332             }
333              
334             # 0.18 API - fetch by segment
335             sub segment {
336 2     2 1 1225 my $self = shift;
337 2         22 my ($ref,$start,$stop,$version) = rearrange([['ref','name'],'start',['stop','end'],'version'],@_);
338 2         14 my $dsn = $self->default_url;
339 2 50 33     17 if (defined $start && defined $stop) {
340 2         14 my $segment = Bio::Das::Segment->new($ref,$start,$stop,$version,$self,$dsn);
341 2 50       9 $segment->autotypes($self->{autotypes}) if $self->{autotypes};
342 2 50       9 $segment->autocategories($self->{autocategories}) if $self->{autocategories};
343 2         9 return $segment;
344             } else {
345 0         0 my @segments;
346             my $request = Bio::Das::Request::Features->new(-dsn => $dsn,
347             -das => $self,
348             -segments => $ref,
349             -type => 'NULL',
350             -segment_callback => sub {
351 0     0   0 push @segments,shift;
352 0         0 });
353 0         0 $self->run_requests([$request]);
354 0 0       0 return if @segments == 0;
355 0 0       0 return @segments if wantarray;
356 0 0       0 return $segments[0] if @segments == 1;
357 0         0 $self->error('requested segment has more than one reference sequence in database. Please call in a list context to retrieve them all.');
358 0         0 $self->throw('multiple segment error');
359             }
360             }
361              
362             # 0.18 API - fetch by feature name - returns a set of Bio::Das::Segment objects
363             sub get_feature_by_name {
364 0     0 1 0 my $self = shift;
365 0         0 my ($class, $name, $dsn);
366 0 0       0 if (@_ == 1) {
367 0         0 $name = shift;
368             } else {
369 0         0 ($class, $name, $dsn)
370             = $self->_rearrange([qw(CLASS NAME DSN)],@_);
371             }
372 0   0     0 $dsn ||= $self->default_url;
373 0 0       0 croak "must provide -dsn argument" unless $dsn;
374 0 0 0     0 my @dsn = ref $dsn && ref $dsn eq 'ARRAY' ? @$dsn : $dsn;
375 0         0 my @requests = map { Bio::Das::Request::Feature2Segments->new(-class => $class,
  0         0  
376             -dsn => $_,
377             -feature => $name,
378             -das => $self,
379             )
380             } @dsn;
381 0         0 $self->run_requests(\@requests);
382             }
383              
384             # gbrowse compatibility
385 0     0 1 0 sub refclass { 'Segment' }
386              
387             # call with list of DSNs, and optionally list of segments and categories
388             sub features {
389 2     2 1 12 my $self = shift;
390 2         35 my ($dsn,$segments,$types,$categories,
391             $fcallback,$scallback,$feature_id,$group_id,$iterator,$rangetype,
392             $seqid,$start,$end)
393             = rearrange([['dsn','dsns'],
394             ['segment','segments'],
395             ['type','types'],
396             ['category','categories'],
397             ['callback','feature_callback'],
398             'segment_callback',
399             'feature_id',
400             'group_id',
401             'iterator',
402             'rangetype',
403             'seq_id',
404             'start',
405             'end',
406             ],@_);
407              
408 2   33     13 $dsn ||= $self->default_url;
409 2 50       5 croak "must provide -dsn argument" unless $dsn;
410 2 50 33     10 my @dsn = ref $dsn && ref $dsn eq 'ARRAY' ? @$dsn : $dsn;
411              
412 2   50     8 $rangetype ||= 'overlaps';
413 2 50       8 $self->throw('DAS/1 only supports range queries of type "overlaps"')
414             unless $rangetype eq 'overlaps';
415              
416 2 50 33     7 if (!$segments && $seqid) {
417 0         0 $segments = [$self->segment($seqid,$start,$end)];
418             }
419              
420             # handle types
421 2         3 my @aggregators;
422 2         20 my $typehandler = Bio::Das::TypeHandler->new;
423 2         10 my $typearray = $typehandler->parse_types($types);
424 2         54 my @typearray_sav = @$typearray;
425 2         9 for my $a ($self->aggregators) {
426 0 0       0 unshift @aggregators,$a if $a->disaggregate($typearray,$typehandler);
427             }
428              
429             # change to gbrowse das server requires us to send the aggregator names,
430             # rather than the disaggregated components. We send both.
431 2         6 my %aggregator_methods = map {$_->method => 1} @aggregators;
  0         0  
432 2         3 my @aggregator_types;
433 2         4 for my $type (@typearray_sav) {
434 0 0       0 next unless $aggregator_methods{$type->[0]};
435 0         0 push @aggregator_types,[$type->[0],$type->[1]];
436             }
437              
438 2         4 my %seen;
439 2 0       4 my @types = grep {!$seen{$_}++} map {defined $_->[1] ? "$_->[0]:$_->[1]" : $_->[0]} (@$typearray,@aggregator_types);
  0         0  
  0         0  
440              
441 2         3 my @request;
442 2         4 for my $dsn (@dsn) {
443 2   50     53 push @request,Bio::Das::Request::Features->new(
      50        
      50        
      50        
444             -dsn => $dsn,
445             -segments => $segments,
446             -types => \@types,
447             -categories => $categories,
448             -feature_callback => $fcallback || undef,
449             -segment_callback => $scallback || undef,
450             -das => $self,
451             -feature_id => $feature_id || undef,
452             -group_id => $group_id || undef,
453             );
454             }
455 2         10 my @results = $self->run_requests(\@request);
456 2 100       50 $self->aggregate(\@aggregators,
    50          
457             $results[0]->can('results') ? \@results : [\@results],
458             $typehandler) if @results;
459 2 50       7 return Bio::Das::FeatureIterator->new(\@results) if $iterator;
460 2 100       31 return wantarray ? @results : $results[0];
461             }
462              
463             sub get_seq_stream {
464 0     0 1 0 my $self = shift;
465 0         0 my @args = @_;
466 0         0 return $self->features(@args,-iterator=>1);
467             }
468              
469 0     0 1 0 sub search_notes { }
470              
471             sub aggregate {
472 2     2 0 2 my $self = shift;
473 2         4 my ($aggregators,$featarray,$typehandler) = @_;
474 2         3 my @f;
475              
476 2         4 foreach (@$featarray) {
477 2 100       14 if (ref($_) eq 'ARRAY') { # 0.18 API
    50          
478 1         2 push @f,$_;
479             } elsif ($_->is_success) { # current API
480 1         5 push @f,scalar $_->results;
481             }
482             }
483 2 50       5 return unless @f;
484 2         4 for my $f (@f) {
485 2         5 for my $a (@$aggregators) {
486 0         0 $a->aggregate($f,$typehandler);
487             }
488             }
489             }
490              
491             sub add_pending {
492 6     6 0 10 my $self = shift;
493 6         15 my $fetcher = shift;
494 6         37 $self->{sockets}{$fetcher->socket} = $fetcher;
495             }
496              
497             sub remove_pending {
498 0     0 0 0 my $self = shift;
499 0         0 my $fetcher = shift;
500 0         0 delete $self->{sockets}{$fetcher->socket};
501             }
502              
503             sub run_requests {
504 6     6 0 12 my $self = shift;
505 6         12 my $requests = shift;
506              
507 6         16 for my $request (@$requests) {
508 6 50       22 my $fetcher = $self->make_fetcher($request) or next;
509 6 50       33 $fetcher->debug(1) if $self->debug;
510 6         25 $self->add_pending($fetcher);
511             }
512              
513 6         24 my $timeout = $self->timeout;
514              
515             # create two IO::Select objects to handle writing & reading
516 6         58 my $readers = IO::Select->new;
517 6         75 my $writers = IO::Select->new;
518              
519 6         51 for my $fetcher (values %{$self->{sockets}}) {
  6         26  
520 6         21 my $socket = $fetcher->socket;
521 6         26 $writers->add($socket);
522             }
523              
524 6         297 my $timed_out;
525 6   100     27 while ($readers->count or $writers->count) {
526 126         1436 my ($readable,$writable) = IO::Select->select($readers,$writers,undef,$timeout);
527              
528 126 50 0     3545053 ++$timed_out && last unless $readable || $writable;
      33        
529              
530 126         377 foreach (@$writable) { # handle is ready for writing
531 6         68 my $fetcher = $self->{sockets}{$_}; # recover the HTTP fetcher
532 6         83 my $result = $fetcher->send_request(); # try to send the request
533 6 50       20 if ($result) {
534 6 50       22 if ($result eq 'reading header') { # request is sent, so monitor for reading
535 6         47 $readers->add($_);
536 6         334 $writers->remove($_); # and remove from list monitored for writing
537             }
538             } else { # some sort of error
539 0         0 $fetcher->request->error($fetcher->error()); # copy the error message
540 0         0 $writers->remove($_); # and remove from list monitored for writing
541             }
542             }
543              
544 126         483 foreach (@$readable) { # handle is ready for reading
545 120         567 my $fetcher = $self->{sockets}{$_}; # recover the HTTP object
546 120         5869 my $result = $fetcher->read; # read some data
547 120 0 33     583 if($fetcher->error
      33        
548             && $fetcher->error =~ /^401\s/
549             && $self->auth_callback()) { # Don't give up if given authentication challenge
550             # The result will automatically appear, as fetcher contains request reference
551 0         0 my $new_sock = $self->authenticate($fetcher);
552 0 0       0 if ($new_sock) {
553 0         0 $writers->remove($_);
554 0         0 $readers->remove($_);
555 0         0 $writers->add($new_sock);
556             }
557             }
558 120 100       1305 unless ($result) { # remove if some error occurred
559 6 50       39 $fetcher->request->error($fetcher->error) unless defined $result;
560 6         28 $readers->remove($_);
561 6         1174 delete $self->{sockets}{$_};
562             }
563             }
564             }
565              
566             # handle timeouts
567 6 50       82 if ($timed_out) {
568 0         0 while (my ($sock,$f) = each %{$self->{sockets}}) { # list of still-pending requests
  0         0  
569 0         0 $f->request->error('509 timeout');
570 0         0 $readers->remove($sock);
571 0         0 $writers->remove($sock);
572 0         0 close $sock;
573             }
574             }
575              
576 6         20 delete $self->{sockets};
577 6 100       27 if ($self->oldstyle_api()) {
578 5 50       41 unless ($requests->[0]->is_success) {
579 0         0 $self->error($requests->[0]->error);
580 0         0 return;
581             }
582 5 100       33 return wantarray ? $requests->[0]->results : ($requests->[0]->results)[0];
583             }
584 1 50       8 return wantarray ? @$requests : $requests->[0];
585             }
586              
587             # The callback routine used below for authentication must accept three arguments:
588             # the fetcher object, the realm for authentication, and the iteration
589             # we are on. A return of undef means that we should stop trying this connection (e.g. cancel button
590             # pressed, or x number of iterations tried), otherwise a two element array (not a reference to an array)
591             # should be returned with the username and password in that order.
592             # I assume if you've called autheniticate, it's because you've gotten a 401 error.
593             # Otherwise this does not make sense.
594             # There is also no caching of authentication done. I suggest the callback do this, so
595             # the user isn't asked 20 times for the same name and password.
596              
597             sub authenticate($$$){
598 0     0 0   my ($self, $fetcher) = @_;
599 0           my $callback = $self->auth_callback;
600              
601 0 0         return undef unless defined $callback;
602              
603 0 0         $self->{auth_iter} = {} if not defined $self->{auth_iter};
604              
605 0           my ($realm) = $fetcher->error =~ /^\S+\s+'(.*)'/;
606              
607 0 0         return if $self->{auth_iter}->{$realm} < 0; # Sign that we've given up, don't try again
608              
609 0           my ($user, $pass) = &$callback ($fetcher, $realm, ++($self->{auth_iter}->{$realm}));
610              
611 0 0 0       if(!defined $user or $user eq ''){ #Give up, denote with negative iteration value
612 0           $self->{auth_iter}->{$realm} = -1;
613 0           return;
614             }
615              
616             # Reuse request, adding the authentication info
617 0           my $request = $fetcher->request;
618 0           $self->remove_pending($fetcher);
619              
620             # How do we clean up the old fetcher,which is no longer needed?
621 0           $request->auth($user,$pass);
622 0 0         my $new_fetcher = $self->make_fetcher($request) or return;
623 0           $self->add_pending($new_fetcher);
624 0           return $new_fetcher->socket;
625             }
626              
627             1;
628              
629             __END__
630              
631              
632             =head1 NAME
633              
634             Bio::Das - Interface to Distributed Annotation System
635              
636             =head1 SYNOPSIS
637              
638             use Bio::Das;
639              
640             # SERIAL API
641             my $das = Bio::Das->new(-source => 'http://www.wormbase.org/db/das',
642             -dsn => 'elegans',
643             -aggregators => ['primary_transcript','clone']);
644             my $segment = $das->segment('Chr1');
645             my @features = $segment->features;
646             my $dna = $segment->dna;
647              
648             # PARALLEL API
649             # create a new DAS agent with a timeout of 5 sec
650             my $das = Bio::Das->new(5);
651              
652             # fetch features from wormbase live and development servers spanning two segments on chromosome I
653             my @request = $das->features(-dsn => ['http://www.wormbase.org/db/das/elegans',
654             'http://dev.wormbase.org/db/das/elegans',
655             ],
656             -segment => ['I:1,10000',
657             'I:10000,20000'
658             ]
659             );
660              
661             for my $request (@request) {
662             if ($request->is_success) {
663             print "\nResponse from ",$request->dsn,"\n";
664             my $results = $request->results;
665             for my $segment (keys %$results) {
666             my @features = @{$results->{$segment}};
667             print "\t",join ' ',$segment,@features,"\n";
668             }
669             }
670              
671             else { #error
672             warn $request->dsn,": ",$request->error,"\n";
673             }
674             }
675              
676             # Same thing, but using a callback:
677             $das->features(-dsn => ['http://www.wormbase.org/db/das/elegans',
678             'http://dev.wormbase.org/db/das/elegans',
679             ],
680             -segment => ['I:1,10000',
681             'I:10000,20000'
682             ],
683             -callback => sub { my $feature = shift;
684             my $segment = $feature->segment;
685             my ($start,$end) = ($feature->start,$feature->end);
686             print "$segment => $feature ($start,$end)\n";
687             }
688             );
689              
690              
691             =head1 DESCRIPTION
692              
693             Bio::Das provides access to genome sequencing and annotation databases
694             that export their data in Distributed Annotation System (DAS) format
695             version 1.5. This system is described at http://biodas.org. Both
696             unencrypted (http:) and SSL-encrypted (https:) DAS servers are
697             supported. (To run SSL, you will need IO::Socket::SSL and Net::SSLeay
698             installed).
699              
700             The components of the Bio::Das class hierarchy are:
701              
702             =over 4
703              
704             =item Bio::Das
705              
706             This class performs I/O with the DAS server, and is responsible for
707             generating DAS requests. At any time, multiple requests to different
708             DAS servers can be running simultaneously.
709              
710             =item Bio::Das::Request
711              
712             This class encapsulates a request to a particular DAS server. After
713             execution of the request, the response can be recovered from the
714             object as well. Methods allow you to return the status of the
715             request, the error message if any, and the data results.
716              
717             =item Bio::Das::Segment
718              
719             This encapsulates information about a segment on the genome, and
720             contains information on its start, end and length.
721              
722             =item Bio::Das::Feature
723              
724             This provides information on a particular feature of a
725             Bio::Das::Segment, such as its type, orientation and score.
726              
727             =item Bio::Das::Type
728              
729             This class contains information about a feature's type, and is a
730             holder for an ontology term.
731              
732             =item Bio::Das::DSN
733              
734             This class contains information about a DAS data source.
735              
736             =item Bio::Das::Stylesheet
737              
738             This class contains information about the stylesheet for a DAS source.
739              
740             =back
741              
742             =head2 PARALLEL AND SERIAL APIs
743              
744             Bio::Das supports two distinct APIs. One is a parallel API which
745             allows you to make Das requests on two or more servers simultaneously.
746             This is highly efficient, but the API is slightly more difficult to
747             use. The other is a serial API which supports only a single request
748             on a single service. It is recommended for simple scripts or for
749             those where performance is not at a premium.
750              
751             The two APIs use the same objects. You select which API to use when
752             you create the Das object with Bio::Das->new().
753              
754             =head2 OBJECT CREATION
755              
756             The public Bio::Das constructor is new(). It is used both for the
757             parallel and serial APIs.
758              
759             B<Serial API object construction:>
760              
761             =over 4
762              
763             =item $das = Bio::Das->new(-server => $url, -dsn => $dsn, -aggregators=>\@aggregators);
764              
765             Clients that will be accessing a single server exclusively can
766             indicate that they wish to use the serial APi by passing the
767             B<-server> argument. The argument for B<-server> is the base name of
768             the DAS server (e.g. http://www.wormbase.org/db/das). You may also
769             select the data source to use (e.g. "elegans") by passing the B<-dsn>
770             argument. B<-aggregators> is a list of aggregators as described
771             earlier.
772              
773             The optional B<-proxy> argument will initialize the Bio::Das object
774             with an HTTP or HTTPS proxy (see also the proxy() method below).
775              
776             =item $das = Bio::Das->new('http://das.server/cgi-bin/das',$dsn,$aggregators)
777              
778             Shortcut for the above.
779              
780             =back
781              
782             B<Parallel API object construction:>
783              
784             =over 4
785              
786             =item $das = Bio::Das->new(-timeout => $timeout,
787             -auth_callback => $authentication_callback,
788             -aggregators => \@aggregators)
789              
790             Create a new Bio::Das object, with the indicated timeout and optional
791             callback for authentication. The timeout will be used to decide when
792             a server is not responding and to return a "can't connect" error. Its
793             value is in seconds, and can be fractional (most systems will provide
794             millisecond resolution). The authentication callback will be invoked
795             if the remote server challenges Bio::Das for authentication credentials.
796              
797             Aggregators are used to build multilevel hierarchies out of the raw
798             features in the DAS stream. For a description of aggregators, see
799             L<Bio::DB::GFF>, which uses exactly the same aggregator system as
800             Bio::Das.
801              
802             The optional B<-proxy> argument will initialize the Bio::Das object
803             with an HTTP or HTTPS proxy (see also the proxy() method below).
804              
805             If successful, this method returns a Bio::Das object.
806              
807             =item $das = Bio::Das->new($timeout [,$authentication_callback])
808              
809             Shortcut for the above.
810              
811             =back
812              
813             =head2 ACCESSOR METHODS
814              
815             Once created, the Bio::Das object provides the following accessor methods:
816              
817             =over 4
818              
819             =item $proxy = $das->proxy([$new_proxy])
820              
821             Get or set the proxy to use for accessing indicated servers. Only
822             HTTP and HTTPS proxies are supported at the current time.
823              
824             =item $callback = $das->auth_callback([$new_callback])
825              
826             Get or set the callback to use when authentication is required. See
827             the section "Authentication" for more details.
828              
829             =item $timeout = $das->timeout([$new_timeout])
830              
831             Get or set the timeout for slow servers.
832              
833             =item $error = $das->error
834              
835             Get a string that describes the last error the module encountered whie
836             using the serial API. If you are using the parallel API, then use the
837             request object's error() method to retrieve the error message from the
838             corresponding request.
839              
840             =item $debug = $das->debug([$debug_flag])
841              
842             Get or set a flag that will turn on verbose debugging messages.
843              
844             =item $das->add_aggregator($aggregator)
845              
846             Aggregators allow you to dynamically build up more multipart features
847             from the simple one-part that are returned by Das servers. The
848             concept of aggregation was introduced in the L<Bio::DB::GFF> module,
849             and is completely compatible with the Bio::Das implementation. See
850             L<Bio::DB::GFF> and L<Bio::DB::GFF::Aggregator> for information on how
851             to create and use aggregators.
852              
853             The add_aggregator() method will append an aggregator to the end of
854             the list of registered aggregators. Three different argument types
855             are accepted:
856              
857             1) a Bio::DB::GFF::Aggregator object -- will be added
858             2) a string in the form "aggregator_name{subpart1,subpart2,subpart3/main_method}"
859             -- will be turned into a Bio::DB::GFF::Aggregator object (the /main_method
860             part is optional).
861             3) a valid Perl token -- will be turned into a Bio::DB::GFF::Aggregator
862             subclass, where the token corresponds to the subclass name.
863              
864             =item $das->aggregators([@new_aggregators]);
865              
866             This method will get or set the list of aggregators assigned to
867             the database. If 1 or more arguments are passed, the existing
868             set will be cleared.
869              
870             =item $das->clear_aggregators
871              
872             This method will clear the aggregators stored in the database object.
873             Use aggregators() or add_aggregator() to add some back.
874              
875             =back
876              
877             =head2 DATA FETCHING METHODS - SERIAL API
878              
879             We will document that serial API first, followed by the parallel API.
880             Do not be confused by the fact is that both serial and parallel APIs
881             have the same method names. The behavior of the methods are
882             determined solely by whether the B<-server> argument was provided to
883             Bio::Das->new() during object construction.
884              
885             =over 4
886              
887             =item @dsn = $das->sources
888              
889             Return a list of data sources available from this server. This is one
890             of the few methods that can be called before setting the data source.
891              
892             =item $segment = $das->segment($id)
893              
894             =item $segment = $das->segment(-ref => $reference [,@args]);
895              
896             The segment() method returns a new Bio::Das::Segment object, which can
897             be queried for information related to a sequence segment. There are
898             two forms of this call. In the single-argument form, you pass
899             segment() an ID to be used as the reference sequence. Sequence IDs
900             are server-specific (some servers will accept genbank accession
901             numbers, others more complex IDs such as Locus:unc-9). The method
902             will return a Bio::Das::Segment object containing a region of the
903             genomic corresponding to the ID.
904              
905             Once you fetch the segment, you can use it to fetch the features that
906             overlap that segment, or the DNA corresponding to the segment. For
907             example:
908              
909             my @features = $segment->features();
910             my $dna = $segment->dna();
911              
912             See L<Bio::Das::Segment> for more details.
913              
914             Instead of a segment ID, you may use a previously-created
915             Bio::Das::Segment object, in which case a copy of the segment will be
916             returned to you. You can then adjust its start and end positions.
917              
918             In the multiple-argument form, you pass a series of argument/value
919             pairs:
920              
921             Argument Value Default
922             -------- ----- -------
923              
924             -ref Reference ID none
925             -segment Bio::Das::Segment obj none
926             -start Starting position 1
927             -end Ending position length of ref ID
928             -offset Starting position 0
929             (0-based)
930             -length Length of segment length of ref ID
931              
932             The B<-ref> argument is required, and indicates the ID of the genomic
933             segment to retrieve. B<-segment> is optional, and can be used to use
934             a previously-created Bio::Das::Segment object as the reference point
935             instead. If both arguments are passed, B<-segment> supersedes
936             B<-ref>.
937              
938             B<-start> and B<-end> indicate the start and stop of the desired
939             genomic segment, relative to the reference ID. If not provided, they
940             default to the start and stop of the reference segment. These
941             arguments use 1-based indexing, so a B<-start> of 0 positions the
942             segment one base before the start of the reference.
943              
944             B<-offset> and B<-length> arguments are alternative ways to indicate a
945             segment using zero-based indexing. It is probably not a good to mix
946             the two calling styles, but if you do, be aware that B<-offset>
947             supersedes B<-start> and B<-length> supersedes B<-stop>.
948              
949             Note that no checking of the validity of the passed reference ID will
950             be performed until you call the segment's features() or dna() methods.
951              
952             =item @segments = $das->get_feature_by_name(-name=>$name [,-class=>$class]);
953              
954             This method implements the DAS feature request using parameters that
955             will translate a feature name into one or more segments. This can be
956             used to retrieve the section of a genome that is occupied by a
957             particular feature. If the feature name matches multiple features in
958             discontinuous parts of the genome, this call may return multiple
959             segments. Once you have a segment, you can call its features() method
960             to get information about the features that overlap this region.
961              
962             The optional -class argument is provided to deal with servers that
963             have namespaced their features using a colon.
964             $das->get_feature_by_name(-name=>'foo',-class=>'bar') is exactly
965             equivalent to $das->get_feature_by_name(-name=>'bar:foo').
966              
967             Because this method is misnamed (it returns segments, not features),
968             it is also known as feature2segment().
969              
970             The method can also be called using the shortcut syntax
971             get_feature_by_name($name).
972              
973             =item @entry_points = $das->entry_points
974              
975             The entry_points() method returns an array of Bio::Das::Segment
976             objects that have been designated "entry points" by the DAS server.
977             Also see the Bio::Das::Segment->entry_points() method.
978              
979             =item $stylesheet = $das->stylesheet
980              
981             Return the stylesheet from the remote DAS server. The stylesheet
982             contains suggestions for the visual format for the various features
983             provided by the server and can be used to translate features into
984             glyphs. The object returned is a Bio::Das::Stylesheet object.
985              
986             =item @types = $das->types
987              
988             This method returns a list of all the annotation feature types served
989             by the DAS server. The return value is an array of Bio::Das::Type
990             objects.
991              
992             =back
993              
994             =head2 DATA FETCHING METHODS - PARALLEL API
995              
996             The following methods accept a series of arguments, contact the
997             indicated DAS servers, and return a series of request objects from
998             which you can learn the status of the request and fetch the results.
999              
1000             Parallel API:
1001              
1002             =over 4
1003              
1004             =item @request = $das->dsn(@list_of_urls)
1005              
1006             The dsn() method accepts a list of DAS server URLs and returns a list
1007             of request objects containing the DSNs provided by each server.
1008              
1009             The request objects will indicate whether each request was successful
1010             via their is_success() methods. For your convenience, the request
1011             object is automagically stringified into the requested URL. For
1012             example:
1013              
1014             my $das = Bio::Das->new(5); # timeout of 5 sec
1015             my @response = $das->dsn('http://stein.cshl.org/perl/das',
1016             'http://genome.cse.ucsc.edu/cgi-bin/das',
1017             'http://user:pass@www.wormbase.org/db/das',
1018             'https://euclid.well.ox.ac.uk/cgi-bin/das',
1019             );
1020              
1021             for my $url (@response) {
1022             if ($url->is_success) {
1023             my @dsns = $url->results;
1024             print "$url:\t\n";
1025             foreach (@dsns) {
1026             print "\t",$_->url,"\t",$_->description,"\n";
1027             }
1028             } else {
1029             print "$url: ",$url->error,"\n";
1030             }
1031             }
1032              
1033             Each element in @dsns is a L<Bio::Das::DSN> object that can be used
1034             subsequently in calls to features(), types(), etc. For example, when
1035             this manual page was written, the following was the output of this
1036             script.
1037              
1038             http://stein.cshl.org/perl/das/dsn:
1039             http://stein.cshl.org/perl/das/chr22_transcripts This is the EST-predicted transcripts on...
1040              
1041             http://servlet.sanger.ac.uk:8080/das:
1042             http://servlet.sanger.ac.uk:8080/das/ensembl1131 The latest Ensembl database
1043              
1044             http://genome.cse.ucsc.edu/cgi-bin/das/dsn:
1045             http://genome.cse.ucsc.edu/cgi-bin/das/hg8 Human Aug. 2001 Human Genome at UCSC
1046             http://genome.cse.ucsc.edu/cgi-bin/das/hg10 Human Dec. 2001 Human Genome at UCSC
1047             http://genome.cse.ucsc.edu/cgi-bin/das/mm1 Mouse Nov. 2001 Human Genome at UCSC
1048             http://genome.cse.ucsc.edu/cgi-bin/das/mm2 Mouse Feb. 2002 Human Genome at UCSC
1049             http://genome.cse.ucsc.edu/cgi-bin/das/hg11 Human April 2002 Human Genome at UCSC
1050             http://genome.cse.ucsc.edu/cgi-bin/das/hg12 Human June 2002 Human Genome at UCSC
1051             http://user:pass@www.wormbase.org/db/das/dsn:
1052             http://user:pass@www.wormbase.org/db/das/elegans This is the The C. elegans genome at CSHL
1053            
1054             https://euclid.well.ox.ac.uk/cgi-bin/das/dsn:
1055             https://euclid.well.ox.ac.uk/cgi-bin/das/dicty Test annotations
1056             https://euclid.well.ox.ac.uk/cgi-bin/das/elegans C. elegans annotations on chromosome I & II
1057             https://euclid.well.ox.ac.uk/cgi-bin/das/ensembl ensembl test annotations
1058             https://euclid.well.ox.ac.uk/cgi-bin/das/test Test annotations
1059             https://euclid.well.ox.ac.uk/cgi-bin/das/transcripts transcripts test annotations
1060              
1061             Notice that the DSN URLs always have the format:
1062              
1063             http://www.wormbase.org/db/das/$DSN
1064             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1065              
1066             In which the ^^^ indicated part is identical to the server address.
1067              
1068             =item @request = $das->types(-dsn=>[$dsn1,$dsn2],@other_args)
1069              
1070             The types() method asks the indicated servers to return the feature
1071             types that they provide. Arguments are name-value pairs:
1072              
1073             Argument Description
1074             -------- -----------
1075              
1076             -dsn A DAS DSN, as returned by the dsn() call. You may
1077             also provide a simple string containing the DSN URL.
1078             To make the types() request on multiple servers, pass an
1079             array reference containing the list of DSNs.
1080              
1081             -segment (optional) An array ref of segment objects. If provided, the
1082             list of types will be restricted to the indicated segments.
1083              
1084             -category (optional) An array ref of type categories. If provided,
1085             the list of types will be restricted to the indicated
1086             categories.
1087              
1088             -enumerate (optional) If true, the server will return the count of
1089             each type. The count can be retrieved using the
1090             L<Bio::Das::Type> objects' count() method.
1091              
1092             -callback (optional) Specifies a subroutine to be invoked on each
1093             type object received.
1094              
1095             Segments have the format: "seq_id:start,end". If successful, the
1096             request results() method will return a list of L<Bio::Das::Type>
1097             objects.
1098              
1099             If a callback is specified, the code ref will be invoked with two
1100             arguments. The first argument is the Bio::Das::Segment object, and
1101             the second is an array ref containing the list of types present in
1102             that segment. If no -segment argument was provided, then the callback
1103             will be invoked once with a dummy segment (a version, but no seq_id,
1104             start or end), and an arrayref containing the types. If a callback is
1105             specified, then the @request array will return the status codes for
1106             each request, but invoking results() will return empty.
1107              
1108             =item @request = $das->entry_points(-dsn=>[$dsn1,$dsn2],@other_args)
1109              
1110             Invoke an entry_points request. Arguments are name-value pairs:
1111              
1112             Argument Description
1113             -------- -----------
1114              
1115             -dsn A DAS DSN, as returned by the dsn() call. You may
1116             also provide a simple string containing the DSN URL.
1117             To make the types() request on multiple servers, pass an
1118             array reference containing the list of DSNs.
1119              
1120             -callback (optional) Specifies a subroutine to be invoked on each
1121             segment object received.
1122              
1123             If a callback is specified, then the @request array will contain the
1124             status codes for each request, but the results() method will return
1125             empty.
1126              
1127             Successful requests will return a set of Bio::Das::Segment objects.
1128              
1129             =item @request = $das->features(-dsn=>[$dsn1,$dsn2],@other_args)
1130              
1131             Invoke a features request to return a set of Bio::Das::Feature
1132             objects. The B<-dsn> argument is required, and may point to a single
1133             DSN or to an array ref of several DSNs. Other arguments are optional:
1134              
1135             Argument Description
1136             -------- -----------
1137              
1138             -dsn A DAS DSN, as returned by the dsn() call. You may
1139             also provide a simple string containing the DSN URL.
1140             To make the types() request on multiple servers, pass an
1141             array reference containing the list of DSNs.
1142              
1143             -segment A single segment, or an array ref containing
1144             several segments. Segments are either Bio::Das::Segment
1145             objects, or strings of the form "seq_id:start,end".
1146              
1147             -type (optional) A single feature type, or an array ref containing
1148             several feature types. Types are either Bio::Das::Type
1149             objects, or plain strings.
1150              
1151             -category (optional) A single feature type category, or an array ref
1152             containing several categories. Category names are described
1153             in the DAS specification.
1154              
1155             -feature_id (optional) One or more feature IDs. The server will return
1156             the list of segment(s) that contain these IDs. You will
1157             need to check with the data provider for the proper format
1158             of the IDs, but the style "class:ID" is common. This will
1159             be replaced in the near future by LSID-style IDs. Also note
1160             that only servers compliant with the 1.52 version of the
1161             spec will honor this.
1162              
1163             -group_id (optional) One or more group IDs. The server will return
1164             the list of segment(s) that contain these IDs. You will
1165             need to check with the data provider for the proper format
1166             of the IDs, but the style "class:ID" is common. This will
1167             be replaced in the near future by LSID-style IDs. Also note
1168             that only servers compliant with the 1.52 version of the
1169             spec will honor this.
1170              
1171             -callback (optional) Specifies a subroutine to be invoked on each
1172             Bio::Das::Feature object received.
1173              
1174             -segment_callback (optional) Specifies a subroutine to be invoked on each
1175             Segment that is retrieved.
1176              
1177             -iterator (optional) If true, specifies that an iterator should be
1178             returned rather than a list of features.
1179              
1180             The features() method returns a list of L<Bio::Das::Request> objects.
1181             There will be one request for each DAS DSN provided in the B<-dsn>
1182             argument. Requests are returned in the same order that they were
1183             passed to B<-dsn>, but you can also query the Bio::Das::Request
1184             object to determine which server processed the request. See Fetching
1185             Results for details. If you happen to call this method in a scalar
1186             context, it will return the first request, discarding the rest.
1187              
1188             If a callback (-callback or -segment_callback) is specified, then the
1189             @request array will contain the status codes for each request, but
1190             results() will return empty.
1191              
1192             The subroutine specified by -callback will be invoked every time a
1193             feature is encountered. The code will be passed a single argument
1194             consisting of a Bio::Das::Feature object. You can find out what
1195             segment this feature is contained within by executing the object's
1196             segment() method.
1197              
1198             The subroutine specified by -segment_callback will be invoked every
1199             time one of the requested segments is finished. It will be invoked
1200             with two arguments consisting of the name of the segment and an array
1201             ref containing the list of Bio::Das::Feature objects contained within
1202             the segment.
1203              
1204             If both -callback and -segment_callback are specified, then the first
1205             subroutine will be invoked for each feature, and the second will be
1206             invoked on each segment *AFTER* the segment is finished. In this
1207             case, the segment processing subroutine will be passed an empty list
1208             of features.
1209              
1210             Note, if the -segment argument is not provided, some servers will
1211             provide all the features in the database.
1212              
1213             The -iterator argument is a true/false flag. If true, the call will
1214             return a L<Bio::Das::FeatureIterator> object. This object implements
1215             a single method, next_seq(), which returns the next Feature. Example:
1216              
1217             $iterator = $das->features(-dsn=>[$dsn1,$dsn2],-iterator=>1);
1218             while (my $feature = $iterator->next_seq) {
1219             my $dsn = $feature->segment->dsn;
1220             my $type = $feature->type;
1221             print "got a $type from $dsn\n";
1222             }
1223              
1224             =item @request = $das->dna(-dsn=>[$dsn1,$dsn2],@other_args)
1225              
1226             Invoke a features request to return a DNA string. The -dsn argument
1227             is required, and may point to a single DSN or to an array ref of
1228             several DSNs. Other arguments are optional:
1229              
1230             Argument Description
1231             -------- -----------
1232              
1233             -dsn A DAS DSN, as returned by the dsn() call. You may
1234             also provide a simple string containing the DSN URL.
1235             To make the types() request on multiple servers, pass an
1236             array reference containing the list of DSNs.
1237              
1238             -segment (optional) A single segment, or an array ref containing
1239             several segments. Segments are either Bio::Das::Segment
1240             objects, or strings of the form "seq_id:start,end".
1241              
1242             -callback (optional) Specifies a subroutine to be invoked on each
1243             DNA string received.
1244              
1245             -dsn, -segment and -callback have the same meaning that they do in
1246             similar methods.
1247              
1248             =item @request = $das->stylesheet(-dsn=>[$dsn1,$dsn2],@other_args)
1249              
1250             Invoke a stylesheet request to return the L<Bio::Das::Stylesheet>
1251             object. The -dsn argument is required, and may point to a single DSN
1252             or to an array ref of several DSNs. Other arguments are optional:
1253              
1254             Argument Description
1255             -------- -----------
1256              
1257             -dsn A DAS DSN, as returned by the dsn() call. You may
1258             also provide a simple string containing the DSN URL.
1259             To make the types() request on multiple servers, pass an
1260             array reference containing the list of DSNs.
1261              
1262             -segment (optional) A single segment, or an array ref containing
1263             several segments. Segments are either Bio::Das::Segment
1264             objects, or strings of the form "seq_id:start,end".
1265              
1266             -callback (optional) Specifies a subroutine to be invoked on each
1267             stylesheet received.
1268              
1269             -dsn, -segment and -callback have the same meaning that they do in
1270             similar methods.
1271              
1272             =item @request = $das->get_feature_by_name(-dsn=>[$dsns],-name=>$name [,-class=>$class]);
1273              
1274             This method implements the DAS feature request using parameters that
1275             will translate a feature name into one or more segments. This can be
1276             used to retrieve the section of a genome that is occupied by a
1277             particular feature. If the feature name matches multiple features in
1278             discontinuous parts of the genome, this call may return multiple
1279             segments. Once you have a segment, you can call its features() method
1280             to get information about the features that overlap this region.
1281              
1282             The optional -class argument is provided to deal with servers that
1283             have namespaced their features using a colon.
1284             $das->get_feature_by_name(-name=>'foo',-class=>'bar') is exactly
1285             equivalent to $das->get_feature_by_name(-name=>'bar:foo').
1286              
1287             Because this method is misnamed (it returns segments, not features),
1288             it is also known as feature2segment().
1289              
1290             In case of a successful request, the request results() method will
1291             return a list of Bio::Das::Segment objects, which can then be passed
1292             back to features().
1293              
1294             =back
1295              
1296             =head2 Fetching Results
1297              
1298             When using the parallel API, the dsn(), features(), dna(), and
1299             stylesheet() methods will return an array of L<Bio::Das::Request>
1300             objects. Each object contains information about the outcome of the
1301             request and the results, if any, returned. The request objects
1302             correspond to each of the DSNs passed to the request in the B<-dsn>
1303             argument, and have the same number and order.
1304              
1305             Because of the inherent uncertainties of the Internet, any DAS request
1306             can fail. It could fail because of a network transmission error, a
1307             timeout, a down server, an HTTP URL-not-found error, or an unparseable
1308             DAS document. For this reason, you should check each request's
1309             is_success() method before trying to use the results. Here is the
1310             canonical code:
1311              
1312             my @requests = $das->some_method(-dsn=>[$dsn1,$dsn2,$dsn3]);
1313             for my $request (@requests) {
1314             if ($request->is_success) {
1315             my $results = $request->results;
1316             # do something with the results
1317             }
1318              
1319             else {
1320             warn $request->error;
1321             }
1322             }
1323              
1324             The is_success() method returns true on a successful request, false
1325             otherwise. In case of an unsuccessful request, the error() method
1326             will provide additional information on why the request failed The
1327             format is "XXXX human-readable string" as in:
1328              
1329             400 Bad command
1330              
1331             The following error strings can be returned:
1332              
1333             400 Bad command
1334             401 Bad data source
1335             402 Bad command arguments
1336             403 Bad reference object
1337             404 Bad stylesheet
1338             405 Coordinate error
1339             410 Unknown host
1340             411 Couldn't connect
1341             412 Communications error
1342             413 Authentication scheme 'xxxx" is not supported
1343             500 Server error
1344             501 Unimplemented feature
1345             502 No X-Das-Version header
1346             503 Invalid X-Das-Version header
1347             504 DAS server is too old
1348             505 No X-Das-Status header
1349             506 Data decompression failure
1350              
1351             To discover which server a request was sent to, you can call its dsn()
1352             method. This will return the server and data source as a single URL,
1353             e.g.:
1354              
1355             my $dsn = $request->dsn;
1356             print $dsn,"\n"; # prints 'http://www.wormbase.org/db/das/elegans'
1357              
1358             What is returned is actually a L<Bio::Das::DSN> object. You can call
1359             the object's base() method to return the server part of the DSN, and
1360             its id() method to return the data source:
1361              
1362             my $dsn = $request->dsn;
1363             print $dsn->base,"\n"; # prints 'http://www.wormbase.org/db/das'
1364             print $dsn->id,"\n"; # prints 'elegans'
1365              
1366             To get the results of from the request, call its results() method. In
1367             a list context, results() will return a list of the appropriate
1368             objects for the request (a set of L<Bio::Das::Feature> objects for the
1369             features() request a set of L<Bio::Das::Stylesheet> objects for the
1370             stylesheet() request, a set of L<Bio::Das::Type> objects for the
1371             types() request, and a set of raw DNA strings for the dna()
1372             request.)
1373              
1374             In a scalar context, results() will return a hashref in which the keys
1375             are the segment strings passed to the request with the B<-segments>
1376             argument and the values are arrayrefs containing the list of results.
1377              
1378             There is an equivalence here. When this code fragment executes, both
1379             $results_hash1 and $results_hash2 will contain the same information.
1380              
1381             my @results = $request->results;
1382             my $result_hash1 = {};
1383             for my $r (@results) {
1384             my $segment = $r->segment;
1385             push @{$result_hash{$segment}},$r;
1386             }
1387              
1388             my $result2_hash2 = $request->results;
1389              
1390             =head2 Authentication
1391              
1392             It may be desirable to access DAS data that is stored in an
1393             authenticating (password protected) server. Only HTTP Basic
1394             authentication is currently supported by Bio::Das, but you can run the
1395             authentication over an SSL connection, thereby avoiding the risk of
1396             passwords being sniffed.
1397              
1398             Authentication information can be passed to the server in either of
1399             two ways:
1400              
1401             =over 4
1402              
1403             =item In the server's URL
1404              
1405             You can provide the username and password in the form:
1406              
1407             http://user:pass@my.das.server.org/cgi-bin/das
1408              
1409             Where B<user> and B<pass> are the username and password required for
1410             authentication.
1411              
1412             Unless you do with this an SSL (https:) connection, you will get a
1413             warning that using the password in the URL violates the recommendation
1414             in RFC 2396. You can suppress this warning using the no_rfc_warning()
1415             method:
1416              
1417             $das->no_rfc_warning(1);
1418              
1419             =item Using an authentication callback
1420              
1421             You can provide a subroutine code reference that returns the username
1422             and password at the time you create the Bio::Das object. When
1423             accessing a password protected site, Bio::Das will invoke your
1424             callback using information about the request. The callback will return
1425             the appropriate username and password. You can do whatever you need
1426             to do to get the authentication information, whether accessing an
1427             enterprise database, or popping up a dialog box for the user to
1428             respond to.
1429              
1430             =back
1431              
1432             To install an authentication callback, pass a coderef to
1433             the B<-auth_callback> argument when calling Bio::Das->new():
1434              
1435             Bio::Das->new(-auth_callback=>\&my_authentication_routine);
1436              
1437             The callback will be called with three arguments:
1438              
1439             my_authentication_routine($fetcher,$realm,$iteration_count)
1440              
1441             B<$fetcher> is an L<Bio::Das::HTTP::Fetch> object. It contains the
1442             information you will need to determine which server is requesting
1443             authentication. You will probably want to call the fetch object's
1444             host() method to get the name of the DAS host, but if you require more
1445             information, the request() method will return the L<Bio::Das::Request>
1446             object with complete information about the request.
1447              
1448             B<$realm> is the Basic Authentication Realm string, as returned by the
1449             remote server.
1450              
1451             B<$iteration_count> records the number of times your authentication
1452             routine has been invoked for this particular realm. You can use this
1453             information to abort authentication if it fails the first time.
1454              
1455             The authentication callback should a two-element list containing the
1456             username and password for authentication against the server. If it
1457             returns an empty list, the request will be aborted.
1458              
1459             Here is a sample authentication routine. It prompts the user up to
1460             three times for his username and password, and then aborts. Notice
1461             the way in which the hostname is recovered from the
1462             Bio::Das::HTTP::Fetch object.
1463              
1464             sub my_authentication_routine {
1465             my ($fetcher,$domain,$iteration_count) = @_;
1466             return if $iteration_count > 3;
1467             my $host = $fetcher->request->host;
1468             print STDERR "$host/$domain requires authentication (try $iteration_count of 3)\n";
1469             print STDERR "Username: ";
1470             chomp (my $username = <>);
1471             print STDERR "Password: ";
1472             chomp (my $password = <>);
1473             return ($username,$password);
1474             }
1475              
1476             Note: while processing the authentication callback, processing of
1477             other pending requests will stall, usually at the point at which the
1478             request has been sent, but the results have not yet been received and
1479             parsed. For this reason, you might want to include a timeout in your
1480             authentication routine.
1481              
1482             =head1 AUTHOR
1483              
1484             Lincoln Stein <lstein@cshl.org>.
1485              
1486             Copyright (c) 2001 Cold Spring Harbor Laboratory
1487              
1488             This library is free software; you can redistribute it and/or modify
1489             it under the same terms as Perl itself. See DISCLAIMER.txt for
1490             disclaimers of warranty.
1491              
1492             =head1 SEE ALSO
1493              
1494             L<Bio::Das::Request>, L<Bio::Das::HTTP::Fetch>,
1495             L<Bio::Das::Segment>, L<Bio::Das::Type>, L<Bio::Das::Stylesheet>,
1496             L<Bio::Das::Source>, L<Bio::RangeI>
1497              
1498             =cut