Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Htsget #1402

Merged
merged 2 commits into from
Oct 2, 2023
Merged

Htsget #1402

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/main/java/org/broad/igv/htsget/HtsgetUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ public static Metadata getMetadata(final String url) throws IOException {
return null;
} else {
String format = json.get("htsget").getAsJsonObject().get("format").getAsString();
// if(!(format.toUpperCase().equals("BAM")) || format.toUpperCase().equals("VCF")) {
// throw new RuntimeException(("Format"))
// }
return new Metadata(url, format);
}
}
Expand Down
105 changes: 38 additions & 67 deletions src/main/java/org/broad/igv/track/TrackLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ public List<Track> load(ResourceLocator locator, Genome genome) throws DataLoadE

log.info("Loading resource: " + (locator.isDataURL() ? "<data url>" : path));
try {

String format = locator.getFormat();

if (format.equals("tbi")) {
Expand All @@ -134,9 +135,23 @@ public List<Track> load(ResourceLocator locator, Genome genome) throws DataLoadE
//This list will hold all new tracks created for this locator
List<Track> newTracks = new ArrayList<Track>();


// Determine track type, if possible, and add new tracks
if (locator.isHtsget()) {
tryHtsget(locator, newTracks, genome);
} else if (format.equals("gmt")) {
HtsgetUtils.Metadata htsgetMeta = HtsgetUtils.getMetadata(locator.getPath());
locator.setFormat(htsgetMeta.getFormat().toLowerCase());
if (htsgetMeta.getFormat().equals("VCF")) {
locator.setHtsget(true);
HtsgetVariantSource source = new HtsgetVariantSource(htsgetMeta, genome);
loadVCFWithSource(locator, source, newTracks);
} else if (htsgetMeta.getFormat().equals("BAM") || htsgetMeta.getFormat().equals("CRAM")) {
locator.setHtsget(true);
loadAlignmentsTrack(locator, newTracks, genome);
} else {
throw new RuntimeException("Format: '" + htsgetMeta.getFormat() + "' is not supported for htsget servers.");
}

} else if (format.equals("gmt")) {
loadGMT(locator);
} else if (format.equals("vcf.list")) {
loadVCFListFile(locator, newTracks, genome);
Expand Down Expand Up @@ -208,33 +223,29 @@ public List<Track> load(ResourceLocator locator, Genome genome) throws DataLoadE
loadMutFile(locator, newTracks, genome); // Must be tried before ".maf" test below
} else if (format.equals("maf")) {
loadMultipleAlignmentTrack(locator, newTracks, genome);
} else {
//if a url, try htsget
boolean isHtsget = tryHtsget(locator, newTracks, genome);
if (!isHtsget) {

// If the file is too large, give up
// TODO -- ftp test
final int tenMB = 10000000;
long fileLength = ParsingUtils.getContentLength(locator.getPath());
if (fileLength > tenMB) {
MessageUtils.confirm("<html>Cannot determine file type of: " + locator.getPath());
}
} else {
// If the file is too large, give up
// TODO -- ftp test
final int tenMB = 10000000;
long fileLength = ParsingUtils.getContentLength(locator.getPath());
if (fileLength > tenMB) {
MessageUtils.confirm("<html>Cannot determine file type of: " + locator.getPath());
}

// Read file contents and try to sort it out
String contents = FileUtils.getContents(locator.getPath());
BufferedReader reader = new BufferedReader(new StringReader(contents));

if (CytoBandFileParser.isValid(reader, locator.getPath())) {
Track track = new CytobandTrack(locator, new BufferedReader(new StringReader(contents)), genome);
newTracks.add(track);
} else if (AttributeManager.isSampleInfoFile(reader)) {
// This might be a sample information file.
AttributeManager.getInstance().loadSampleInfo(locator);
} else {
MessageUtils.showMessage("<html>Unknown file type: " + path + "<br>Check file extension");
}
// Read file contents and try to sort it out
String contents = FileUtils.getContents(locator.getPath());
BufferedReader reader = new BufferedReader(new StringReader(contents));

if (CytoBandFileParser.isValid(reader, locator.getPath())) {
Track track = new CytobandTrack(locator, new BufferedReader(new StringReader(contents)), genome);
newTracks.add(track);
} else if (AttributeManager.isSampleInfoFile(reader)) {
// This might be a sample information file.
AttributeManager.getInstance().loadSampleInfo(locator);
} else {
MessageUtils.showMessage("<html>Unknown file type: " + path + "<br>Check file extension");
}

}

// Track line
Expand Down Expand Up @@ -275,46 +286,6 @@ public List<Track> load(ResourceLocator locator, Genome genome) throws DataLoadE

}

/**
* Try to load as an htsget resource. As most (all?) htsget endpoints use an https:// scheme URL, there is
* no way to detect other than try.
*
* @param locator
* @param newTracks
* @param genome
* @return
*/
private boolean tryHtsget(ResourceLocator locator, List<Track> newTracks, Genome genome) {
boolean isHtsget = false;
if (locator.getPath().startsWith("https://") ||
locator.getPath().startsWith("http://") ||
locator.getPath().startsWith("htsget://")) {
try {
HtsgetUtils.Metadata htsgetMeta = HtsgetUtils.getMetadata(locator.getPath());
if (htsgetMeta != null) {
isHtsget = true;
locator.setFormat(htsgetMeta.getFormat().toLowerCase());
if (htsgetMeta.getFormat().equals("VCF")) {
locator.setHtsget(true);
HtsgetVariantSource source = new HtsgetVariantSource(htsgetMeta, genome);
loadVCFWithSource(locator, source, newTracks);
} else if (htsgetMeta.getFormat().equals("BAM") || htsgetMeta.getFormat().equals("CRAM")) {
locator.setHtsget(true);
loadAlignmentsTrack(locator, newTracks, genome);
} else {
throw new RuntimeException("Format: '" + htsgetMeta.getFormat() + "' is not supported for htsget servers.");
}
}
} catch (IOException e) {
// Not neccessarily an error, might just indicate its not an htsget server. Not sure
// if this should be logged or not, it will be a common and expected occurence when loading
// sample information, which is checked after htsget
return false;
}
}
return isHtsget;
}

public static boolean isAlignmentTrack(String typeString) {
if (typeString == null) {
return false;
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/org/broad/igv/ui/IGVMenuBar.java
Original file line number Diff line number Diff line change
Expand Up @@ -284,10 +284,14 @@ JMenu createFileMenu() {
menuAction.setToolTipText(UIConstants.LOAD_TRACKS_TOOLTIP);
menuItems.add(MenuAndToolbarUtils.createMenuItem(menuAction));

menuAction = new LoadFromServerAction("Load from Server...", KeyEvent.VK_S, igv);
menuAction = new LoadFromServerAction("Load IGV Hosted Tracks...", KeyEvent.VK_S, igv);
menuAction.setToolTipText(UIConstants.LOAD_SERVER_DATA_TOOLTIP);
menuItems.add(MenuAndToolbarUtils.createMenuItem(menuAction));

menuAction = new LoadFromURLMenuAction(LoadFromURLMenuAction.LOAD_FROM_HTSGET, 0, igv);
menuAction.setToolTipText(UIConstants.LOAD_HTSGET_TOOLTOP);
menuItems.add(MenuAndToolbarUtils.createMenuItem(menuAction));

if (PreferencesManager.getPreferences().getAsBoolean(DB_ENABLED)) {
menuAction = new LoadFromDatabaseAction("Load from Database...", 0, igv);
menuItems.add(MenuAndToolbarUtils.createMenuItem(menuAction));
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/org/broad/igv/ui/UIConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public class UIConstants {

// Menu tooltips
static final public String LOAD_TRACKS_TOOLTIP = "Load tracks or sample information";

static final public String LOAD_HTSGET_TOOLTOP = "Load BAM or VCF tracks from an htsget server";
static final public String LOAD_SERVER_DATA_TOOLTIP = "Load tracks or sample information from a server";
static final public String SAVE_PNG_IMAGE_TOOLTIP = "Capture and save a PNG image";
static final public String SAVE_SVG_IMAGE_TOOLTIP = "Capture and save an SVG image";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ public static LinkedHashSet<String> getNodeURLs(String genomeURL) {
nodeURLs = getResourceUrls(bufferedReader);
} catch (IOException e) {
//This is pretty common, if there is no data registry file for the genome the file won't exist
log.error("Error loading genome registry file", e);
//log.error("Error loading genome registry file", e);
log.warn("No data found for current genome.");
} finally {
if (is != null) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public class LoadFromURLMenuAction extends MenuAction {
static Logger log = LogManager.getLogger(LoadFilesMenuAction.class);
public static final String LOAD_FROM_URL = "Load from URL...";
public static final String LOAD_GENOME_FROM_URL = "Load Genome from URL...";
public static final String LOAD_FROM_HTSGET = "Load from htsget Server...";
private IGV igv;

public LoadFromURLMenuAction(String label, int mnemonic, IGV igv) {
Expand All @@ -71,9 +72,10 @@ public void actionPerformed(ActionEvent e) {

JPanel ta = new JPanel();
ta.setPreferredSize(new Dimension(600, 20));
if (e.getActionCommand().equalsIgnoreCase(LOAD_FROM_URL)) {
boolean isHtsGet = e.getActionCommand().equalsIgnoreCase(LOAD_FROM_HTSGET);
if (e.getActionCommand().equalsIgnoreCase(LOAD_FROM_URL) || isHtsGet) {

LoadFromURLDialog dlg = new LoadFromURLDialog(IGV.getInstance().getMainFrame());
LoadFromURLDialog dlg = new LoadFromURLDialog(IGV.getInstance().getMainFrame(), isHtsGet);
dlg.setVisible(true);

if (!dlg.isCanceled()) {
Expand Down Expand Up @@ -114,6 +116,9 @@ public void actionPerformed(ActionEvent e) {
String indexUrl = indexes[i];
rl.setIndexPath(indexUrl);
}
if(isHtsGet) {
rl.setHtsget(true);
}
locators.add(rl);
}
igv.loadTracks(locators);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/broad/igv/ui/action/MenuAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public class MenuAction extends AbstractAction {
public MenuAction(String name, Icon icon, int mnemonic) {
super(name, icon);
if(mnemonic >= 0) {
putValue(MNEMONIC_KEY, new Integer(mnemonic));
putValue(MNEMONIC_KEY, mnemonic);
}
}

Expand Down
88 changes: 47 additions & 41 deletions src/main/java/org/broad/igv/ui/util/LoadFromURLDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@
/**
* @author James Robinson
*/
public class LoadFromURLDialog extends org.broad.igv.ui.IGVDialog {
public class LoadFromURLDialog extends org.broad.igv.ui.IGVDialog {

boolean canceled = false;
String fileURL;
String indexURL;

public LoadFromURLDialog(Frame owner) {
super(owner, "Load from URL");
initComponents();
public LoadFromURLDialog(Frame owner, boolean isHtsget) {
super(owner, isHtsget ? "htsget URL": "Load from URL");
initComponents(isHtsget);
}


Expand Down Expand Up @@ -82,7 +82,7 @@ public String getIndexURL() {
return indexURL;
}

private void initComponents() {
private void initComponents(boolean isHtsget) {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
// Generated using JFormDesigner non-commercial license
dialogPane = new JPanel();
Expand Down Expand Up @@ -112,69 +112,75 @@ private void initComponents() {
{
contentPanel.setBorder(new EmptyBorder(10, 10, 5, 5));
contentPanel.setLayout(new GridBagLayout());
((GridBagLayout)contentPanel.getLayout()).columnWidths = new int[] {0, 0, 0};
((GridBagLayout)contentPanel.getLayout()).rowHeights = new int[] {0, 0, 0, 0, 0, 0, 0};
((GridBagLayout)contentPanel.getLayout()).columnWeights = new double[] {0.0, 0.0, 1.0E-4};
((GridBagLayout)contentPanel.getLayout()).rowWeights = new double[] {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0E-4};
((GridBagLayout) contentPanel.getLayout()).columnWidths = new int[]{0, 0, 0};
((GridBagLayout) contentPanel.getLayout()).rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0};
((GridBagLayout) contentPanel.getLayout()).columnWeights = new double[]{0.0, 0.0, 1.0E-4};
((GridBagLayout) contentPanel.getLayout()).rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0E-4};
contentPanel.add(vSpacer2, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 10, 0), 0, 0));
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 10, 0), 0, 0));

//---- label1 ----
label1.setText("File URL:");
contentPanel.add(label1, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 10, 5), 0, 0));

GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 10, 5), 0, 0));
fileField.setPreferredSize(new Dimension(720, 28));
fileField.setMinimumSize(new Dimension(720, 28));
//---- label2 ----
label2.setText("Index URL:");
contentPanel.add(label2, new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 5), 0, 0));

contentPanel.add(fileField, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 10, 0), 0, 0));
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 10, 0), 0, 0));
contentPanel.add(vSpacer1, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 10, 5), 0, 0));
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 10, 5), 0, 0));
contentPanel.add(vSpacer3, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 10, 5), 0, 0));
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 10, 5), 0, 0));

//---- indexField ----
indexField.setPreferredSize(new Dimension(720, 28));
indexField.setMinimumSize(new Dimension(720, 28));
contentPanel.add(indexField, new GridBagConstraints(1, 5, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0), 0, 0));

//---- label3 ----
label3.setText("<html><i>Specify url to an index file. <b>Required for BAM and indexed files</b></i>");
contentPanel.add(label3, new GridBagConstraints(0, 4, 2, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 10, 0), 0, 0));
if (!isHtsget) {
label2.setText("Index URL:");
contentPanel.add(label2, new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 5), 0, 0));

indexField.setPreferredSize(new Dimension(720, 28));
indexField.setMinimumSize(new Dimension(720, 28));
contentPanel.add(indexField, new GridBagConstraints(1, 5, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0), 0, 0));


//---- label3 ----
label3.setText("<html><i>Specify url to an index file. <b>Required for BAM and indexed files</b></i>");
contentPanel.add(label3, new GridBagConstraints(0, 4, 2, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 10, 0), 0, 0));
}
}
dialogPane.add(contentPanel, BorderLayout.CENTER);

//======== buttonBar ========
{
buttonBar.setLayout(new GridBagLayout());
((GridBagLayout)buttonBar.getLayout()).columnWidths = new int[] {0, 85, 80};
((GridBagLayout)buttonBar.getLayout()).columnWeights = new double[] {1.0, 0.0, 0.0};
((GridBagLayout) buttonBar.getLayout()).columnWidths = new int[]{0, 85, 80};
((GridBagLayout) buttonBar.getLayout()).columnWeights = new double[]{1.0, 0.0, 0.0};

//---- okButton ----
okButton.setText("OK");
okButton.addActionListener(e -> okButtonActionPerformed(e));
buttonBar.add(okButton, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 5), 0, 0));
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 5), 0, 0));

//---- cancelButton ----
cancelButton.setText("Cancel");
cancelButton.addActionListener(e -> cancelButtonActionPerformed(e));
buttonBar.add(cancelButton, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0), 0, 0));
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0), 0, 0));
}
dialogPane.add(buttonBar, BorderLayout.SOUTH);
}
Expand Down
Loading