From b735ad7f7076ede06e977052d8f2f98b54f98c60 Mon Sep 17 00:00:00 2001 From: Damien Goutte-Gattat Date: Mon, 25 Mar 2024 14:31:24 +0000 Subject: [PATCH] Add the IDRangeHelper class. Create a new class of static method, IDRangeHelper, and move all the code needed to deal with ID range files to that class. That code will later be reused by another command. --- .../obofoundry/kgcl/robot/ApplyCommand.java | 98 +++------- .../obofoundry/kgcl/robot/IDRangeHelper.java | 168 ++++++++++++++++++ 2 files changed, 192 insertions(+), 74 deletions(-) create mode 100644 robot/src/main/java/org/incenp/obofoundry/kgcl/robot/IDRangeHelper.java diff --git a/robot/src/main/java/org/incenp/obofoundry/kgcl/robot/ApplyCommand.java b/robot/src/main/java/org/incenp/obofoundry/kgcl/robot/ApplyCommand.java index 02befa1..7e9aad1 100644 --- a/robot/src/main/java/org/incenp/obofoundry/kgcl/robot/ApplyCommand.java +++ b/robot/src/main/java/org/incenp/obofoundry/kgcl/robot/ApplyCommand.java @@ -19,7 +19,6 @@ package org.incenp.obofoundry.kgcl.robot; import java.io.File; -import java.io.FilenameFilter; import java.io.IOException; import java.time.LocalDate; import java.time.ZoneId; @@ -31,10 +30,6 @@ import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Options; -import org.incenp.obofoundry.idrange.IDRange; -import org.incenp.obofoundry.idrange.IDRangePolicyException; -import org.incenp.obofoundry.idrange.IDRangePolicyParser; -import org.incenp.obofoundry.idrange.IIDRangePolicy; import org.incenp.obofoundry.kgcl.AutoIDAllocator; import org.incenp.obofoundry.kgcl.IAutoIDGenerator; import org.incenp.obofoundry.kgcl.KGCLHelper; @@ -231,9 +226,14 @@ private KGCLWriter getRejectedWriter(CommandLine line) throws IOException { } } - private IAutoIDGenerator getAutoIDGenerator(CommandLine line, OWLOntology ontology) - throws Exception { - if ( line.hasOption("audo-id-prefix") ) { + private IAutoIDGenerator getAutoIDGenerator(CommandLine line, OWLOntology ontology) throws Exception { + IAutoIDGenerator generator = null; + + if ( line.hasOption("auto-id-prefix") ) { + /* + * Manual mode; generate IDs in a range that is explicitly specified on the + * command line. + */ if ( !line.hasOption("auto-id-min") ) { throw new Exception("Missing --auto-id-min option for auto-assigned IDs"); } @@ -242,76 +242,26 @@ private IAutoIDGenerator getAutoIDGenerator(CommandLine line, OWLOntology ontolo : lower + 1000; int width = line.hasOption("auto-id-width") ? Integer.parseInt(line.getOptionValue("auto-id-width")) : 7; String format = String.format("%s%%0%dd", line.getOptionValue("auto-id-prefix"), width); - return new RandomizedIDGenerator(ontology, format, lower, upper); + generator = new RandomizedIDGenerator(ontology, format, lower, upper); } else if ( line.hasOption("auto-id-temp-prefix") ) { + /* + * Temporary ID mode; generate temporary IDs that should later be replaced by + * permanent IDs. + */ String prefix = line.getOptionValue("auto-id-temp-prefix"); - return () -> prefix + UUID.randomUUID().toString(); - } else if ( line.hasOption("auto-id-range-file") ) { - return getAutoIDGenerator(line, ontology, line.getOptionValue("auto-id-range-file"), false); + generator = () -> prefix + UUID.randomUUID().toString(); } else { - String rangeFile = findIDRangeFile(); - if ( rangeFile != null ) { - return getAutoIDGenerator(line, ontology, rangeFile, true); - } - } - return null; - } - - private IAutoIDGenerator getAutoIDGenerator(CommandLine line, OWLOntology ontology, String rangeFile, - boolean silent) throws Exception { - IDRangePolicyParser parser = new IDRangePolicyParser(rangeFile); - try { - IIDRangePolicy policy = parser.parse(); - IDRange range = null; - if ( line.hasOption("auto-id-range-name") ) { - range = policy.getRange(line.getOptionValue("auto-id-range-name")); - if ( range == null ) { - throw new Exception("Requested range not found in ID range file"); - } - } - - if ( range == null ) { - range = policy.getRange("kgcl"); - } - if ( range == null ) { - range = policy.getRange("KGCL"); - } - if ( range == null ) { - range = policy.getRange("ontobot"); - } - if ( range == null ) { - range = policy.getRange("Ontobot"); - } - - if ( range != null ) { - String format = String.format("%s%%0%dd", policy.getPrefix(), policy.getWidth()); - return new RandomizedIDGenerator(ontology, format, range.getLowerBound(), range.getUpperBound()); - } else if ( !silent ) { - throw new Exception("No range specified and no default range found in ID range file"); - } - } catch ( IDRangePolicyException e ) { - if ( !silent ) { - throw new Exception("Cannot parse ID range policy file"); - } - } - - return null; - } - - private String findIDRangeFile() { - FilenameFilter idRangeFilter = new FilenameFilter() { - @Override - public boolean accept(File file, String name) { - return name.endsWith("-idranges.owl"); - } - }; - - File currentDir = new File("."); - String[] rangeFiles = currentDir.list(idRangeFilter); - if ( rangeFiles.length == 1 ) { - return rangeFiles[0]; + /* + * Range-file mode; similar to manual mode, but the range is obtained from a + * file of ID ranges. + */ + String rangeFile = line.getOptionValue("auto-id-range-file"); + String requestedName = line.getOptionValue("auto-id-range-name"); + String[] defaultNames = new String[] { "kgcl", "KGCL", "ontobot", "Ontobot" }; + + generator = IDRangeHelper.maybeGetIDGenerator(ontology, rangeFile, requestedName, defaultNames, true); } - return null; + return generator; } } diff --git a/robot/src/main/java/org/incenp/obofoundry/kgcl/robot/IDRangeHelper.java b/robot/src/main/java/org/incenp/obofoundry/kgcl/robot/IDRangeHelper.java new file mode 100644 index 0000000..eeeb0dc --- /dev/null +++ b/robot/src/main/java/org/incenp/obofoundry/kgcl/robot/IDRangeHelper.java @@ -0,0 +1,168 @@ +/* + * KGCL-Java - KGCL library for Java + * Copyright © 2024 Damien Goutte-Gattat + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the Gnu General Public License + * along with this program. If not, see . + */ + +package org.incenp.obofoundry.kgcl.robot; + +import java.io.File; +import java.io.FilenameFilter; + +import org.incenp.obofoundry.idrange.IDRange; +import org.incenp.obofoundry.idrange.IDRangePolicyException; +import org.incenp.obofoundry.idrange.IDRangePolicyParser; +import org.incenp.obofoundry.idrange.IIDRangePolicy; +import org.incenp.obofoundry.kgcl.IAutoIDGenerator; +import org.incenp.obofoundry.kgcl.RandomizedIDGenerator; +import org.incenp.obofoundry.kgcl.SequentialIDGenerator; +import org.semanticweb.owlapi.model.OWLOntology; + +/* + * Helper methods to work with OBO-style ID range policy files. + */ +public class IDRangeHelper { + + /** + * Finds an ID range policy file in the current directory. This methods looks + * for a single file whose name ends with {@code -idranges.owl} in the current + * directory. + * + * @return The name of the ID range policy file, if such a file exists; + * otherwise {@code null}. + */ + public static String findIDRangeFile() { + FilenameFilter idRangeFilter = new FilenameFilter() { + @Override + public boolean accept(File file, String name) { + return name.endsWith("-idranges.owl"); + } + }; + + File cwd = new File("."); + String[] rangeFiles = cwd.list(idRangeFilter); + if ( rangeFiles.length == 1 ) { + return rangeFiles[0]; + } + + return null; + } + + /** + * Gets an ID generator initialised with data from the specified range file. + * + * @param ontology The ontology to generate IDs for. + * @param rangeFile The range file to initialise the generator with. + * @param rangeName The name of the range to use. This should match the + * {@code allocatedto} annotation of one of the ranges in the + * file. May be {@code null}, in which case the method will + * look for a range that matches one of the alternative names + * instead. If not {@code null} and a corresponding range + * cannot be found, an exception will be thrown. + * @param altNames A list of default range names to use if {@code rangeName} is + * {@code null}. + * @param random If {@code true}, the generator will produce IDs picked at + * random within the target range; otherwise, IDs will be + * picked sequentially. + * @return A newly initialised ID generator. + * @throws IDRangePolicyException If the range file cannot be read for any + * reason, if the requested {@code rangeName} + * cannot be found, or if none of the default + * ranges can be found. + */ + public static IAutoIDGenerator getIDGenerator(OWLOntology ontology, String rangeFile, String rangeName, + String[] altNames, boolean random) throws IDRangePolicyException { + + IDRangePolicyParser parser = new IDRangePolicyParser(rangeFile); + IIDRangePolicy policy = parser.parse(); + IDRange range = null; + + if ( rangeName != null ) { + range = policy.getRange(rangeName); + if ( range == null ) { + throw new IDRangePolicyException("Requested range not found in ID range file"); + } + } + + int i = 0; + while ( range == null && altNames != null && i < altNames.length ) { + range = policy.getRange(altNames[i++]); + } + + if ( range == null ) { + throw new IDRangePolicyException("Not suitable range found in ID range file"); + } + + String format = String.format("%s%%0%dd", policy.getPrefix(), policy.getWidth()); + if ( random ) { + return new RandomizedIDGenerator(ontology, format, range.getLowerBound(), range.getUpperBound()); + } else { + return new SequentialIDGenerator(ontology, format, range.getLowerBound(), range.getUpperBound()); + } + } + + /** + * Gets an ID generator initialised with data from the specified range file, or + * a default file. This method is similar to + * {@link #getIDGenerator(OWLOntology, String, String, String[], boolean)}, + * except that if the {@code rangeFile} parameter is {@code null}, it tries to + * find a default range file (using the {@link #findIDRangeFile()} method); in + * that case, no exception will be thrown. + * + * @param ontology The ontology to generate IDs for. + * @param rangeFile The range file to initialise the generator with. If + * {@code null}, the method will try to find a default file. + * @param rangeName The name of the range to use. This should match the + * {@code allocatedto} annotation of one of the ranges in the + * file. May be {@code null}, in which case the method will + * look for a range that matches one of the alternative names + * instead. + * @param altNames A list of default range names to use if {@code rangeName} is + * {@code null}. + * @param random If {@code true}, the generator will produce IDs picked at + * random within the target range; otherwise, IDs will be + * picked sequentially. + * @return A newly initialised ID generator or {@code null} if no range file has + * been specified and no suitable default file was found. + * @throws IDRangePolicyException Only if {@code rangeFile} is not {@code null}: + * iIf the range file cannot be read for any + * reason, if the requested {@code rangeName} + * cannot be found, or if none of the default + * ranges can be found. + */ + public static IAutoIDGenerator maybeGetIDGenerator(OWLOntology ontology, String rangeFile, String rangeName, + String[] altNames, boolean random) throws IDRangePolicyException { + boolean silent = false; + IAutoIDGenerator generator = null; + + if ( rangeFile == null ) { + rangeFile = findIDRangeFile(); + if ( rangeFile == null ) { + return null; + } + silent = true; + } + + try { + generator = getIDGenerator(ontology, rangeFile, rangeName, altNames, random); + } catch ( IDRangePolicyException e ) { + if ( !silent ) { + throw e; + } + } + + return generator; + } +}