Skip to content

Commit

Permalink
Merge pull request #223 from cdk/patch/inchitimeout
Browse files Browse the repository at this point in the history
Workaround for timeouts in JNI InChI - default timeout included of 5 …
  • Loading branch information
egonw committed Aug 17, 2016
2 parents 4cdf4eb + 78af7c0 commit bfb3d6c
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 2 deletions.
Expand Up @@ -147,7 +147,7 @@ protected InChIGenerator(IAtomContainer atomContainer, boolean ignoreAromaticBon
protected InChIGenerator(IAtomContainer atomContainer, String options, boolean ignoreAromaticBonds)
throws CDKException {
try {
input = new JniInchiInput(options);
input = new JniInChIInputAdapter(options);
generateInchiFromCDKAtomContainer(atomContainer, ignoreAromaticBonds);
auxNone = input.getOptions() != null && input.getOptions().contains("AuxNone");
} catch (JniInchiException jie) {
Expand All @@ -169,7 +169,7 @@ protected InChIGenerator(IAtomContainer atomContainer, String options, boolean i
protected InChIGenerator(IAtomContainer atomContainer, List<INCHI_OPTION> options, boolean ignoreAromaticBonds)
throws CDKException {
try {
input = new JniInchiInput(options);
input = new JniInChIInputAdapter(options);
generateInchiFromCDKAtomContainer(atomContainer, ignoreAromaticBonds);
auxNone = input.getOptions() != null && input.getOptions().contains("AuxNone");
} catch (JniInchiException jie) {
Expand Down
@@ -0,0 +1,120 @@
/*
* Copyright (c) 2016 John May <jwmay@users.sf.net>
*
* Contact: cdk-devel@lists.sourceforge.net
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at
* your option) any later version. All we ask is that proper credit is given
* for our work, which includes - but is not limited to - adding the above
* copyright notice to the beginning of your source code files, and to any
* copyright notice that you may distribute with programs based on this work.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 U
*/

package org.openscience.cdk.inchi;

import net.sf.jniinchi.INCHI_OPTION;
import net.sf.jniinchi.JniInchiException;
import net.sf.jniinchi.JniInchiInput;

import java.util.List;
import java.util.StringTokenizer;

public class JniInChIInputAdapter extends JniInchiInput {

public static final String FIVE_SECOND_TIMEOUT = "-W5";

public JniInChIInputAdapter(String options) throws JniInchiException {
this.options = options == null ? "" : checkOptions(options);
}

public JniInChIInputAdapter(List<INCHI_OPTION> options) throws JniInchiException {
this.options = options == null ? "" : checkOptions(options);
}

private static boolean isTimeoutOptions(String op) {
if (op == null || op.length() < 2) return false;
int pos = 0;
int len = op.length();
if (op.charAt(pos) == 'W')
pos++;
while (pos < len && Character.isDigit(op.charAt(pos)))
pos++;
if (pos < len && op.charAt(pos) == '.')
pos++;
while (pos < len && Character.isDigit(op.charAt(pos)))
pos++;
return pos == len;
}

private static String checkOptions(final String ops) throws JniInchiException {
if (ops == null) {
throw new IllegalArgumentException("Null options");
}
StringBuilder sbOptions = new StringBuilder();


boolean hasUserSpecifiedTimeout = false;

StringTokenizer tok = new StringTokenizer(ops);
while (tok.hasMoreTokens()) {
String op = tok.nextToken();

if (op.startsWith("-") || op.startsWith("/")) {
op = op.substring(1);
}

INCHI_OPTION option = INCHI_OPTION.valueOfIgnoreCase(op);
if (option != null) {
sbOptions.append('-').append(option.name());
if (tok.hasMoreTokens()) {
sbOptions.append(" ");
}
} else if (isTimeoutOptions(op)) {
sbOptions.append('-').append(op);
hasUserSpecifiedTimeout = true;
if (tok.hasMoreTokens()) {
sbOptions.append(" ");
}
} else {
throw new JniInchiException("Unrecognised InChI option");
}
}

if (!hasUserSpecifiedTimeout) {
if (sbOptions.length() > 0)
sbOptions.append(' ');
sbOptions.append(FIVE_SECOND_TIMEOUT);
}

return sbOptions.toString();
}


private static String checkOptions(List<INCHI_OPTION> ops) throws JniInchiException {
if (ops == null) {
throw new IllegalArgumentException("Null options");
}
StringBuilder sbOptions = new StringBuilder();

for (INCHI_OPTION op : ops) {
sbOptions.append('-').append(op.name()).append(" ");
}

if (sbOptions.length() > 0)
sbOptions.append(' ');
sbOptions.append(FIVE_SECOND_TIMEOUT);

return sbOptions.toString();
}
}
Expand Up @@ -19,10 +19,12 @@
*/
package org.openscience.cdk.inchi;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

import java.util.Collections;
import java.util.concurrent.TimeUnit;

import javax.vecmath.Point2d;
import javax.vecmath.Point3d;
Expand All @@ -38,11 +40,15 @@
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.interfaces.IBond.Order;
import org.openscience.cdk.interfaces.IChemObjectBuilder;
import org.openscience.cdk.interfaces.IDoubleBondStereochemistry;
import org.openscience.cdk.interfaces.IStereoElement;
import org.openscience.cdk.interfaces.ITetrahedralChirality;
import org.openscience.cdk.interfaces.ITetrahedralChirality.Stereo;
import org.openscience.cdk.io.MDLV2000Reader;
import org.openscience.cdk.silent.SilentChemObjectBuilder;
import org.openscience.cdk.smiles.SmilesGenerator;
import org.openscience.cdk.smiles.SmilesParser;
import org.openscience.cdk.stereo.DoubleBondStereochemistry;
import org.openscience.cdk.stereo.ExtendedTetrahedral;
import org.openscience.cdk.stereo.TetrahedralChirality;
Expand Down Expand Up @@ -855,4 +861,16 @@ public void s_penta_2_3_diene_expl_h() throws Exception {

}
}

@Test
public void timeout() throws Exception {
IChemObjectBuilder bldr = SilentChemObjectBuilder.getInstance();
SmilesParser smipar = new SmilesParser(bldr);
String smiles = "C(CCCNC(=N)N)(COCC(COP([O])(=O)OCCCCCCNC(NC1=CC(=C(C=C1)C2(C3=CC=C(C=C3OC=4C2=CC=C(C4)O)O)C)C(=O)[O])=S)OP(=O)([O])OCC(COCC(CCC/[NH]=C(\\[NH])/N)(CCCNC(=N)N)CCCNC(=N)N)OP(=O)([O])OCC(COCC(CCCNC(=N)N)(CCC/[NH]=C(\\[NH])/N)CCCNC(=N)N)OP(OCC(COCC(CCCNC(=N)N)(CCCNC(=N)N)CCC/[NH]=C(\\[NH])/N)OP(=O)([O])OCC(COCC(CCCNC(=N)N)(CCCNC(N)=N)CCC/[NH]=C(/N)\\[NH])OP([O])(=O)CCC(COCC(CCCNC(=N)N)(CCC/[NH]=C(\\[NH])/N)CCCNC(=N)N)OP([O])(=O)OCC(COCC(CCCNC(N)=N)(CCCNC(N)=N)CCC/[NH]=C(\\[NH])/N)OP(OCC(COCC(CCCNC(N)=N)(CCC/[NH]=C(/N)\\[NH])CCCNC(N)=N)O=P([O])(OCC(COP(=OC(COCC(CCC/[NH]=C(\\[NH])/N)(CCCNC(N)=N)CCCNC(N)=N)COP([O])(=O)OC(COP(OC(COCC(CCCNC(=N)N)(CCC/[NH]=C(\\[NH])/N)CCCNC(=N)N)COP(OC(COCC(CCCNC(=N)N)(CCC/[NH]=C(\\[NH])/N)CCCNC(=N)N)COP([O])(=O)OC(COP(OC(COP(OC(COP(=O)([O])OC(COCC(CCC/[NH]=C(/N)\\[NH])(CCCNC(N)=N)CCCNC(=N)N)COP([O])(=O)OCCCCCCNC(NC=5C=CC(=C(C5)C(=O)[O])C6(C7=CC=C(C=C7OC=8C6=CC=C(C8)O)O)C)=S)COCC(CCCNC(N)=N)(CCC/[NH]=C(\\[NH])/N)CCCNC(=N)N)([O])=O)COCC(CCCNC(=N)N)(CCC/[NH]=C(\\[NH])/N)CCCNC(=N)N)([O])=O)COCC(CCCNC(=N)N)(CCCNC(=N)N)CCC/[NH]=C(\\[NH])/N)([O])=O)([O])=O)COCC(CCC/[NH]=C(/N)\\[NH])(CCCNC(=N)N)CCCNC(=N)N)([O])[O])(C)COP(OCCCCCCO)(=O)[O])[O])(=O)[O])([O])=O)(CCC/[NH]=C(\\[NH])/[NH])CCCNC(=N)N";
IAtomContainer mol = smipar.parseSmiles(smiles);
InChIGeneratorFactory inchiFact = InChIGeneratorFactory.getInstance();
InChIGenerator generator = inchiFact.getInChIGenerator(mol, "W0.01");
assertThat(generator.getReturnStatus(), is(INCHI_RET.ERROR));
assertThat(generator.getLog(), containsString("Time limit exceeded"));
}
}

0 comments on commit bfb3d6c

Please sign in to comment.