Skip to content

Commit

Permalink
Genome loading refactor to recover gracefully on startup errors
Browse files Browse the repository at this point in the history
  • Loading branch information
jrobinso committed Sep 2, 2024
1 parent c597d32 commit bbc7989
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 99 deletions.
36 changes: 12 additions & 24 deletions src/main/java/org/broad/igv/feature/genome/Genome.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import org.broad.igv.track.TribbleFeatureSource;
import org.broad.igv.ucsc.Hub;
import org.broad.igv.ucsc.twobit.TwoBitSequence;
import org.broad.igv.util.ParsingUtils;
import org.broad.igv.util.ResourceLocator;
import org.broad.igv.util.liftover.Liftover;

Expand Down Expand Up @@ -242,6 +243,7 @@ public Genome(String id, List<Chromosome> chromosomes) {
chromosomeMap.put(chromosome.getName(), chromosome);
}
this.longChromosomeNames = computeLongChromosomeNames();
this.homeChromosome = this.longChromosomeNames.size() > 1 ? Globals.CHR_ALL : chromosomeNames.get(0);
this.chromAliasSource = (new ChromAliasDefaults(id, chromosomeNames));
}

Expand Down Expand Up @@ -623,18 +625,15 @@ public long getWGLength() {
}


// TODO A hack (obviously), we need to record a species in the genome definitions to support old style
// blat servers.
// Species mapping to support old style blat servers. This should not be needed for current IGV releases.
private static Map<String, String> ucscSpeciesMap;

private static synchronized String getSpeciesForID(String id) {
if (ucscSpeciesMap == null) {
ucscSpeciesMap = new HashMap<>();

InputStream is = null;
try (InputStream is = Genome.class.getResourceAsStream("speciesMapping.txt")) {

try {
is = Genome.class.getResourceAsStream("speciesMapping.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(is));

String nextLine;
Expand All @@ -649,14 +648,7 @@ private static synchronized String getSpeciesForID(String id) {
}
} catch (IOException e) {
log.error("Error reading species mapping table", e);
} finally {
if (is != null) try {
is.close();
} catch (IOException e) {
log.error("", e);
}
}

}

for (Map.Entry<String, String> entry : ucscSpeciesMap.entrySet()) {
Expand Down Expand Up @@ -685,18 +677,6 @@ public List<ResourceLocator> getAnnotationResources() {
return annotationResources;
}

/**
* Mock genome for unit tests
*/

private Genome(String id) {
this.id = id;
}

public boolean getShowWholeGenomeView() {
return showWholeGenomeView;
}

public Map<String, Liftover> getLiftoverMap() {
return liftoverMap;
}
Expand Down Expand Up @@ -809,4 +789,12 @@ public void setHub(Hub hub) {
this.hub = hub;
}

public synchronized static Genome nullGenome() {
if(nullGenome == null) {
nullGenome = new Genome("None", Arrays.asList(new Chromosome(0, "", 0)));
}
return nullGenome;
}

private static Genome nullGenome = null;
}
65 changes: 33 additions & 32 deletions src/main/java/org/broad/igv/feature/genome/GenomeManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -134,21 +134,11 @@ public static File getGenomeFile(String genomePath) throws MalformedURLException
return archiveFile;
}

public void setCurrentGenome(Genome genome) {
if (genome != null) {
PreferencesManager.getPreferences().setLastGenome(genome.getId());
}
// Setter provided for unit tests
public void setCurrentGenomeForTest(Genome genome) {
this.currentGenome = genome;
if (genome != null) {
if (IGV.hasInstance()) {
IGV.getInstance().getSession().clearHistory();
FrameManager.getDefaultFrame().setChromosomeName(genome.getHomeChromosome(), true);
IGVEventBus.getInstance().post(new GenomeChangeEvent(genome));
}
}
}


public void loadGenomeById(String genomeId) throws IOException {
final Genome currentGenome = getCurrentGenome();
if (currentGenome != null && genomeId.equals(currentGenome.getId())) {
Expand Down Expand Up @@ -176,6 +166,8 @@ public void loadGenomeById(String genomeId) throws IOException {
/**
* The main load method -- loads a genome from a file or url path. Note this is a long running operation and
* should not be done on the Swing event thread as it will block the UI.
* <p>
* NOTE: The member 'currentGenome' is set here as a side effect.
*
* @param genomePath
* @return
Expand Down Expand Up @@ -214,26 +206,8 @@ public Genome loadGenome(String genomePath) throws IOException {
IGV.getInstance().resetSession(null);
}

GenomeListItem genomeListItem = new GenomeListItem(newGenome.getDisplayName(), genomePath, newGenome.getId());
final Set<String> serverGenomeIDs = genomeListManager.getServerGenomeIDs();

boolean userDefined = !serverGenomeIDs.contains(newGenome.getId());
genomeListManager.addGenomeItem(genomeListItem, userDefined);

setCurrentGenome(newGenome);

// hasInstance() test needed for unit tests
if (IGV.hasInstance()) {
IGV.getInstance().goToLocus(newGenome.getHomeChromosome()); // newGenome.getDefaultPos());
loadGenomeAnnotations(newGenome);
IGV.getInstance().resetFrames();
}

if (PreferencesManager.getPreferences().getAsBoolean(Constants.CIRC_VIEW_ENABLED) && CircularViewUtilities.ping()) {
CircularViewUtilities.changeGenome(newGenome);
}
setCurrentGenome(genomePath, newGenome);

// log.warn("Genome loaded. id= " + newGenome.getId());
return currentGenome;

} catch (SocketException e) {
Expand All @@ -246,6 +220,33 @@ public Genome loadGenome(String genomePath) throws IOException {
}
}

public void setCurrentGenome(String genomePath, Genome newGenome) {

GenomeListItem genomeListItem = new GenomeListItem(newGenome.getDisplayName(), genomePath, newGenome.getId());
final Set<String> serverGenomeIDs = genomeListManager.getServerGenomeIDs();

boolean userDefined = !serverGenomeIDs.contains(newGenome.getId());
genomeListManager.addGenomeItem(genomeListItem, userDefined);

this.currentGenome = newGenome;

// hasInstance() check to filters unit test
if (IGV.hasInstance()) {
IGV.getInstance().goToLocus(newGenome.getHomeChromosome()); // newGenome.getDefaultPos());
FrameManager.getDefaultFrame().setChromosomeName(newGenome.getHomeChromosome(), true);

loadGenomeAnnotations(newGenome);
IGV.getInstance().resetFrames();
IGV.getInstance().getSession().clearHistory();

PreferencesManager.getPreferences().setLastGenome(newGenome.getId());
if (PreferencesManager.getPreferences().getAsBoolean(Constants.CIRC_VIEW_ENABLED) && CircularViewUtilities.ping()) {
CircularViewUtilities.changeGenome(newGenome);
}
IGVEventBus.getInstance().post(new GenomeChangeEvent(newGenome));
}
}

/**
* Load and initialize the track objects from the genome's track resource locators. Does not add the tracks
* to the IGV instance.
Expand Down Expand Up @@ -458,7 +459,7 @@ private static void updateSequenceMapFile() {
public void refreshHostedGenome(String genomeId) {

Map<String, GenomeListItem> itemMap = GenomeListManager.getInstance().getServerGenomeMap();
if(itemMap.containsKey(genomeId)) {
if (itemMap.containsKey(genomeId)) {
downloadGenome(itemMap.get(genomeId), false);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
import org.broad.igv.logging.Logger;
import org.broad.igv.track.TribbleFeatureSource;
import org.broad.igv.util.FileUtils;
import org.broad.igv.util.HttpUtils;
import org.broad.igv.util.ParsingUtils;
import org.broad.igv.util.ResourceLocator;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
Expand All @@ -35,17 +37,16 @@ public JsonGenomeLoader(String genomePath) {
@Override
public Genome loadGenome() throws IOException {

BufferedReader reader = null;

try {
reader = ParsingUtils.openBufferedReader(genomePath);
String jsonString = ParsingUtils.readContentsAsString(genomePath);
try (InputStream is = ParsingUtils.openInputStream(genomePath + "..")){

String jsonString = ParsingUtils.readContentsFromStream(is);

if (jsonString.contains("chromosomeOrder")) {
jsonString = fixChromosomeOrder(jsonString);
}

GenomeConfig genomeConfig = GenomeConfig.fromJson (jsonString);
GenomeConfig genomeConfig = GenomeConfig.fromJson(jsonString);

fixPaths(genomeConfig);

Expand All @@ -68,8 +69,6 @@ public Genome loadGenome() throws IOException {

return genome;

} finally {
reader.close();
}
}

Expand Down Expand Up @@ -168,10 +167,9 @@ private void addToFeatureDB(List<ResourceLocator> locators, Genome genome) {
}

private String stripQuotes(String str) {
if(str.startsWith("\"")) {
if (str.startsWith("\"")) {
return str.substring(1, str.length() - 1); // Assume also ends with
}
else {
} else {
return str;
}
}
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/org/broad/igv/track/SequenceTrack.java
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,12 @@ public void load(ReferenceFrame referenceFrame) {
end = Math.min(end + w / 2 + 2, chromosomeLength);

Genome genome = currentGenome;
String sequence = new String(genome.getSequence(chr, start, end));
byte [] seqBytes = genome.getSequence(chr, start, end);
if(seqBytes == null) {
return;

}
String sequence = new String(seqBytes);

int mod = start % 3;
int n1 = normalize3(3 - mod);
Expand Down
30 changes: 17 additions & 13 deletions src/main/java/org/broad/igv/ui/IGV.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@
import org.broad.igv.session.autosave.SessionAutosaveManager;
import org.broad.igv.track.*;
import org.broad.igv.ui.WaitCursorManager.CursorToken;
import org.broad.igv.ui.commandbar.GenomeListManager;
import org.broad.igv.ui.dnd.GhostGlassPane;
import org.broad.igv.ui.panel.*;
import org.broad.igv.ui.util.*;
Expand Down Expand Up @@ -1942,21 +1941,26 @@ public void run() {
} catch (Exception e) {
MessageUtils.showErrorMessage("Error loading genome " + genomeId + "<br/>" + e.getMessage(), e);
genomeLoaded = false;
}
}

if (!genomeLoaded) {
// If the error is with the default genome try refreshing it.
if(genomeId.equals(GenomeListManager.DEFAULT_GENOME.getId())) {
GenomeManager.getInstance().refreshHostedGenome(genomeId);
}
Genome genome = Genome.nullGenome();
GenomeManager.getInstance().setCurrentGenome("", genome);

genomeId = GenomeListManager.DEFAULT_GENOME.getId();
try {
GenomeManager.getInstance().loadGenomeById(genomeId);
} catch (IOException e) {
MessageUtils.showErrorMessage("Error loading genome: " + genomeId, e);
log.error("Error loading genome: " + genomeId, e);
}

//GenomeManager.getInstance().setCurrentGenome(Genome.NoneGenome());
// If the error is with the default genome try refreshing it.
// if(genomeId.equals(GenomeListManager.DEFAULT_GENOME.getId())) {
// GenomeManager.getInstance().refreshHostedGenome(genomeId);
// }
//
// genomeId = GenomeListManager.DEFAULT_GENOME.getId();
// try {
// GenomeManager.getInstance().loadGenomeById(genomeId);
// } catch (IOException e) {
// MessageUtils.showErrorMessage("Error loading genome: " + genomeId, e);
// log.error("Error loading genome: " + genomeId, e);
// }
}
}

Expand Down
30 changes: 18 additions & 12 deletions src/main/java/org/broad/igv/ui/commandbar/IGVCommandBar.java
Original file line number Diff line number Diff line change
Expand Up @@ -180,24 +180,30 @@ public void selectGenome(String genomeId) {
public void updateCurrentCoordinates() {

if (IGV.hasInstance()) {
String p = "";
ReferenceFrame defaultFrame = FrameManager.getDefaultFrame();
final String chrName = defaultFrame.getChrName();
if (!Globals.CHR_ALL.equals(chrName) && !FrameManager.isGeneListMode()) {
p = defaultFrame.getFormattedLocusString();
}
final String position = p;
final History history = IGV.getInstance().getSession().getHistory();

UIUtilities.invokeOnEventThread(new Runnable() {
public void run() {
if(GenomeManager.getInstance().getCurrentGenome() == Genome.nullGenome()) {
UIUtilities.invokeOnEventThread(() -> {
searchTextField.setText("");
});

} else {
String p = "";
ReferenceFrame defaultFrame = FrameManager.getDefaultFrame();
final String chrName = defaultFrame.getChrName();
if (!Globals.CHR_ALL.equals(chrName) && !FrameManager.isGeneListMode()) {
p = defaultFrame.getFormattedLocusString();
}
final String position = p;
final History history = IGV.getInstance().getSession().getHistory();

UIUtilities.invokeOnEventThread(() -> {
searchTextField.setText(position);
forwardButton.setEnabled(history.canGoForward());
backButton.setEnabled(history.canGoBack());
roiToggleButton.setEnabled(!Globals.CHR_ALL.equals(chrName));
zoomControl.setEnabled(!Globals.CHR_ALL.equals(chrName) && !FrameManager.isGeneListMode());
}
});
});
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/broad/igv/ui/panel/ZoomSliderPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public ZoomSliderPanel(ReferenceFrame referenceFrame) {
}

private void updateTickCount() {
int tmp = getReferenceFrame().getMaxZoom() + 1;
int tmp = Math.max(0, getReferenceFrame().getMaxZoom() + 1);
if (tmp != numZoomLevels) {
numZoomLevels = tmp;
zoomLevelRects = new Rectangle[numZoomLevels];
Expand Down
4 changes: 0 additions & 4 deletions src/main/java/org/broad/igv/util/ParsingUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,6 @@ public static String readContentsFromStream(InputStream is) throws IOException {
return new String(bytes, "UTF-8");
}

public static String readContentsAsString(String path) throws IOException {
return readContentsFromStream(openInputStream(path));
}

/**
* Parse the string and return the result as an integer. This method supports scientific notation for integers,
* which Integer.parseInt() does not.
Expand Down
4 changes: 2 additions & 2 deletions src/test/java/org/broad/igv/AbstractHeadlessTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,14 @@ public class AbstractHeadlessTest {
@BeforeClass
public static void setUpClass() throws Exception {
setUpHeadless();
GenomeManager.getInstance().setCurrentGenome(null);
GenomeManager.getInstance().setCurrentGenomeForTest(null);
genome = TestUtils.loadGenome();
}

@AfterClass
public static void tearDownClass() throws Exception {
TestUtils.clearOutputDir();
GenomeManager.getInstance().setCurrentGenome(null);
GenomeManager.getInstance().setCurrentGenomeForTest(null);
}

@Before
Expand Down

0 comments on commit bbc7989

Please sign in to comment.