package jalview.datamodel.xdb.embl;
import jalview.analysis.SequenceIdMatcher;
+import jalview.bin.Cache;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.DBRefSource;
import jalview.datamodel.FeatureProperties;
import jalview.util.MappingUtils;
import jalview.util.StringUtils;
+import java.text.ParseException;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
}
/**
- * Returns the CDS positions as a list of [start, end, start, end...]
+ * Returns the CDS positions as a single array of [start, end, start, end...]
* positions. If on the reverse strand, these will be in descending order.
*
* @param feature
{
return new int[] {};
}
- List<int[]> ranges = DnaUtils.parseLocation(feature.location);
- return ranges == null ? new int[] {} : listToArray(ranges);
+
+ try
+ {
+ List<int[]> ranges = DnaUtils.parseLocation(feature.location);
+ return listToArray(ranges);
+ } catch (ParseException e)
+ {
+ Cache.log.warn(String.format(
+ "Not parsing inexact CDS location %s in ENA %s",
+ feature.location, this.accession));
+ return new int[] {};
+ }
}
/**
package jalview.util;
+import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Parses an ENA/GenBank format location specifier and returns a list of
- * [start, end] ranges. Returns null if not able to parse.
+ * [start, end] ranges. Throws an exception if not able to parse.
+ * <p>
+ * Currently we do not parse "order()" specifiers, or indeterminate ranges of
+ * the format "<start..end" or "start..>end" or "start.end" or
+ * "start^end"
*
* @param location
* @return
+ * @throws ParseException
+ * if unable to parse the location (the exception message is the
+ * location specifier being parsed); we use ParseException in
+ * preference to the unchecked IllegalArgumentException
* @see http://www.insdc.org/files/feature_table.html#3.4
*/
public static List<int[]> parseLocation(String location)
+ throws ParseException
{
if (location.startsWith("join("))
{
{
return parseComplement(location);
}
- String errorMessage = "Unable to process location specifier: "
- + location;
if (location.startsWith("order("))
{
- System.err.println(errorMessage);
- return null;
+ throw new ParseException(location, 0);
}
/*
/*
* could be a location like <1..888 or 1..>888
*/
- System.err.println(errorMessage);
- return null;
+ throw new ParseException(location, 0);
}
}
else
/*
* could be a location like 102.110 or 123^124
*/
- System.err.println(errorMessage);
- return null;
+ throw new ParseException(location, 0);
}
}
*
* @param location
* @return
+ * @throws ParseException
*/
- static List<int[]> parseComplement(String location)
+ static List<int[]> parseComplement(String location) throws ParseException
{
/*
* take what is inside complement()
*/
if (!location.endsWith(")"))
{
- return null;
+ throw new ParseException(location, 0);
}
String toComplement = location.substring("complement(".length(),
location.length() - 1);
List<int[]> ranges = parseLocation(toComplement);
- if (ranges == null)
- {
- /*
- * something bad in there
- */
- return null;
- }
/*
* reverse the order and direction of ranges
*
* @param location
* @return
+ * @throws ParseException
*/
- static List<int[]> parseJoin(String location)
+ static List<int[]> parseJoin(String location) throws ParseException
{
List<int[]> ranges = new ArrayList<int[]>();
*/
if (!location.endsWith(")"))
{
- return null;
+ throw new ParseException(location, 0);
}
String joinedLocs = location.substring("join(".length(),
location.length() - 1);
for (String loc : locations)
{
List<int[]> range = parseLocation(loc);
- if (range == null)
- {
- /*
- * something bad in there
- */
- return null;
- }
- else
- {
- ranges.addAll(range);
- }
+ ranges.addAll(range);
}
return ranges;
}
import static org.testng.AssertJUnit.assertNull;
import static org.testng.AssertJUnit.fail;
+import java.text.ParseException;
import java.util.List;
import org.testng.annotations.Test;
/**
* Tests for parsing an ENA/GenBank location specifier
*
+ * @throws ParseException
+ *
* @see http://www.insdc.org/files/feature_table.html#3.4
*/
@Test(groups = { "Functional" })
- public void testParseLocation()
+ public void testParseLocation() throws ParseException
{
/*
* single locus
assertEquals(87064, ranges.get(1)[1]);
/*
- * beyond 5' or 3' locus
- */
- ranges = DnaUtils.parseLocation("<34..126");
- assertEquals(1, ranges.size());
- assertEquals(34, ranges.get(0)[0]);
- assertEquals(126, ranges.get(0)[1]);
- ranges = DnaUtils.parseLocation("35..>127");
- assertEquals(1, ranges.size());
- assertEquals(35, ranges.get(0)[0]);
- assertEquals(127, ranges.get(0)[1]);
-
- /*
* valid things we don't yet handle
*/
- assertNull(DnaUtils.parseLocation("34.126"));
- assertNull(DnaUtils.parseLocation("34^126"));
- assertNull(DnaUtils.parseLocation("order(34..126,130..180)"));
+ checkForParseException("<34..126");
+ checkForParseException("35..>126");
+ checkForParseException("34.126");
+ checkForParseException("34^126");
+ checkForParseException("order(34..126,130..180)");
/*
* invalid things
*/
- assertNull(DnaUtils.parseLocation(""));
- assertNull(DnaUtils.parseLocation("JOIN(1..2)"));
- assertNull(DnaUtils.parseLocation("join(1..2"));
- assertNull(DnaUtils.parseLocation("join(1..2("));
- assertNull(DnaUtils.parseLocation("complement(1..2"));
- assertNull(DnaUtils.parseLocation("complement(1..2("));
+ checkForParseException("");
+ checkForParseException("JOIN(1..2)");
+ checkForParseException("join(1..2");
+ checkForParseException("join(1..2(");
+ checkForParseException("complement(1..2");
+ checkForParseException("complement(1..2(");
try
{
assertNull(DnaUtils.parseLocation(null));
* nested joins are not allowed; just as well since this fails to parse
* (splitting tokens by comma fragments the inner join expression)
*/
- assertNull(DnaUtils
- .parseLocation("join(1..2,join(4..5,10..12),18..22)"));
+ checkForParseException("join(1..2,join(4..5,10..12),18..22)");
/*
* complement may not enclose multiple ranges
* parsing fails for the same reason
*/
- assertNull(DnaUtils
- .parseLocation("join(complement(36618..36700,4000..4200),86988..87064)"));
+ checkForParseException("join(complement(36618..36700,4000..4200),86988..87064)");
+ }
+
+ /**
+ * Verifies that a ParseException is thrown when the given location is parsed
+ *
+ * @param location
+ */
+ void checkForParseException(String location)
+ {
+ try
+ {
+ DnaUtils.parseLocation(location);
+ fail("Expected exception");
+ } catch (ParseException e)
+ {
+ // expected;
+ }
}
}