Skip to content

Commit

Permalink
Upate to htsjdk 4.0.2
Browse files Browse the repository at this point in the history
Htsjdk added a new NamedFeature interface that is clashing with IGV's slightly different NamedFeature.
Renamed NamedFeature -> IGVNamedFeature
Slight change to IGVFeatureReader interface to make it return a CloseableIterator so that it can be handled with try-with-resources.
  • Loading branch information
lbergelson committed Oct 31, 2023
1 parent 11b0971 commit 0331f6e
Show file tree
Hide file tree
Showing 16 changed files with 70 additions and 103 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ dependencies {
[group: 'org.xerial.snappy', name: 'snappy-java', version: '1.1.7.3'],
[group: 'org.apache.commons', name: 'commons-jexl', version: '2.1.1'],
[group: 'org.apache.commons', name: 'commons-lang3', version: '3.9'],
[group: 'com.github.samtools', name: 'htsjdk', version: '3.0.5'],
[group: 'com.github.samtools', name: 'htsjdk', version: '4.0.2'],
[group: 'org.swinglabs', name: 'swing-layout', version: '1.0.3'],
[group: 'com.formdev', name: 'jide-oss', version: '3.7.12'],
[group: 'com.google.guava', name: 'guava', version: '27.0.1-jre'],
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/broad/igv/feature/Cytoband.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
package org.broad.igv.feature;


public class Cytoband implements NamedFeature {
public class Cytoband implements IGVNamedFeature {
String chromosome;
String name;
String longName;
Expand Down
44 changes: 22 additions & 22 deletions src/main/java/org/broad/igv/feature/FeatureDB.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ public class FeatureDB {
/**
* Map for all features other than genes.
*/
//private static Map<String, NamedFeature> featureMap = new HashMap(10000);
private static Map<String, List<NamedFeature>> featureMap = Collections.synchronizedSortedMap(new TreeMap<String, List<NamedFeature>>());
//private static Map<String, IGVNamedFeature> featureMap = new HashMap(10000);
private static Map<String, List<IGVNamedFeature>> featureMap = Collections.synchronizedSortedMap(new TreeMap<String, List<IGVNamedFeature>>());
private static final int MAX_DUPLICATE_COUNT = 20;

public static void addFeature(NamedFeature feature, Genome genome) {
public static void addFeature(IGVNamedFeature feature, Genome genome) {

final String name = feature.getName();
if (name != null && name.length() > 0 && !name.equals(".")) {
Expand All @@ -81,7 +81,7 @@ public static void addFeature(NamedFeature feature, Genome genome) {
}
}

public static void removeFeature(NamedFeature feature, Genome genome) {
public static void removeFeature(IGVNamedFeature feature, Genome genome) {

final String name = feature.getName();
if (name != null && name.length() > 0 && !name.equals(".")) {
Expand Down Expand Up @@ -134,7 +134,7 @@ private static void removeByAttributes(IGVFeature igvFeature, Genome genome) {
* @param genome The genome which these features belong to. Used for checking chromosomes
* @return true if successfully added, false if not
*/
static boolean put(String name, NamedFeature feature, Genome genome) {
static boolean put(String name, IGVNamedFeature feature, Genome genome) {
String key = name.toUpperCase();
if (!Globals.isHeadless()) {
Genome currentGenome = genome != null ? genome : GenomeManager.getInstance().getCurrentGenome();
Expand All @@ -144,9 +144,9 @@ static boolean put(String name, NamedFeature feature, Genome genome) {
}

synchronized (featureMap) {
List<NamedFeature> currentList = featureMap.get(key);
List<IGVNamedFeature> currentList = featureMap.get(key);
if (currentList == null) {
List<NamedFeature> newList = new SortedList<NamedFeature>(
List<IGVNamedFeature> newList = new SortedList<IGVNamedFeature>(
new ArrayList<>(), FeatureComparator.get(true));
boolean added = newList.add(feature);
if (added) {
Expand All @@ -170,7 +170,7 @@ static boolean put(String name, NamedFeature feature, Genome genome) {
Genome currentGenome = GenomeManager.getInstance().getCurrentGenome();
if (currentGenome == null || currentGenome.getChromosome(feature.getChr()) != null) {
NamedFeature currentFeature = featureMap.get(key);
IGVNamedFeature currentFeature = featureMap.get(key);
if (currentFeature == null) {
featureMap.put(key, feature);
} else {
Expand Down Expand Up @@ -200,7 +200,7 @@ static boolean put(String name, NamedFeature feature, Genome genome) {
*/


public static void addFeature(String name, NamedFeature feature, Genome genome) {
public static void addFeature(String name, IGVNamedFeature feature, Genome genome) {
put(name.toUpperCase(), feature, genome);
}

Expand Down Expand Up @@ -228,9 +228,9 @@ static int size() {
/**
* Return a feature with the given name.
*/
public static NamedFeature getFeature(String name) {
public static IGVNamedFeature getFeature(String name) {
String nm = name.trim().toUpperCase();
List<NamedFeature> features = featureMap.get(nm);
List<IGVNamedFeature> features = featureMap.get(nm);

if (features != null) {
return features.get(0);
Expand All @@ -255,9 +255,9 @@ public static NamedFeature getFeature(String name) {
* string will be found.
* @return
*/
static Map<String, List<NamedFeature>> getFeaturesMap(String name) {
static Map<String, List<IGVNamedFeature>> getFeaturesMap(String name) {
String nm = name.trim().toUpperCase();
SortedMap<String, List<NamedFeature>> treeMap = (SortedMap) featureMap;
SortedMap<String, List<IGVNamedFeature>> treeMap = (SortedMap) featureMap;
//Search is inclusive to first argument, exclusive to second
return treeMap.subMap(nm, nm + Character.MAX_VALUE);
}
Expand All @@ -270,7 +270,7 @@ static Map<String, List<NamedFeature>> getFeaturesMap(String name) {
* @return
* @see #getFeaturesList(String, int, boolean)
*/
public static List<NamedFeature> getFeaturesList(String name, int limit) {
public static List<IGVNamedFeature> getFeaturesList(String name, int limit) {
return getFeaturesList(name, limit, true);
}

Expand All @@ -283,18 +283,18 @@ public static List<NamedFeature> getFeaturesList(String name, int limit) {
* @param longestOnly Whether to take only the longest feature for each name
* @return
*/
public static List<NamedFeature> getFeaturesList(String name, int limit, boolean longestOnly) {
public static List<IGVNamedFeature> getFeaturesList(String name, int limit, boolean longestOnly) {

//Note: We are iterating over submap, this needs
//to be synchronized over the main map.
synchronized (featureMap) {
Map<String, List<NamedFeature>> resultMap = getFeaturesMap(name);
Map<String, List<IGVNamedFeature>> resultMap = getFeaturesMap(name);
Set<String> names = resultMap.keySet();
Iterator<String> nameIter = names.iterator();
ArrayList<NamedFeature> features = new ArrayList<NamedFeature>((Math.min(limit, names.size())));
ArrayList<IGVNamedFeature> features = new ArrayList<IGVNamedFeature>((Math.min(limit, names.size())));
int ii = 0;
while (nameIter.hasNext() && ii < limit) {
List<NamedFeature> subFeats = resultMap.get(nameIter.next());
List<IGVNamedFeature> subFeats = resultMap.get(nameIter.next());
if (longestOnly) {
features.add(subFeats.get(0));
} else {
Expand Down Expand Up @@ -328,11 +328,11 @@ public static Map<Integer, BasicFeature> getMutationAA(String name, int proteinP
}

Map<Integer, BasicFeature> results = new HashMap<Integer, BasicFeature>();
List<NamedFeature> possibles = featureMap.get(nm);
List<IGVNamedFeature> possibles = featureMap.get(nm);

if (possibles != null) {
synchronized (featureMap) {
for (NamedFeature f : possibles) {
for (IGVNamedFeature f : possibles) {
if (!(f instanceof BasicFeature)) {
continue;
}
Expand Down Expand Up @@ -381,13 +381,13 @@ public static Map<Integer, BasicFeature> getMutationNT(String name, int startPos
}

Map<Integer, BasicFeature> results = new HashMap<Integer, BasicFeature>();
List<NamedFeature> possibles = featureMap.get(nm);
List<IGVNamedFeature> possibles = featureMap.get(nm);
String tempNT;
String brefNT = refNT.toUpperCase();

if (possibles != null) {
synchronized (featureMap) {
for (NamedFeature f : possibles) {
for (IGVNamedFeature f : possibles) {
if (!(f instanceof BasicFeature)) {
continue;
}
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/org/broad/igv/feature/IGVFeature.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,12 @@
import java.awt.*;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
* Interface for features in IGV annotation tracks (FeatureTrack and derived classes).
*/

public interface IGVFeature extends LocusScore, NamedFeature {
public interface IGVFeature extends LocusScore, IGVNamedFeature {

default String getIdentifier() {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,11 @@

package org.broad.igv.feature;

import htsjdk.tribble.Feature;

/**
* @author jrobinso
* @date Sep 16, 2010
*/
public interface NamedFeature extends Feature {
public interface IGVNamedFeature extends htsjdk.tribble.NamedFeature {

String getName();

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/broad/igv/feature/Locus.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
/**
* @author jrobinso
*/
public class Locus extends Range implements NamedFeature {
public class Locus extends Range implements IGVNamedFeature {

private static NumberFormat NUMBER_FORMAT = NumberFormat.getInstance(Locale.US);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
import htsjdk.tribble.CloseableTribbleIterator;
import htsjdk.tribble.Feature;
import htsjdk.tribble.FeatureReader;
import org.broad.igv.feature.IGVNamedFeature;
import org.broad.igv.logging.*;
import org.broad.igv.Globals;
import org.broad.igv.feature.CytoBandFileParser;
import org.broad.igv.feature.FeatureDB;
import org.broad.igv.feature.NamedFeature;
import org.broad.igv.feature.genome.Genome;
import org.broad.igv.feature.genome.fasta.FastaBlockCompressedSequence;
import org.broad.igv.feature.genome.fasta.FastaIndexedSequence;
Expand All @@ -26,8 +26,6 @@

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

public class JsonGenomeLoader extends GenomeLoader {
Expand Down Expand Up @@ -288,8 +286,8 @@ private void addToFeatureDB(List<ResourceLocator> locators, Genome genome) {
CloseableTribbleIterator<Feature> iter = featureReader.iterator();
while (iter.hasNext()) {
Feature f = iter.next();
if (f instanceof NamedFeature) {
FeatureDB.addFeature((NamedFeature) f, genome);
if (f instanceof IGVNamedFeature) {
FeatureDB.addFeature((IGVNamedFeature) f, genome);
}
}
} catch (IOException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@



import htsjdk.samtools.util.CloseableIterator;
import htsjdk.tribble.Feature;
import htsjdk.tribble.index.Index;

Expand All @@ -49,7 +50,7 @@ public interface IGVFeatureReader {

public Iterator<Feature> query(final String chr, final int start, final int end) throws IOException;

public Iterator<Feature> iterator() throws IOException;
public CloseableIterator<Feature> iterator() throws IOException;

public List<String> getSequenceNames();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

package org.broad.igv.feature.tribble;

import htsjdk.samtools.util.CloseableIterator;
import htsjdk.tribble.*;
import htsjdk.tribble.index.Index;
import htsjdk.tribble.index.IndexFactory;
Expand Down Expand Up @@ -54,9 +55,7 @@ public TribbleReaderWrapper(FeatureReader<Feature> wrappedReader) {
public synchronized Iterator<Feature> query(String chr, int start, int end) throws IOException {

// Tribble iterators must be closed, so we need to copy the features and insure closure before exiting.
CloseableTribbleIterator<Feature> iter = null;
try {
iter = wrappedReader.query(chr, start + 1, end);
try (CloseableTribbleIterator<Feature> iter = wrappedReader.query(chr, start + 1, end)) {
List<Feature> featureList = new ArrayList<Feature>();
while (iter.hasNext()) {
Feature f = iter.next();
Expand All @@ -69,13 +68,11 @@ public synchronized Iterator<Feature> query(String chr, int start, int end) thro
}
}
return featureList.iterator();
} finally {
if(iter != null) iter.close();
}
}

@Override
public Iterator<Feature> iterator() throws IOException {
public CloseableIterator<Feature> iterator() throws IOException {
// Note: Technically this is a file handle leak as the "close" method of the tribble iterator is not called.
// In practice this is not a problem as the iterator() method is only called by batch programs transversing
// the entire file. It is none-the-less a file handle leak that should be addressed at some point.
Expand Down
26 changes: 6 additions & 20 deletions src/main/java/org/broad/igv/track/TribbleFeatureSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

package org.broad.igv.track;

import htsjdk.samtools.util.CloseableIterator;
import htsjdk.tribble.*;
import htsjdk.tribble.index.Index;
import org.broad.igv.Globals;
Expand Down Expand Up @@ -332,45 +333,30 @@ private NonIndexedFeatureSource(AbstractFeatureReader basicReader, FeatureCodec
super(basicReader, codec, genome);

featureMap = new HashMap<>(25);
Iterator<Feature> iter = null;

try {
iter = reader.iterator();
try (CloseableIterator<Feature> iter = reader.iterator()) {
while (iter.hasNext()) {
Feature f = iter.next();
if (f == null) continue;

String seqName = f.getChr();
String igvChr = genome == null ? seqName : genome.getCanonicalChrName(seqName);

List<Feature> featureList = featureMap.get(igvChr);
if (featureList == null) {
featureList = new ArrayList();
featureMap.put(igvChr, featureList);
}
List<Feature> featureList = featureMap.computeIfAbsent(igvChr, k -> new ArrayList<>());
featureList.add(f);
if (f instanceof org.broad.igv.feature.NamedFeature) FeatureDB.addFeature((org.broad.igv.feature.NamedFeature) f, genome);
if (f instanceof IGVNamedFeature named) FeatureDB.addFeature(named, genome);

if (this.isVCF && f instanceof Variant) {
Variant v = (Variant) f;
if (this.isVCF && f instanceof Variant v) {
String chr2 = v.getAttributeAsString("CHR2");
String pos2 = v.getAttributeAsString("END");
if (chr2 != null && pos2 != null) {
String mateChr = genome == null ? chr2 : genome.getCanonicalChrName(chr2);
MateVariant mate = new MateVariant(mateChr, Integer.parseInt(pos2), v);
featureList = featureMap.get(mateChr);
if (featureList == null) {
featureList = new ArrayList();
featureMap.put(mateChr, featureList);
}
featureList = featureMap.computeIfAbsent(mateChr, k -> new ArrayList<>());
featureList.add(mate);
}
}
}
} finally {
if (iter instanceof CloseableTribbleIterator) {
((CloseableTribbleIterator) iter).close();
}
}

for (List<Feature> featureList : featureMap.values()) {
Expand Down
Loading

0 comments on commit 0331f6e

Please sign in to comment.