Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,7 @@ private void parseCathDomall(BufferedReader bufferedReader) throws IOException{

protected void downloadFileFromRemote(URL remoteURL, File localFile) throws IOException{
// System.out.println("downloading " + remoteURL + " to: " + localFile);
LOGGER.info("Downloaded file {} to local file {}", remoteURL, localFile);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be "Downloading"? It isn't downloaded at this point yet

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


long timeS = System.currentTimeMillis();
File tempFile = File.createTempFile(FileDownloadUtils.getFilePrefix(localFile), "."+ FileDownloadUtils.getFileExtension(localFile));
Expand Down Expand Up @@ -665,7 +666,7 @@ protected void downloadFileFromRemote(URL remoteURL, File localFile) throws IOEx
disp = disp / 1024.0;
}
long timeE = System.currentTimeMillis();
LOGGER.info("Downloaded file {} ({}) to local file {} in {} sec.", remoteURL, String.format("%.1f",disp) + unit, localFile, (timeE - timeS)/1000);
LOGGER.info("Downloaded {} in {} sec. to {}", String.format("%.1f",disp) + unit, (timeE - timeS)/1000, localFile);
}

private boolean domainDescriptionFileAvailable(){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ public static enum FetchBehavior {

protected static final String lineSplit = System.getProperty("file.separator");

/** Minimum size for a valid structure file (CIF or PDB), in bytes */
public static final long MIN_PDB_FILE_SIZE = 40; // Empty gzip files are 20bytes. Add a few more for buffer.

private File path;
private List<String> extensions;

Expand Down Expand Up @@ -687,6 +690,14 @@ public File getLocalFile(String pdbId) {
for(String ex : getExtensions() ){
File f = new File(searchdir,prefix + pdbId.toLowerCase() + ex) ;
if ( f.exists()) {
// delete files that are too short to have contents
if( f.length() < MIN_PDB_FILE_SIZE ) {
boolean success = f.delete();
if( ! success) {
return null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this rather throw an exception (perhaps IOException)? I don't see how can this null be handled if file can't be deleted.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

switched to Files.delete which throws the exception

}
assert(!f.exists());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather log a warning here. Assert is going to be ignored in normal situations

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's intended. If the delete was successful then the file will not exist. This is just a sanity check during development to make sure delete() wasn't asynchronous or something.

}
return f;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,8 @@ public static ChemComp getChemComp(String recordName){
* again. Note that this change can have unexpected behavior of
* code executed afterwards.
* <p>
* Changing the provider does not reset the cache, so Chemical
* Component definitions already downloaded from previous providers
* will be used. To reset the cache see {@link #getCache()).
* Changing the provider also resets the cache, so any groups
* previously accessed will be re-downloaded and reread.
*
* @param provider
*/
Expand All @@ -84,6 +83,13 @@ public static void setChemCompProvider(ChemCompProvider provider) {
public static ChemCompProvider getChemCompProvider(){
return chemCompProvider;
}

/**
* Force the cache to be reset.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This clears the memory cache, right? Could you add that to javadoc, it's an important detail since there is both memory and file cache

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only memory. Documented.

*/
public static void clearCache() {
cache.clear();
}

public static Group getGroupFromChemCompDictionary(String recordName) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.biojava.nbio.core.util.InputStreamProvider;
import org.biojava.nbio.structure.align.util.HTTPConnectionTools;
import org.biojava.nbio.structure.align.util.UserConfiguration;
import org.biojava.nbio.structure.io.LocalPDBDirectory;
import org.biojava.nbio.structure.io.mmcif.model.ChemComp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -85,6 +86,8 @@ public class DownloadChemCompProvider implements ChemCompProvider {
protectedIDs.add("AUX");
protectedIDs.add("NUL");
}

private static ChemCompProvider fallback = null; // Fallback provider if the download fails

/** by default we will download only some of the files. User has to request that all files should be downloaded...
*
Expand Down Expand Up @@ -272,7 +275,10 @@ public ChemComp getChemComp(String recordName) {

ChemComp chemComp = dict.getChemComp(recordName);

return chemComp;
// May be null if the file was corrupt. Fall back on ReducedChemCompProvider in that case
if(chemComp != null) {
return chemComp;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a small change in behavior. If we can't read the downloaded chemcomp file, we now return a stub chemcomp rather than NULL. Previously the stub was returned for corrupt GZIP files (which threw an error) but not for malformed cif contents (which just returned null).

}

} catch (IOException e) {

Expand All @@ -296,9 +302,11 @@ public ChemComp getChemComp(String recordName) {

// see https://github.com/biojava/biojava/issues/315
// probably a network error happened. Try to use the ReducedChemCOmpProvider
ReducedChemCompProvider reduced = new ReducedChemCompProvider();
if( fallback == null) {
fallback = new ReducedChemCompProvider();

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

creating a ReducedChemCompProvider is cheap (and idempotent), but let's cache it anyways.

}

return reduced.getChemComp(recordName);
return fallback.getChemComp(recordName);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a warning logged when the fallback is used? That'd be important, so that users are aware and can investigate if there's something wrong in their code or file system

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea.


}

Expand Down Expand Up @@ -337,6 +345,12 @@ private static boolean fileExists(String recordName){

File f = new File(fileName);

// delete files that are too short to have contents
if( f.length() < LocalPDBDirectory.MIN_PDB_FILE_SIZE ) {
f.delete();
return false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the file fails to be deleted, this won't work as expected. I think the fail to delete case should throw an IOException

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't check the status because the delete isn't really necessary here. If this method returns false then we re-download the file and move it on top of the old one. I just added the delete defensively.

}

return f.exists();

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,13 @@ public void newAtomSite(AtomSite atom) {

String recordName = atom.getGroup_PDB();
String residueNumberS = atom.getAuth_seq_id();
Integer residueNrInt = Integer.parseInt(residueNumberS);
Integer residueNrInt;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you handle this in a separate pull request? as per discussion in #775

if(residueNumberS != null) {
residueNrInt = Integer.parseInt(residueNumberS);
} else {
String label_seq_id = atom.getLabel_seq_id();
residueNrInt = Integer.parseInt(label_seq_id);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

label_seq_id is not the same as residue number. This can introduce many problems.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should discuss this further.

I added it because the atp.cif.gz file I added (from pymol) has label_seq_id but not auth_seq_id. It seems reasonable to me to fall back on the sequential numbering if the authors don't specify a custom numbering.

Note that auth_seq_id is optional but label_seq_id is required. From the spec it sounds to me like label_seq_id is a good fallback for ResidueNumber:

_atom_site.auth_seq_id:

An alternative identifier for _atom_site.label_seq_id that
may be provided by an author in order to match the identification
used in the publication that describes the structure.

Ideally BioJava would use Group.getId() rather then getResidueNumber() everywhere. However, many things still use residue numbers, so setting a default seems prudent.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's another potential issue here, which is that the seq_id is stored as a long while ResidueNumber contains an Integer. I don't think there are any files with >2billion groups per entity, but if we hit it then the ResidueNumber would throw a NumberFormatException here. I think that's fine.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started #775 to continue this discussion.

}

// the 3-letter name of the group:
String groupCode3 = atom.getLabel_comp_id();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,9 @@ public void parse(BufferedReader buf)

// the first line is a data_PDBCODE line, test if this looks like a mmcif file
line = buf.readLine();
while( line != null && (line.isEmpty() || line.startsWith(COMMENT_CHAR))) {
line = buf.readLine();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice to handle comments in first line!

Is an empty first line also valid CIF?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think blank lines are permitted anywhere in CIF, but I could be wrong. I try to write permissive parsers. It seems like it shouldn't break the spec so we might as well be robust to it either way.

if (line == null || !line.startsWith(MMCIF_TOP_HEADER)){
logger.error("This does not look like a valid mmCIF file! The first line should start with 'data_', but is: '" + line+"'");
triggerDocumentEnd();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@
*/
package org.biojava.nbio.structure.io.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
Expand All @@ -36,6 +33,15 @@
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FileDownloadUtils {

Expand Down Expand Up @@ -240,6 +246,41 @@ public static URLConnection prepareURLConnection(String url, int timeout) throws
connection.setConnectTimeout(timeout);
return connection;
}

/**
* Recursively delete a folder & contents
*
* @param dir directory to delete
*/
public static void deleteDirectory(Path dir) throws IOException {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surprisingly this isn't an nio method and I couldn't find one in BioJava

if(dir == null || !Files.exists(dir))
return;
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException {
if (e != null) {
throw e;
}
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
}
/**
* Recursively delete a folder & contents
*
* @param dir directory to delete
*/
public static void deleteDirectory(String dir) throws IOException {
deleteDirectory(Paths.get(dir));
}


public static void main(String[] args) {
String url;
Expand Down
Loading