ExternalFeatureAdaptor.pm 25.3 KB
Newer Older
1 2 3 4 5 6 7 8 9
#
# EnsEMBL module for Bio::EnsEMBL::External::ExternalFeatureAdaptor
#
# You may distribute this module under the same terms as perl itself

# POD documentation - main docs before the code

=head1 NAME

10 11 12 13 14 15 16 17
Bio::EnsEMBL::External::ExternalFeatureAdaptor

=head 1 SUMMARY

Allows features created externally from EnsEMBL in a single coordinate system 
to be retrieved in several other (EnsEMBL-style) coordinate systems. This is 
intended to be a replacement for the old 
Bio::EnsEMBL::DB::ExternalFeatureFactoryI interface.
18 19 20 21 22 23 24 25

=head1 SYNOPSIS

  $database_adaptor = 
    new Bio::EnsEMBL::DBSQL::DBAdaptor( -host   => 'kaka.sanger.ac.uk',
                                        -dbname => 'homo_sapiens_core_9_30',
                                        -pass   => 'anonymous' );

26 27
  $xf_adaptor = new ExternalFeatureAdaptorSubClass;

28
  #Connect the EnsEMBL core database:
29
  $xf_adaptor->db($database_adaptor);
30 31 32 33 34 35 36 37 38 39

  #get some features in RawContig coords
  @feats = @{$xf_adaptor->fetch_all_by_contig_name('AC000087.2.1.42071')};

  #get some features in assembly coords
  @feats = @{$xf_adaptor->fetch_all_by_chr_start_end('X', 100000, 200000)};

  #get some features in clone coords
  @feats = @{$xf_adaptor->fetch_all_by_clone_accession('AC000087')};

40 41 42
  #Add the adaptor to the ensembl core dbadaptor (implicitly sets db attribute)
  $database_adaptor->add_ExternalFeatureAdaptor($xf_adaptor);

43 44
  #get some features in Slice coords
  $slice_adaptor = $database_adaptor->get_SliceAdaptor;
45
  $slice = $slice_adaptor->fetch_all_by_chr_start_end(1,100000,200000);
46 47
  @feats = @{$xf_adaptor->fetch_all_by_Slice($slice)};

48
  #now features can be retrieved directly from Slice
49 50 51
  @feats = @{$slice->get_all_ExternalFeatures};
  

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
=head1 DESCRIPTION

This class is intended to be used as a method of getting external features into
EnsEMBL.  To work, this class must be extended and must implement the
the coordinate_systems method.  As well, the subclass is required to implement
a single fetch method so that the external features may be retrieved.  
By implementing a single fetch_method in a single coordinate system all
of the other ExternalFeatureAdaptor fetch methods become available for 
retrieving the data in several different coordinate systems.

The coordinate_systems method should return a list of strings indicating which
coordinate system(s) have been implemented.  If a given string is returned 
from the coordinate_systems method then the corresponding fetch method must be 
implemented.  The reverse is also true: if a fetch method is implemented then
coordinate_systems must return the appropriate string in its list of return 
values.  The following are the valid coordinate system values and the 
corresponding fetch methods that must be implemented:

  COORD SYSTEM STRING   FETCH_METHOD      
  -------------------   ------------
  'ASSEMBLY'            fetch_all_by_chr_start_end
  'CLONE'               fetch_all_by_clone_accession
  'CONTIG'              fetch_all_by_contig_name
75
  'SUPERCONTIG'         fetch_all_by_supercontig_name
76 77
  'SLICE'               fetch_all_by_Slice

78 79
The objects returned by the fetch methods should be EnsEMBL or BioPerl style
Feature objects.  These objects MUST have start, end and strand methods.
80 81 82 83

Before the non-overridden ExternalFeatureAdaptor fetch methods may be called
an EnsEMBL core database adaptor must be attached to the ExternalFeatureAdaptor
.  This database adaptor is required to perform the remappings between various
84 85 86
coordinate system.  This may be done implicitly by adding the 
ExternalFeatureAdaptor to the database adaptor through a call to the 
DBAdaptor add_ExternalFeatureAdaptor method or explicitly by calling the 
87
ExternalFeatureAdaptor ensembl_db method.
88 89


90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
=head1 CONTACT

Post questions to the EnsEMBL developer list: <ensembl-dev@ebi.ac.uk>

=head1 AUTHOR

Graham McVicker

=head1 APPENDIX

The rest of the documentation details each of the object methods. 
Internal methods are usually preceded with a _

=cut

use strict;

package Bio::EnsEMBL::External::ExternalFeatureAdaptor;

109
use Bio::EnsEMBL::Utils::Exception qw(warning throw);
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135


=head2 new

  Arg [1]    : none
  Example    : $xfa = new Bio::EnsEMBL::External::ExternalFeatureAdaptor;
  Description: Creates a new ExternalFeatureAdaptor object.  You may wish to
               extend this constructor and provide your own set of paremeters.
  Returntype : Bio::EnsEMBL::External::ExternalFeatureAdaptor
  Exceptions : none
  Caller     : general

=cut

sub new {
  my $class = shift;

  if(ref $class) {
    return bless {}, ref $class;
  }

  return bless {}, $class;
}



Arne Stabenau's avatar
bug fix  
Arne Stabenau committed
136
=head2 ensembl_db
137 138

  Arg [1]    : (optional) Bio::EnsEMBL::DBSQL::DBAdaptor
Arne Stabenau's avatar
bug fix  
Arne Stabenau committed
139
  Example    : $external_feature_adaptor->ensembl_db($new_val);
140 141 142 143 144 145 146
  Description: none
  Returntype : Bio::EnsEMBL::DBSQL::DBAdaptor
  Exceptions : none
  Caller     : internal

=cut

Arne Stabenau's avatar
bug fix  
Arne Stabenau committed
147
sub ensembl_db {
148 149 150
  my ($self, $value) = @_;

  if($value) {
151 152
    #avoid potentially nasty memory leaks
    if(ref $value && $value->isa("Bio::EnsEMBL::Container")) {
Arne Stabenau's avatar
bug fix  
Arne Stabenau committed
153 154 155
      $self->{'ensembl_db'} = $value->_obj;
    } else {
      $self->{'ensembl_db'} = $value;
156
    }
157 158
  }     

Arne Stabenau's avatar
bug fix  
Arne Stabenau committed
159
  return $self->{'ensembl_db'};
160
}
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181



=head2 coordinate_systems

  Arg [1]    : none
  Example    : @implemented_coord_systems = $ext_adaptor->coordinate_systems;
  Description: ABSTRACT method. Must be implemented by all 
               ExternalFeatureAdaptor subclasses.  This method returns a list
               of coordinate systems which are implemented by the subclass. 
               A minimum of on valid coordinate system must be implemented.
               Valid coordinate systems are: 'SLICE', 'ASSEMBLY', 'CONTIG',
               and 'CLONE'.
  Returntype : list of strings
  Exceptions : none
  Caller     : internal

=cut

sub coordinate_systems {
  my $self = shift;
182 183

  throw("abstract method coordinate_systems not implemented\n");
184 185 186 187 188

  return '';
}


189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
=head2 track_name

  Arg [1]    : none
  Example    : $track_name = $xf_adaptor->track_name;
  Description: Currently this is not really used.  In the future it may be 
               possible to have ExternalFeatures automatically displayed by
               the EnsEMBL web code.  By default this method returns 
               'External features' but you are encouraged to override this 
               method and provide your own meaningful name for the features
               your adaptor provides.  This also allows you to distinguish the
               type of features retrieved from RawContigs or Slices.  See
               the PODs for Bio::EnsEMBL::Slice::get_all_ExternalFeatures and 
               Bio::EnsEMBL::DBSQL::DBAdaptor::add_ExternalFeatureAdaptor 
               methods. 
  Returntype : string
  Exceptions : none
  Caller     : Bio::EnsEMBL::DBSQL::DBAdaptor::add_ExternalFeatureAdaptor

=cut

sub track_name {
  my $self = shift;

  return 'External features';
}



=head2 feature_type

  Arg [1]    : none
  Example    : $feature_type = $xf_adaptor->track_name
  Description: Currently this is not used.  In the future it may be possible
               to have ExternalFeatures automatically displayed by the EnsEMBL
               web code.  This method would then be used do determine the 
               type of glyphs used to draw the features which are returned
               from this external adaptor.
  Returntype : string
  Exceptions : none
  Caller     : none

=cut

sub feature_type {
  my $self = shift;
  
  return qw(SIMPLE);
}


239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262

=head2 fetch_all_by_Slice

  Arg [1]    : Bio::EnsEMBL::Slice $slice
  Example    : @features = @{$ext_adaptor->fetch_all_by_Slice($slice)};
  Description: Retrieves all features which lie in the region defined
               by $slice in slice coordinates.  
  
               If this method is overridden then the coordinate_systems method
               must return 'SLICE' as one of its values.  

               This method will work as is (i.e. without overriding it) 
               providing at least one of the other fetch methods is overridden.
  Returntype : reference to a list of Bio::SeqFeature objects in the Slice
               coordinate system
  Exceptions : Thrown on incorrect input arguments
  Caller     : general, fetch_all_by_chr_start_end

=cut

sub fetch_all_by_Slice {
  my ($self, $slice) = @_;

  unless($slice && ref $slice && $slice->isa('Bio::EnsEMBL::Slice')) {
263
    throw("[$slice] is not a Bio::EnsEMBL::Slice");
264 265 266 267
  }

  my $out = [];

268 269 270 271
  my $csa = $self->ensembl_db->get_CoordSystemAdaptor();

  my $slice_start  = $slice->start;
  my $slice_end    = $slice->end;
272
  my $slice_strand = $slice->strand;
273 274
  my $slice_seq_region  = $slice->seq_region_name;
  my $coord_system = $slice->coord_system;
275 276

  if($self->_supported('SLICE')) {
277
    throw("ExternalFeatureAdaptor supports SLICE coordinate system" .
278
		 " but fetch_all_by_Slice not implemented");
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
  }

  my %features;
  my $from_coord_system;

  my $fetch_method;

  #
  # Get all of the features from whatever coord system they are computed in
  #
  if($self->_supported('CLONE')) {
    $fetch_method = sub {
      my $self = shift;
      my $name = shift;
      my ($acc, $ver) = split(/\./, $name);
      $self->fetch_all_by_clone_accession($acc,$ver,@_);
    };
    $from_coord_system = $csa->fetch_by_name('clone');
  } elsif($self->_supported('ASSEMBLY')) {
    $from_coord_system = $csa->fetch_by_name('toplevel');
    $fetch_method = $self->can('fetch_all_by_chr_start_end');
  } elsif($self->_supported('CONTIG')) {
    $from_coord_system = $csa->fetch_by_name('contig');
    $fetch_method = $self->can('fetch_all_by_contig_name');
  } elsif($self->_supported('SUPERCONTIG')) {
    $from_coord_system = $csa->fetch_by_name('supercontig');
    $fetch_method = $self->can('fetch_all_by_supercontig_name');
  } else {
    $self->_no_valid_coord_systems();
  }

  if($from_coord_system->equals($coord_system)) {
    $features{$slice_seq_region} = &$fetch_method($self, $slice_seq_region,
                                                  $slice_start,$slice_end);
  } else {
    foreach my $segment (@{$slice->project($from_coord_system->name,
                                           $from_coord_system->version)}) {
      my ($start,$end,$pslice) = @$segment;
      $features{$pslice->seq_region_name} ||= [];
      push @{$features{$pslice->seq_region_name}},
           @{&$fetch_method($self, $pslice->seq_region_name,
                            $pslice->start(),
                            $pslice->end())};
    }
  }

  my @out;

  if(!$coord_system->equals($from_coord_system)) {             
    my $asma = $self->ensembl_db->get_AssemblyMapperAdaptor();
    my $mapper = $asma->fetch_by_CoordSystems($from_coord_system,
                                              $coord_system);
    my %slice_cache;
    my $slice_adaptor = $self->ensembl_db->get_SliceAdaptor();
    my $slice_setter;

    #convert the coordinates of each of the features retrieved
    foreach my $fseq_region (keys %features) {
      my $feats = $features{$fseq_region};
      next if(!$feats);
      $slice_setter = _guess_slice_setter($feats) if(!$slice_setter);

      foreach my $f (@$feats) {
        my($sr_name, $start, $end, $strand) = 
          $mapper->fastmap($fseq_region,$f->start,$f->end,$f->strand,
                           $from_coord_system);
        
        #maps to gap
        next if(!defined($sr_name));

        #maps to unexpected seq region, probably error in the externally
        if($sr_name ne $slice_seq_region) {
          warning("Externally created Feature mapped to [$sr_name] " .
                  "which is not on requested seq_region [$slice_seq_region]");
          next;
        }

        #update the coordinates of the feature
        &$slice_setter($f,$slice);
        $f->start($start);
        $f->end($end);
        $f->strand($strand);
        push @out, $f;
      }
    }
  } else {
    #we already know the seqregion the featues are on, we just have
    #to put them on the slice
    @out = @{$features{$slice_seq_region}};
    my $slice_setter = _guess_slice_setter(\@out);

    foreach my $f (@out) {
      &$slice_setter($f,$slice);
372
    }
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
  }

  #shift the feature coordinates again if
  #the requested slice is not the full seqregion
  if($slice->start != 1 || $slice->strand != 1) {
    #convert from assembly coords to slice coords
    my($f_start, $f_end, $f_strand);
    foreach my $f (@out) {
      if($slice_strand == 1) {
        $f_start  = $f->start - $slice_start + 1;
        $f_end    = $f->end   - $slice_start + 1;
        $f_strand = $f->strand;
      } else {
        $f_start  = $slice_end - $f->end   + 1;
        $f_end    = $slice_end - $f->start + 1;
        $f_strand = $f->strand * -1;
      }
390
    
391 392 393 394
      $f->start($f_start);
      $f->end($f_end);
      $f->strand($f_strand);
    }
395 396
  }
  
397
  return \@out;
398 399 400
}
  

401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
sub _guess_slice_setter {
  my $features = shift;

  #we do not know what type of features these are.  They might
  #be bioperl features or old ensembl features, hopefully they are new
  #style features.  Try to come up with a setter method for the
  #slice.

  return undef if(!@$features);

  my ($f) = @$features;

  my $slice_setter;
  foreach my $method (qw(slice contig attach_seq)) {
    last if($slice_setter = $f->can($method));
  }
    
  if(!$slice_setter) {
    if($f->can('seqname')) {
      $slice_setter = sub { $_[0]->seqname($_[1]->seq_region_name()); };
    } else {
      $slice_setter = sub{} if(!$slice_setter);
    }
  }

  return $slice_setter;
}


430 431 432 433 434

=head2 fetch_all_by_RawContig

  Arg [1]    : Bio::EnsEMBL::RawContig $contig
  Example    : @features = @{$self->fetch_all_by_RawContig($contig)};
435 436 437
  Description: You should use the fetch_all_by_Slice method instead of this
               method now.  RawContigs have been effectively replaced by
               Slices.
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457

               If this method is overridden then it is also necessary to 
               override the fetch_all_by_contig_name method due to 
               interdependencies.  As well, if this method is overridden then 
               the coordinate_systems method must return 'CONTIG' as one of 
               its values.  

               It is probably more useful to only override the 
               fetch_all_by_contig_name instead of both methods. This method 
               will work as is - providing at least one other fetch method has 
               been overridden.               
  Returntype : reference to a list of Bio::SeqFeature objects in the RawContig
               coordinate system.
  Exceptions : thrown if the input argument is incorrect
  Caller     : general, fetch_all_by_contig_name, 
               fetch_all_by_Clone, fetch_all_by_chr_start_end

=cut

sub fetch_all_by_RawContig {
458 459 460
  my $self = shift;
  return $self->fetch_all_by_Slice(@_);
}
461 462


463
=head2 fetch_all_by_contig_name
464

465 466 467 468 469 470 471 472 473 474
  Arg [1]    : string $contig_name
  Arg [2]    : int $start (optional)
               The start of the region on the contig to retrieve features on
               if not specified the whole of the contig is used.
  Arg [3]    : int $end (optional) 
               The end of the region on the contig to retrieve features on
               if not specified the whole of the contig is used.
  Example    : @fs = @{$self->fetch_all_by_contig_name('AB00879.1.1.39436')};
  Description: Retrieves features on the contig defined by the name 
               $contig_name in RawContig coordinates.
475

476 477
               If this method is overridden then the coordinate_systems 
               method must return 'CONTIG' as one of its values. 
478

479 480 481 482 483 484 485 486 487
               This method will work as is (i.e. without being overridden) 
               providing at least one other fetch method has 
               been overridden.               
  Returntype : reference to a list of Bio::SeqFeature objects in the RawContig
               coordinate system.
  Exceptions : thrown if the input argument is incorrect
               thrown if the coordinate_systems method returns the value 
               'CONTIG' and this method has not been overridden.
  Caller     : general, fetch_all_by_Slice
488

489 490 491 492
=cut

sub fetch_all_by_contig_name {
  my ($self, $contig_name, $start, $end) = @_;
493

494 495
  unless($contig_name) {
    throw("contig_name argument not defined");
496 497
  }

498 499 500
  if($self->_supported('CONTIG')) {
    throw("ExternalFeatureAdaptor supports CONTIG coordinate system" .
		 " but fetch_all_by_contig_name is not implemented");
501 502
  }

Arne Stabenau's avatar
bug fix  
Arne Stabenau committed
503
  unless($self->ensembl_db) {
504
    throw('DB attribute not set.  This value must be set for the ' .
505 506
		 'ExternalFeatureAdaptor to function correctly');
  }
507

508 509 510 511
  my $slice_adaptor = $self->ensembl_db->get_SliceAdaptor();
  my $slice = $slice_adaptor->fetch_by_region('contig', $contig_name,
                                             $start, $end);
  return $self->fetch_all_by_Slice($slice);
512 513 514 515
}



516 517 518 519 520 521 522 523 524 525
=head2 fetch_all_by_supercontig_name

  Arg [1]    : string $supercontig_name
  Arg [2]    : int $start (optional)
               The start of the region on the contig to retrieve features on
               if not specified the whole of the contig is used.
  Arg [3]    : int $end (optional) 
               The end of the region on the contig to retrieve features on
               if not specified the whole of the contig is used.
  Example    : @fs = @{$self->fetch_all_by_contig_name('NT_004321')};
526
  Description: Retrieves features on the contig defined by the name 
527
               $supercontigname in supercontig coordinates.
528 529

               If this method is overridden then the coordinate_systems 
530
               method must return 'SUPERCONTIG' as one of its values. 
531 532 533

               This method will work as is (i.e. without being overridden) 
               providing at least one other fetch method has 
534
               been overridden.               
535 536 537 538
  Returntype : reference to a list of Bio::SeqFeature objects in the RawContig
               coordinate system.
  Exceptions : thrown if the input argument is incorrect
               thrown if the coordinate_systems method returns the value 
539 540
               'SUPERCONTIG' and this method has not been overridden.
  Caller     : general, fetch_all_by_Slice
541 542 543 544

=cut


545 546 547 548 549
sub fetch_all_by_supercontig_name {
  my ($self, $supercontig_name, $start, $end) = @_;

  unless($supercontig_name) {
    throw("supercontig_name argument not defined");
550 551
  }

552 553 554
  if($self->_supported('SUPERCONTIG')) {
    throw("ExternalFeatureAdaptor supports SUPERCONTIG coordinate system" .
		 " but fetch_all_by_supercontig_name is not implemented");
555 556
  }

Arne Stabenau's avatar
bug fix  
Arne Stabenau committed
557
  unless($self->ensembl_db) {
558
    throw('DB attribute not set.  This value must be set for the ' .
559 560 561
		 'ExternalFeatureAdaptor to function correctly');
  }

562 563 564 565
  my $slice_adaptor = $self->ensembl_db->get_SliceAdaptor();
  my $slice = $slice_adaptor->fetch_by_region('supercontig', $supercontig_name,
                                             $start, $end);
  return $self->fetch_all_by_Slice($slice);
566 567 568 569 570 571 572
}


=head2 fetch_all_by_Clone

  Arg [1]    : Bio::EnsEMBL::Clone $clone
  Example    : @features = @{$self->fetch_all_by_Clone($clone)};
573 574 575
  Description: You should not use this method anymore. Use the 
               fetch_all_by_Slice method instead. Clones have effectively been
               replaced by Slices on the 'clone' coordinate system.
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
               
               If this method is overridden then it is also necessary to 
               override the fetch_all_by_clone_accession method due to 
               interdependencies.  As well, if this method is overridden then 
               the coordinate_systems method must return 'CLONE' as one of its
               values.  
              
               It is probably more useful to override only the 
               fetch_all_by_clone_accession method rather than both of these 
               methods. This method will work as is - providing at least one 
               other fetch method has been overridden.               
  Returntype : reference to a list of Bio::SeqFeature objects in the Clone
               coordinate system
  Exceptions : thrown if the input argument is incorrect
               thrown if the coordinate systems method does not return any 
               valid values.
  Caller     : general, fetch_all_by_clone_accession, 
               fetch_all_by_RawContig

=cut

sub fetch_all_by_Clone {
598 599
  my $self = shift;
  return $self->fetch_all_by_Slice(@_);
600 601 602 603 604 605 606 607
}



=head2 fetch_all_by_clone_accession

  Arg [1]    : string $acc
               The EMBL accession number of the clone to fetch features from.
608 609 610 611
  Arg [2]    : (optional) string $ver
  Arg [3]    : (optional) int $start
  Arg [4]    : (optional) int $end
 
612 613 614 615 616
  Example    : @fs = @{$self->fetch_all_by_clone_accession('AC000093')};
  Description: Retrieves features on the clone defined by the $acc arg in 
               Clone coordinates. 
               
               If this method is overridden then the coordinate_systems method
617 618 619 620
               must return 'CLONE' as one of its values. The arguments 
               start, end, version are passed if this method is overridden and
               can optionally be used to reduce the scope of the query and 
               improve performance.  
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640

               If the fetch_all_by_Clone method has been overridden then this
               method must also be overridden to chain calls to that method
               (and avoid throwing an exception).
               This method will work as is - providing at least one other 
               fetch method has been overridden and the fetch_all_by_Clone 
               method has not been overridden.
  Returntype : reference to a list of Bio::SeqFeature objects in the Clone
               coordinate system
  Exceptions : thrown if the input argument is incorrect
               thrown if the coordinate system method returns the value 'CLONE'
               and this method is not overridden.
               thrown if the coordinate systems method does not return any 
               valid values.
  Caller     : general, fetch_all_by_clone_accession, 
               fetch_all_by_RawContig

=cut

sub fetch_all_by_clone_accession {
641
  my ($self, $acc, $version, $start, $end) = @_;
642 643

  unless($acc) {
644
    throw("clone accession argument not defined");
645 646 647
  }

  if($self->_supported('CLONE')) {
648
    throw('ExternalFeatureAdaptor supports CLONE coordinate system ' .
649 650 651
		 'but does not implement fetch_all_by_clone_accession');
  }

Arne Stabenau's avatar
bug fix  
Arne Stabenau committed
652
  unless($self->ensembl_db) {
653
    throw('DB attribute not set.  This value must be set for the ' .
654 655 656
		 'ExternalFeatureAdaptor to function correctly');
  }

657 658 659 660 661
  if(defined($version)) {
    $acc = "$acc.$version";
  } elsif(!$acc =~ /\./) {
    $acc = "$acc.1";
  }
662

663
  my $slice_adaptor = $self->ensembl_db->get_SliceAdaptor;
664

665
  my $slice = $slice_adaptor->fetch_by_region('clone', $acc, $start, $end);
666

667
  return $self->fetch_all_by_Slice($slice);
668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
}



=head2 fetch_all_by_chr_start_end

  Arg [1]    : string $chr_name
               The name of the chromosome to retrieve features from
  Arg [2]    : int $start
               The start coordinate of the chromosomal region to retrieve
               features from.
  Arg [3]    : int $end
               The end coordinate of the chromosomal region to retrieve 
               features from.
  Example    : @features
  Description: Retrieves features on the region defined by the $chr_name,
               $start, and $end args in assembly (chromosomal) coordinates. 

               If this method is overridden then the coordinate_systems method
               must return 'ASSEMBLY' as one of its values.  

               This method will work as is (i.e. without overriding it) 
               providing at least one of the other fetch methods is overridden.
  Returntype : reference to a list of Bio::SeqFeatures 
  Exceptions : Thrown if the coordinate_systems method returns ASSEMBLY as a 
               value and this method is not overridden.  
               Thrown if any of the input arguments are incorrect
  Caller     : general, fetch_all_by_Slice, fetch_all_by_RawContig

=cut

sub fetch_all_by_chr_start_end {
  my ($self, $chr_name, $start, $end) = @_;

  unless($chr_name && defined $start && defined $end && $start < $end) {
703
    throw("Incorrect start [$start] end [$end] or chr [$chr_name] arg");
704 705
  }

Arne Stabenau's avatar
bug fix  
Arne Stabenau committed
706
  unless($self->ensembl_db) {
707
    throw('DB attribute not set.  This value must be set for the ' .
708 709 710
		 'ExternalFeatureAdaptor to function correctly');
  }

711
  my $slice_adaptor = $self->ensembl_db->get_SliceAdaptor();
712

713 714
  my $slice = $slice_adaptor->fetch_by_region('toplevel', $chr_name, $start,
                                              $end);
715

716
  return $self->fetch_all_by_Slice($slice);
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
}


=head2 _no_valid_coord_system

  Arg [1]    : none
  Example    : none
  Description: PRIVATE method - throws an error with a descriptive message
  Returntype : none
  Exceptions : always thrown
  Caller     : internal

=cut

sub _no_valid_coord_system {
  my $self = shift;

734
  throw("This ExternalFeatureAdaptor does not support a known " .
735
		"coordinate system.\n Valid coordinate systems are: " .
736
		"[SLICE,ASSEMBLY,SUPERCONTIG,CONTIG,CLONE].\n This External Adaptor " . 
737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771
                "supports: [" . join(', ', $self->coordinate_systems) . "]");
}  




=head2 _supported

  Arg [1]    : string $system 
  Example    : print "CONTIG system supported" if($self->_supported('CONTIG'));
  Description: PRIVATE method. Tests if the coordinate system defined by
               the $system argument is implemented.
  Returntype : boolean
  Exceptions : none
  Caller     : internal

=cut

sub _supported {
  my ($self, $system) = @_;

  #construct the hash of supported features if it has not been already
  unless(exists $self->{_supported}) {
    $self->{_supported} = {};
    foreach my $coord_system ($self->coordinate_systems) {
      $self->{_supported}->{$coord_system} = 1;
    }
  }

  return $self->{_supported}->{$system};
}
  


1;