From ee1488d1228065140f792ec5583122666f166a3d Mon Sep 17 00:00:00 2001 From: Joel Weiser Date: Thu, 14 Aug 2025 16:36:39 -0400 Subject: [PATCH 01/13] refactors Main class to user helper classes --- .../cosmicupdate/COSMICFileManager.java | 110 ++++++ .../reactome/release/cosmicupdate/Config.java | 148 ++++++++ .../reactome/release/cosmicupdate/Main.java | 322 ++++-------------- 3 files changed, 319 insertions(+), 261 deletions(-) create mode 100644 src/main/java/org/reactome/release/cosmicupdate/COSMICFileManager.java create mode 100644 src/main/java/org/reactome/release/cosmicupdate/Config.java diff --git a/src/main/java/org/reactome/release/cosmicupdate/COSMICFileManager.java b/src/main/java/org/reactome/release/cosmicupdate/COSMICFileManager.java new file mode 100644 index 0000000..4eced10 --- /dev/null +++ b/src/main/java/org/reactome/release/cosmicupdate/COSMICFileManager.java @@ -0,0 +1,110 @@ +package org.reactome.release.cosmicupdate; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.reactome.release.common.dataretrieval.cosmic.COSMICFileRetriever; +import org.reactome.util.general.GUnzipCallable; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Duration; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; + +public class COSMICFileManager { + private static final Logger logger = LogManager.getLogger(); + + private final Config config; + + public COSMICFileManager(Config config) { + this.config = config; + } + + public void unzipFiles() throws InterruptedException { + ExecutorService execService = Executors.newCachedThreadPool(); + // The files are large, and it could be slow to unzip them sequentially, so we will unzip them in parallel. + execService.invokeAll(getGUnzipCallables()); + execService.shutdown(); + } + + /** + * Clean up the uncompressed data files. Don't remove the zipped files, because if you need to run this code again, + * you'll be stuck waiting for the files to download again. Try to avoid removing the zipped files until + * you're *sure* this step has run successfully. + */ + public void cleanupFiles() { + List filesToDelete = getConfig().getAllCOSMICLocalFilePaths(); + for (String file : filesToDelete) { + deleteFile(file); + } + } + + /** + * Download the data files from COSMIC if older than the specified duration + */ + public void downloadFiles(Duration fileAge) { + for (Config.FileConfig fileConfig : getConfig().getFileConfigs() ) { + downloadFile(fileConfig, fileAge); + } + } + + private void downloadFile(Config.FileConfig config, Duration fileAge) { + try { + COSMICFileRetriever retriever = new COSMICFileRetriever(); + retriever.setDataURL(new URI(config.getUrl())); + retriever.setFetchDestination(config.getDestination()); + retriever.setMaxAge(fileAge); + retriever.setUserName(getConfig().getCosmicUsername()); + retriever.setPassword(getConfig().getCosmicPassword()); + + logger.info("Downloading {} to {}", retriever.getDataURL(), config.getDestination()); + retriever.fetchData(); + } catch (URISyntaxException e) { + throw new RuntimeException("Invalid URL for " + config.getDescription(), e); + } catch (Exception e) { + throw new RuntimeException("Error downloading " + config.getDescription(), e); + } + } + + /** + * Deletes a file and logs a message about the deletion. + * @param filePath Path of the file to delete + */ + private void deleteFile(String filePath) { + try { + Files.deleteIfExists(Paths.get(filePath)); + logger.info("{} was deleted.", filePath); + } catch (IOException e) { + logger.warn("IOException caught while cleaning up the data file: \"" + filePath + "\". " + + "You may need to manually remove any remaining files.", e); + } + } + + private List getGUnzipCallables() { + return getConfig().getAllCOSMICLocalFilePaths().stream() + .map(this::getGUnzipCallable) + .collect(Collectors.toList()); + } + + private GUnzipCallable getGUnzipCallable(String filePathAsString) { + return new GUnzipCallable(getGZippedFilePath(filePathAsString), getGUnzippedFilePath(filePathAsString)); + } + + private Path getGZippedFilePath(String filePathAsString) { + return Paths.get(getGUnzippedFilePath(filePathAsString) + ".gz"); + } + + private Path getGUnzippedFilePath(String filePathAsString) { + return Paths.get(filePathAsString); + } + + private Config getConfig() { + return this.config; + } +} diff --git a/src/main/java/org/reactome/release/cosmicupdate/Config.java b/src/main/java/org/reactome/release/cosmicupdate/Config.java new file mode 100644 index 0000000..63e4a24 --- /dev/null +++ b/src/main/java/org/reactome/release/cosmicupdate/Config.java @@ -0,0 +1,148 @@ +package org.reactome.release.cosmicupdate; + +import org.gk.persistence.MySQLAdaptor; +import org.reactome.util.general.DBUtils; + +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; + +public class Config { + private final Properties configProps; + + public Config(String configFilePath) { + validateConfigFilePath(configFilePath); + this.configProps = loadConfigProperties(configFilePath); + } + + public String getCosmicUsername() { + return throwIfNullOrBlank("cosmic.user", getConfigProperties().getProperty("cosmic.user")); + } + + public String getCosmicPassword() { + return throwIfNullOrBlank("cosmic.password", getConfigProperties().getProperty("cosmic.password")); + } + + public long getPersonId() { + return Long.parseLong(getConfigProperties().getProperty("personId")); + } + + public boolean isTestMode() { + return Boolean.parseBoolean(getConfigProperties().getProperty("testMode", "false")); + } + + public MySQLAdaptor getDBA() throws SQLException { + return DBUtils.getCuratorDbAdaptor(getConfigProperties()); + } + + public List getFileConfigs() { + return Arrays.asList( + new FileConfig( + getMutantExportRemoteFilePath(), + addGzipExtension(getMutantExportLocalFilePath()), + "Mutant Export" + ), + new FileConfig( + getMutationTrackingRemoteFilePath(), + addGzipExtension(getMutationTrackingLocalFilePath()), + "Mutation Tracking" + ), + new FileConfig( + getFusionExportRemoteFilePath(), + addGzipExtension(getFusionExportLocalFilePath()), + "Fusion Export" + ) + ); + } + + public List getAllCOSMICLocalFilePaths() { + return Arrays.asList( + getMutantExportLocalFilePath(), + getFusionExportLocalFilePath(), + getMutationTrackingLocalFilePath() + ); + } + + public String getMutantExportLocalFilePath() { + return getConfigProperties().getProperty("pathToMutantExportFile", "./CosmicMutantExport.tsv"); + + } + + public String getFusionExportLocalFilePath() { + return getConfigProperties().getProperty("pathToFusionExportFile", "./CosmicFusionExport.tsv"); + } + + public String getMutationTrackingLocalFilePath() { + return getConfigProperties().getProperty("pathToMutationTrackingFile", "./CosmicMutationTracking.tsv"); + } + + private String getMutantExportRemoteFilePath() { + return throwIfNullOrBlank( + "urlToMutantExportFile", getConfigProperties().getProperty("urlToMutantExportFile") + ); + } + + private String getFusionExportRemoteFilePath() { + return throwIfNullOrBlank( + "urlToFusionExportFile", getConfigProperties().getProperty("urlToFusionExportFile") + ); + } + + private String getMutationTrackingRemoteFilePath() { + return throwIfNullOrBlank( + "urlToMutationTrackingFile", getConfigProperties().getProperty("urlToMutationTrackingFile") + ); + } + + private String throwIfNullOrBlank(String name, String value) { + if (value == null || value.isBlank()) { + throw new IllegalStateException("Config value " + name + " cannot be null or blank!"); + } + return value; + } + + private void validateConfigFilePath(String configFilePath) { + if (configFilePath == null || configFilePath.isBlank()) { + throw new IllegalArgumentException("Config file path cannot be null or blank!"); + } + } + + private Properties loadConfigProperties(String configFilePath) { + Properties configProps = new Properties(); + + try(Reader configReader = new FileReader(configFilePath)) { + configProps.load(configReader); + } catch (IOException e) { + throw new RuntimeException("Unable to load config file", e); + } + return configProps; + } + + private Properties getConfigProperties() { + return this.configProps; + } + + private String addGzipExtension(String filePath) { + return filePath + ".gz"; + } + + public static class FileConfig { + private final String url; + private final String destination; + private final String description; + + public FileConfig(String url, String destination, String description) { + this.url = url; + this.destination = destination; + this.description = description; + } + + public String getUrl() { return url; } + public String getDestination() { return destination; } + public String getDescription() { return description; } + } +} diff --git a/src/main/java/org/reactome/release/cosmicupdate/Main.java b/src/main/java/org/reactome/release/cosmicupdate/Main.java index 84f590d..92356cf 100644 --- a/src/main/java/org/reactome/release/cosmicupdate/Main.java +++ b/src/main/java/org/reactome/release/cosmicupdate/Main.java @@ -1,41 +1,21 @@ package org.reactome.release.cosmicupdate; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.io.Reader; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.sql.SQLException; import java.time.Duration; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.util.*; import java.util.stream.Collectors; -import java.util.stream.Stream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.gk.model.GKInstance; import org.gk.model.ReactomeJavaConstants; import org.gk.persistence.MySQLAdaptor; -import org.gk.schema.InvalidAttributeException; -import org.reactome.release.common.ReleaseStep; -import org.reactome.release.common.dataretrieval.cosmic.COSMICFileRetriever; -import org.reactome.util.general.DBUtils; -import org.reactome.util.general.GUnzipCallable; import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; -public class Main extends ReleaseStep { +public class Main { + private static final Logger logger = LogManager.getLogger(); + @Parameter(names = {"-u"}, description = "Specifies that the updates should be performed.") private boolean executeUpdate; @@ -51,25 +31,8 @@ public class Main extends ReleaseStep { description = "The path to the configuration file. Default is src/main/resources/config.properties") private String configPath = "src/main/resources/config.properties"; - //TODO: Create a separate properties file for authentication values (username, password). -// @Parameter(names = {"-a"}, -// description = "The path to the authentication file, containing usernames and passwords. -// + Default is src/main/resources/auth.properties") -// private static String authPath = "src/main/resources/auth.properties"; - - private static String COSMICMutantExport; - private static String COSMICFusionExport; - private static String COSMICMutationTracking; - - private static String COSMICMutantExportURL; - private static String COSMICFusionExportURL; - private static String COSMICMutationTrackingURL; - - private static String COSMICUsername; - private static String COSMICPassword; - - private static final Logger logger = LogManager.getLogger(); - private static long personId; + private Config config; + private COSMICFileManager cosmicFileManager; public static void main(String[] args) throws Exception { Main cosmicUpdateStep = new Main(); @@ -78,275 +41,112 @@ public static void main(String[] args) throws Exception { .addObject(cosmicUpdateStep) .build() .parse(args); - Properties configProps = cosmicUpdateStep.getConfig(); - cosmicUpdateStep.executeStep(configProps); + + cosmicUpdateStep.executeStep(); logger.info("COSMIC Update complete."); } - private Properties getConfig() { - boolean noConfigSpecified = this.configPath != null && this.configPath.trim().isEmpty(); -// boolean noAuthConfigSpecified = Main.authPath != null && !Main.authPath.trim().isEmpty(); + public void executeStep() throws Exception { + this.config = new Config(this.configPath); + this.cosmicFileManager = new COSMICFileManager(this.config); - if (noConfigSpecified) { - String errorMessage = "An empty path to config.properties was given. " + - "Please give a valid path with -c at command line or use default."; - logger.fatal(errorMessage); - throw new RuntimeException(errorMessage); - } -// if (noAuthConfigSpecified) { -// logger.fatal("Empty/null value for path to auth.properties file was specified. This MUST be specified -// as \"-c /path/to/auth.properties\" " -// + "or do not specify anything and the default will be src/main/resources/auth.properties"); -// throw new RuntimeException("Empty/null values were given for the path to an auth file. The program " + -// "cannot run without the auth file."); -// } - Properties configProps = getConfigProperties(); - - // These default to files in the same directory where the program is running. - Main.COSMICMutantExport = - configProps.getProperty("pathToMutantExportFile", "./CosmicMutantExport.tsv"); - Main.COSMICFusionExport = - configProps.getProperty("pathToFusionExportFile", "./CosmicFusionExport.tsv"); - Main.COSMICMutationTracking = - configProps.getProperty("pathToMutationTrackingFile", "./CosmicMutationTracking.tsv"); - - // These have NO default. - Main.COSMICUsername = configProps.getProperty("cosmic.user"); - Main.COSMICPassword = configProps.getProperty("cosmic.password"); - Main.personId = Long.parseLong(configProps.getProperty("personId")); - - // These must be set in the properties file. - Main.COSMICMutantExportURL = configProps.getProperty("urlToMutantExportFile"); - Main.COSMICFusionExportURL = configProps.getProperty("urlToFusionExportFile"); - Main.COSMICMutationTrackingURL = configProps.getProperty("urlToMutationTrackingFile"); - - return configProps; - } - - @Override - public void executeStep(Properties props) throws Exception { redownloadFilesIfTooOld(this.fileAge); if (this.executeUpdate) { - executeUpdate(props); - } - } - - private Properties getConfigProperties() { - Properties configProps = new Properties(); - - try(Reader configReader = new FileReader(this.configPath)) { - configProps.load(configReader); - } catch (IOException e) { - throw new RuntimeException("Unable to load config file", e); + executeUpdate(); } - return configProps; } - private void redownloadFilesIfTooOld(Duration fileAge) throws Exception { + private void redownloadFilesIfTooOld(Duration fileAge) { if (fileAge != null) { logger.info("User has specified that download process should run."); logger.info("Files will be downloaded if they are older than {}", this.fileAge); - this.downloadFiles(); + getCosmicFileManager().downloadFiles(fileAge); } } - private void executeUpdate(Properties props) throws Exception { + private void executeUpdate() throws Exception { logger.info("User has specified that update process should run."); - unzipFiles(); - - MySQLAdaptor adaptor = DBUtils.getCuratorDbAdaptor(props); - Collection cosmicObjects = COSMICUpdateUtil.getCOSMICIdentifiers(adaptor); - logger.info("{} COSMIC identifiers", cosmicObjects.size()); - // Filter the identifiers to exclude the COSV prefixes. - List filteredCosmicObjects = cosmicObjects.parallelStream().filter(inst -> { - try { - return !((String)inst.getAttributeValue(ReactomeJavaConstants.identifier)).toUpperCase().startsWith("COSV"); - } catch (Exception e) { - // exception caught here means there is probably some fundamental problem with the data - // such that the program should probably not continue.. - throw new RuntimeException(e); - } - }).collect(Collectors.toList()); - logger.info("{} filtered COSMIC identifiers", filteredCosmicObjects.size()); + try { + // Step 1: Prepare files + getCosmicFileManager().unzipFiles(); - Map> updaters = COSMICUpdateUtil.determinePrefixes(filteredCosmicObjects); + // Step 2: Get and filter COSMIC identifiers + MySQLAdaptor adaptor = getConfig().getDBA(); + List filteredCosmicObjects = getFilteredCosmicObjects(adaptor); - COSMICUpdateUtil.validateIdentifiersAgainstFiles(updaters, COSMICFusionExport, COSMICMutationTracking, COSMICMutantExport); - COSMICUpdateUtil.printIdentifierUpdateReport(updaters); + // Step 3: Process and validate identifiers + Map> updaters = + COSMICUpdateUtil.determinePrefixes(filteredCosmicObjects); + validateAndReportUpdates(updaters); - loadTestModeFromProperties(props); - if (!this.testMode) { - updateIdentifiers(adaptor, updaters); + // Step 4: Perform updates if not in test mode + if (!getConfig().isTestMode()) { + updateIdentifiers(adaptor, updaters); + } + } finally { + // Step 5: Cleanup + getCosmicFileManager().cleanupFiles(); } - cleanupFiles(); } - private void unzipFiles() throws InterruptedException { - ExecutorService execService = Executors.newCachedThreadPool(); - // The files are large and it could be slow to unzip them sequentially, so we will unzip them in parallel. - execService.invokeAll(getGUnzipCallables()); - execService.shutdown(); - } + private List getFilteredCosmicObjects(MySQLAdaptor adaptor) throws Exception { + Collection cosmicObjects = COSMICUpdateUtil.getCOSMICIdentifiers(adaptor); + logger.info("{} COSMIC identifiers", cosmicObjects.size()); - private List getGUnzipCallables() { - return Stream.of(COSMICFusionExport, COSMICMutantExport, COSMICMutationTracking) - .map(this::getGUnzipCallable) + // Filter out COSV prefixes + List filteredObjects = cosmicObjects.parallelStream() + .filter(this::isNotCOSVPrefix) .collect(Collectors.toList()); - } - - private GUnzipCallable getGUnzipCallable(String filePathAsString) { - return new GUnzipCallable(getGZippedFilePath(filePathAsString), getGUnzippedFilePath(filePathAsString)); - } - - private Path getGZippedFilePath(String filePathAsString) { - return Paths.get(getGUnzippedFilePath(filePathAsString).toString() + ".gz"); - } - private Path getGUnzippedFilePath(String filePathAsString) { - return Paths.get(filePathAsString); + logger.info("{} filtered COSMIC identifiers", filteredObjects.size()); + return filteredObjects; } - /** - * Clean up the uncompressed data files. Don't remove the zipped files, because if you need to run this code again, - * you'll be stuck waiting for the files to download again. Try to avoid removing the zipped files until you're *sure* - * this step has run successfully. - */ - private void cleanupFiles() { - List filesToDelete = Arrays.asList(COSMICFusionExport, COSMICMutantExport, COSMICMutationTracking); - for (String file : filesToDelete) { - deleteFile(file); - } - } - - /** - * Deletes a file and logs a message about the deletion. - * @param fileName - */ - private void deleteFile(String fileName) { - try { - Files.deleteIfExists(Paths.get(fileName)); - logger.info("{} was deleted.", fileName); - } catch (IOException e) { - logger.warn("IOException caught while cleaning up the data file: \"" + fileName + "\". " + - "You may need to manually remove any remaining files.", e); - } - } - - /** - * Checks that a config value. If it is null or blank or empty, - * an IllegalArgumentException is thrown. - * @param value The value to check - * @param message The message that will be put into the IllegalArgumentException - * @throws IllegalArgumentException If value == null || value.isEmpty() - */ - private void validateConfigValue(String value, String message) { - if (value == null || value.trim().isEmpty()) { - throw new IllegalArgumentException(message); - } - } - - /** - * Download the data files from COSMIC. - * @throws Exception - */ - private void downloadFiles() throws IllegalArgumentException, URISyntaxException, Exception { - //TODO: Better Properties class in release-common-lib. (for future work) - validateConfigValue(Main.COSMICUsername, - "COSMIC Username cannot be null/empty! Please set a value for cosmic.username in the " + - "application's properties file"); - validateConfigValue(Main.COSMICUsername, - "COSMIC Password cannot be null/empty! Please set a value for cosmic.password in the " + - "application's properties file"); - validateConfigValue(Main.COSMICMutantExportURL, - "URL for COSMIC Mutant Export file cannot be null/empty! Please set a value for " + - "urlToMutantExportFile in the application's properties file"); - validateConfigValue(Main.COSMICMutationTrackingURL, - "URL for COSMIC Mutation Tracking file cannot be null/empty! Please set a value for " + - "urlToMutationTrackingFile in the application's properties file"); - validateConfigValue(Main.COSMICFusionExportURL, "URL for COSMIC Fusion Export file cannot be null/empty!" + - " Please set a value for urlToFusionExportFile in the application's properties file"); - - COSMICFileRetriever mutantExportRetriever = new COSMICFileRetriever(); - COSMICFileRetriever mutationTrackingRetriever = new COSMICFileRetriever(); - COSMICFileRetriever fusionExportRetriever = new COSMICFileRetriever(); - + private boolean isNotCOSVPrefix(GKInstance instance) { try { - mutantExportRetriever.setDataURL(new URI(Main.COSMICMutantExportURL)); - mutationTrackingRetriever.setDataURL(new URI(Main.COSMICMutationTrackingURL)); - fusionExportRetriever.setDataURL(new URI(Main.COSMICFusionExportURL)); - - Properties configProps = getConfigProperties(); - - final String mutantExportDestination = addGzipExtension(configProps.getProperty( - "pathToMutantExportFile", "./CosmicMutantExport.tsv")); - final String mutationTrackingDestination = addGzipExtension(configProps.getProperty( - "pathToMutationTrackingFile", "./CosmicMutationTracking.tsv")); - final String fusionExportDestination = addGzipExtension(configProps.getProperty( - "pathToFusionExportFile", "./CosmicFusionExport.tsv")); - - mutantExportRetriever.setFetchDestination(mutantExportDestination); - mutationTrackingRetriever.setFetchDestination(mutationTrackingDestination); - fusionExportRetriever.setFetchDestination(fusionExportDestination); - - logDownloadMessage(mutantExportRetriever, mutantExportDestination); - this.executeDownload(mutantExportRetriever); - - logDownloadMessage(mutationTrackingRetriever, mutationTrackingDestination); - this.executeDownload(mutationTrackingRetriever); - - logDownloadMessage(fusionExportRetriever, fusionExportDestination); - this.executeDownload(fusionExportRetriever); - } catch (URISyntaxException e) { - e.printStackTrace(); - throw e; + String identifier = (String) instance.getAttributeValue(ReactomeJavaConstants.identifier); + return !identifier.toUpperCase().startsWith("COSV"); } catch (Exception e) { - logger.error("Error occurred while trying to download a file! " + e.getMessage(), e); - // throw the exception further up the stack - can't continue if file downloads are failing. - throw e; + throw new RuntimeException("Error accessing instance identifier", e); } } - private void logDownloadMessage(COSMICFileRetriever retriever, final String destination) { - logger.info("Downloading {} to {}", retriever.getDataURL(), destination); - } - - /** - * Executes a single download. - * @param retriever - the file retriever to run. - * @throws Exception - */ - private void executeDownload(COSMICFileRetriever retriever) throws Exception { - retriever.setMaxAge(this.fileAge); - retriever.setUserName(Main.COSMICUsername); - retriever.setPassword(Main.COSMICPassword); - retriever.fetchData(); + private void validateAndReportUpdates(Map> updaters) throws Exception { + COSMICUpdateUtil.validateIdentifiersAgainstFiles( + updaters, + getConfig().getFusionExportLocalFilePath(), + getConfig().getMutationTrackingLocalFilePath(), + getConfig().getMutantExportLocalFilePath() + ); + COSMICUpdateUtil.printIdentifierUpdateReport(updaters); } /** * Updates the identifiers that need updating. * @param adaptor * @param updates - * @throws Exception */ - private static void updateIdentifiers(MySQLAdaptor adaptor, Map> updates) - throws Exception { - + private void updateIdentifiers(MySQLAdaptor adaptor, Map> updates) { for (List listOfUpdaters : updates.values()) { listOfUpdaters.forEach(updater -> { try { - updater.updateIdentfier(adaptor, personId); + updater.updateIdentifier(adaptor, getConfig().getPersonId()); } catch (Exception e) { logger.error("Exception caught while trying to update identifier: " + - listOfUpdaters.toString() + " ; Exception is: ", e); + listOfUpdaters + " ; Exception is: ", e); } }); } } - private String addGzipExtension(String filePath) { - return filePath + ".gz"; + private Config getConfig() { + return this.config; + } + + private COSMICFileManager getCosmicFileManager() { + return this.cosmicFileManager; } } From 6ea9274f50e29d39d7e8c29a4799ad6fd511df5b Mon Sep 17 00:00:00 2001 From: Joel Weiser Date: Thu, 14 Aug 2025 16:42:14 -0400 Subject: [PATCH 02/13] changes braces and line lengths --- .../cosmicupdate/COSMICIdentifierUpdater.java | 103 ++++++++---------- .../COSMICIdentifierUpdaterTest.java | 6 +- 2 files changed, 47 insertions(+), 62 deletions(-) diff --git a/src/main/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdater.java b/src/main/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdater.java index 725418b..0244ab2 100644 --- a/src/main/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdater.java +++ b/src/main/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdater.java @@ -16,15 +16,16 @@ /** * Updates a COSMIC Identifier. - * Implements Comparable to make sorting easier for reporting purposes. Does *not* override the equals method. + * Implements Comparable to make sorting easier for reporting purposes. + * Does *not* override the equals method. * @author sshorser * */ -public class COSMICIdentifierUpdater implements Comparable -{ +public class COSMICIdentifierUpdater implements Comparable { private static final Logger logger = LogManager.getLogger(); private static GKInstance instanceEditNewCOSV; private static GKInstance instanceEditPrependCOSM; + private String identifier; private long dbID; private String suggestedPrefix; @@ -32,58 +33,56 @@ public class COSMICIdentifierUpdater implements Comparable mutationIDs = new HashSet<>(); private String cosvIdentifier; - public String getIdentifier() - { + public String getIdentifier() { return identifier; } - public void setIdentifier(String identifier) - { + + public void setIdentifier(String identifier) { this.identifier = identifier; } - public long getDbID() - { + + public long getDbID() { return dbID; } - public void setDbID(long dbID) - { + + public void setDbID(long dbID) { this.dbID = dbID; } - public String getSuggestedPrefix() - { + + public String getSuggestedPrefix() { return suggestedPrefix; } - public void setSuggestedPrefix(String suggestedPrefix) - { + + public void setSuggestedPrefix(String suggestedPrefix) { this.suggestedPrefix = suggestedPrefix; } - public boolean isValid() - { + + public boolean isValid() { return valid; } - public void setValid(boolean valid) - { + + public void setValid(boolean valid) { this.valid = valid; } - public Set getMutationIDs() - { + + public Set getMutationIDs() { return mutationIDs; } - public void setMutationIDs(Set mutationIDs) - { + + public void setMutationIDs(Set mutationIDs) { this.mutationIDs = mutationIDs; } - public String getCosvIdentifier() - { + + public String getCosvIdentifier() { return cosvIdentifier; } - public void setCosvIdentifier(String cosvIdentifier) - { + + public void setCosvIdentifier(String cosvIdentifier) { this.cosvIdentifier = cosvIdentifier; } @Override - public String toString() - { + public String toString() { return "[" + this.getDbID() + "; " + this.getIdentifier()+ "; " + this.getSuggestedPrefix() + "; " @@ -97,22 +96,15 @@ public String toString() * This is done so that the invalid identifiers are at the top of the report. */ @Override - public int compareTo(COSMICIdentifierUpdater other) - { - if (other.valid && !this.valid) - { + public int compareTo(COSMICIdentifierUpdater other) { + if (other.valid && !this.valid) { return -1; } - if (!other.valid && this.valid) - { + if (!other.valid && this.valid) { return 1; } - if (other.valid == this.valid) - { - return this.identifier.compareTo(other.identifier); - } - return 0; - } + return this.identifier.compareTo(other.identifier); + } /** * Perform an update of a COSMIC identifier. @@ -120,16 +112,12 @@ public int compareTo(COSMICIdentifierUpdater other) * @param creatorID - the DB_ID of the Creator of this update. * @throws Exception */ - public void updateIdentfier(MySQLAdaptor adaptor, long creatorID) throws Exception - { + public void updateIdentifier(MySQLAdaptor adaptor, long creatorID) throws Exception { // If there is a COSV identifier, we'll update using that. - if (this.getCosvIdentifier() != null && !this.getCosvIdentifier().isEmpty()) - { + if (this.getCosvIdentifier() != null && !this.getCosvIdentifier().isEmpty()) { // Create the InstanceEdit, if necessary. - synchronized (COSMICIdentifierUpdater.class) - { - if (COSMICIdentifierUpdater.instanceEditNewCOSV == null) - { + synchronized (COSMICIdentifierUpdater.class) { + if (COSMICIdentifierUpdater.instanceEditNewCOSV == null) { COSMICIdentifierUpdater.instanceEditNewCOSV = InstanceEditUtils.createDefaultIE(adaptor, creatorID, true, "Identifier was automatically updated to new \"COSV\" identifier by COSMIC Update process."); } } @@ -144,13 +132,10 @@ else if (this.getSuggestedPrefix() != null && this.getSuggestedPrefix().equalsIg String currentIdentifier = (String) identifierObject.getAttributeValue(ReactomeJavaConstants.identifier); // If the current identifier already begins with "C" then leave it alone. // This code is for updating numeric identifiers that have a suggested prefix. - if (!COSMICUpdateUtil.stringStartsWithC(currentIdentifier.toUpperCase())) - { + if (!COSMICUpdateUtil.stringStartsWithC(currentIdentifier.toUpperCase())) { // Create the InstanceEdit, if necessary. - synchronized (COSMICIdentifierUpdater.class) - { - if (COSMICIdentifierUpdater.instanceEditPrependCOSM == null) - { + synchronized (COSMICIdentifierUpdater.class) { + if (COSMICIdentifierUpdater.instanceEditPrependCOSM == null) { COSMICIdentifierUpdater.instanceEditPrependCOSM = InstanceEditUtils.createDefaultIE(adaptor, creatorID, true, "Identifier was automatically prepended with \"COSM\" by COSMIC Update process."); } } @@ -158,8 +143,7 @@ else if (this.getSuggestedPrefix() != null && this.getSuggestedPrefix().equalsIg } } // Some identifiers won't have a COSV identifier in the COSMIC files, and they might not have a suggested prefix either. - else - { + else { logger.info("No suggested prefix OR corresponding COSV identifier for {} (DBID: {}) - identifier will not be updated.", this.getIdentifier(), this.getDbID()); } } @@ -177,8 +161,9 @@ else if (this.getSuggestedPrefix() != null && this.getSuggestedPrefix().equalsIg * @throws Exception * @throws InvalidAttributeValueException */ - private void updateIdentifierObject(MySQLAdaptor adaptor, GKInstance modifiedForCOSMICUpdate, GKInstance identifierObject, String identifierValue) throws InvalidAttributeException, Exception, InvalidAttributeValueException - { + private void updateIdentifierObject( + MySQLAdaptor adaptor, GKInstance modifiedForCOSMICUpdate, GKInstance identifierObject, String identifierValue + ) throws InvalidAttributeException, Exception, InvalidAttributeValueException { // Set the identifier value. identifierObject.setAttributeValue(ReactomeJavaConstants.identifier, identifierValue); diff --git a/src/test/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdaterTest.java b/src/test/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdaterTest.java index 67d3d81..9ae11de 100644 --- a/src/test/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdaterTest.java +++ b/src/test/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdaterTest.java @@ -52,7 +52,7 @@ public void testUpdateIdentifierNoUpdate() try(MockedStatic mockedStatic = Mockito.mockStatic(InstanceEditUtils.class)) { Mockito.when(InstanceEditUtils.createDefaultIE(any(MySQLAdaptor.class), any(Long.class), any(Boolean.class), any(String.class))).thenReturn(mockInstanceEdit); - updater.updateIdentfier(mockAdaptor, creatorID); + updater.updateIdentifier(mockAdaptor, creatorID); } } catch (Exception e) @@ -83,7 +83,7 @@ public void testUpdateIdentifier() Mockito.when(InstanceEditUtils.createDefaultIE(any(MySQLAdaptor.class), any(Long.class), any(Boolean.class), any(String.class))).thenReturn(mockInstanceEdit); Mockito.when(InstanceDisplayNameGenerator.generateDisplayName(any(GKInstance.class))).thenReturn("TestDisplayName"); Mockito.when(mockAdaptor.fetchInstance(any(Long.class))).thenReturn(mockIdentifierObject); - updater.updateIdentfier(mockAdaptor, creatorID); + updater.updateIdentifier(mockAdaptor, creatorID); } } catch (Exception e) @@ -116,7 +116,7 @@ public void testUpdateCOSMIdentifier() Mockito.when(mockIdentifierObject.getAttributeValue(ReactomeJavaConstants.identifier)).thenReturn("3333"); Mockito.when(mockAdaptor.fetchInstance(any(Long.class))).thenReturn(mockIdentifierObject); - updater.updateIdentfier(mockAdaptor, creatorID); + updater.updateIdentifier(mockAdaptor, creatorID); } } catch (Exception e) From 350738bbd16af12cfe7499ce2334d061be85617c Mon Sep 17 00:00:00 2001 From: Joel Weiser Date: Fri, 15 Aug 2025 03:23:43 -0400 Subject: [PATCH 03/13] adds cache for dba in Config.java --- .../java/org/reactome/release/cosmicupdate/Config.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/reactome/release/cosmicupdate/Config.java b/src/main/java/org/reactome/release/cosmicupdate/Config.java index 63e4a24..d0cb7ef 100644 --- a/src/main/java/org/reactome/release/cosmicupdate/Config.java +++ b/src/main/java/org/reactome/release/cosmicupdate/Config.java @@ -13,6 +13,7 @@ public class Config { private final Properties configProps; + private MySQLAdaptor dba; public Config(String configFilePath) { validateConfigFilePath(configFilePath); @@ -36,7 +37,11 @@ public boolean isTestMode() { } public MySQLAdaptor getDBA() throws SQLException { - return DBUtils.getCuratorDbAdaptor(getConfigProperties()); + if (this.dba == null) { + this.dba = DBUtils.getCuratorDbAdaptor(getConfigProperties()); + } + + return this.dba; } public List getFileConfigs() { From bc946b70dd7bf8d3f8f736c1b00a682e5edd2fdc Mon Sep 17 00:00:00 2001 From: Joel Weiser Date: Fri, 15 Aug 2025 03:24:01 -0400 Subject: [PATCH 04/13] moves brace position --- .../org/reactome/release/cosmicupdate/DurationConverter.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/reactome/release/cosmicupdate/DurationConverter.java b/src/main/java/org/reactome/release/cosmicupdate/DurationConverter.java index 8ed616d..3af10d3 100644 --- a/src/main/java/org/reactome/release/cosmicupdate/DurationConverter.java +++ b/src/main/java/org/reactome/release/cosmicupdate/DurationConverter.java @@ -10,8 +10,7 @@ * @author sshorser * */ -class DurationConverter implements IStringConverter -{ +class DurationConverter implements IStringConverter { @Override public Duration convert(String value) { From 774cb24a3be3a84e8a0c32407c84fddbd82b3207 Mon Sep 17 00:00:00 2001 From: Joel Weiser Date: Fri, 15 Aug 2025 03:29:50 -0400 Subject: [PATCH 05/13] adds modified instance edit to Main and other refactorings --- .../reactome/release/cosmicupdate/Main.java | 52 ++++++++++++------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/reactome/release/cosmicupdate/Main.java b/src/main/java/org/reactome/release/cosmicupdate/Main.java index 92356cf..893ec45 100644 --- a/src/main/java/org/reactome/release/cosmicupdate/Main.java +++ b/src/main/java/org/reactome/release/cosmicupdate/Main.java @@ -1,5 +1,6 @@ package org.reactome.release.cosmicupdate; +import java.sql.SQLException; import java.time.Duration; import java.util.*; import java.util.stream.Collectors; @@ -12,6 +13,7 @@ import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; +import org.reactome.release.common.database.InstanceEditUtils; public class Main { private static final Logger logger = LogManager.getLogger(); @@ -33,6 +35,7 @@ public class Main { private Config config; private COSMICFileManager cosmicFileManager; + private GKInstance modifiedInstanceEdit; public static void main(String[] args) throws Exception { Main cosmicUpdateStep = new Main(); @@ -75,16 +78,17 @@ private void executeUpdate() throws Exception { // Step 2: Get and filter COSMIC identifiers MySQLAdaptor adaptor = getConfig().getDBA(); - List filteredCosmicObjects = getFilteredCosmicObjects(adaptor); + List nonCOSVCosmicDatabaseIdentifierInstances = + getNonCOSVCosmicDatabaseIdentifierInstances(adaptor); // Step 3: Process and validate identifiers Map> updaters = - COSMICUpdateUtil.determinePrefixes(filteredCosmicObjects); + COSMICUpdateUtil.determinePrefixes(nonCOSVCosmicDatabaseIdentifierInstances); validateAndReportUpdates(updaters); // Step 4: Perform updates if not in test mode if (!getConfig().isTestMode()) { - updateIdentifiers(adaptor, updaters); + updateIdentifiers(updaters); } } finally { // Step 5: Cleanup @@ -92,12 +96,13 @@ private void executeUpdate() throws Exception { } } - private List getFilteredCosmicObjects(MySQLAdaptor adaptor) throws Exception { - Collection cosmicObjects = COSMICUpdateUtil.getCOSMICIdentifiers(adaptor); - logger.info("{} COSMIC identifiers", cosmicObjects.size()); + private List getNonCOSVCosmicDatabaseIdentifierInstances(MySQLAdaptor adaptor) throws Exception { + Collection cosmicDatabaseIdentifierInstances = + COSMICUpdateUtil.getCOSMICDatabaseIdentifierInstances(adaptor); + logger.info("{} COSMIC identifiers", cosmicDatabaseIdentifierInstances.size()); // Filter out COSV prefixes - List filteredObjects = cosmicObjects.parallelStream() + List filteredObjects = cosmicDatabaseIdentifierInstances.parallelStream() .filter(this::isNotCOSVPrefix) .collect(Collectors.toList()); @@ -126,22 +131,20 @@ private void validateAndReportUpdates(Map> /** * Updates the identifiers that need updating. - * @param adaptor * @param updates */ - private void updateIdentifiers(MySQLAdaptor adaptor, Map> updates) { - for (List listOfUpdaters : updates.values()) { - listOfUpdaters.forEach(updater -> { - try { - updater.updateIdentifier(adaptor, getConfig().getPersonId()); - } catch (Exception e) { - logger.error("Exception caught while trying to update identifier: " + - listOfUpdaters + " ; Exception is: ", e); - } - }); + private void updateIdentifiers(Map> updates) throws Exception { + for (COSMICIdentifierUpdater updater : getAllCOSMICIdentifierUpdaters(updates)) { + updater.updateIdentifier(getModifiedInstanceEdit()); } } + private List getAllCOSMICIdentifierUpdaters( + Map> updates) { + + return updates.values().stream().flatMap(List::stream).collect(Collectors.toList()); + } + private Config getConfig() { return this.config; } @@ -149,4 +152,17 @@ private Config getConfig() { private COSMICFileManager getCosmicFileManager() { return this.cosmicFileManager; } + + private GKInstance getModifiedInstanceEdit() throws Exception { + if (this.modifiedInstanceEdit == null) { + this.modifiedInstanceEdit = + InstanceEditUtils.createDefaultIE( + getConfig().getDBA(), + getConfig().getPersonId(), + true, + "Identifier was automatically updated to new identifier by COSMIC Update process." + ); + } + return this.modifiedInstanceEdit; + } } From 905aa0b2f1cd6f6d5a45d17742ee98f42efb5b5d Mon Sep 17 00:00:00 2001 From: Joel Weiser Date: Fri, 15 Aug 2025 03:31:00 -0400 Subject: [PATCH 06/13] uses modified instance edit and other refactorings --- .../cosmicupdate/COSMICIdentifierUpdater.java | 127 ++++++++++-------- 1 file changed, 68 insertions(+), 59 deletions(-) diff --git a/src/main/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdater.java b/src/main/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdater.java index 0244ab2..6105544 100644 --- a/src/main/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdater.java +++ b/src/main/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdater.java @@ -23,34 +23,32 @@ */ public class COSMICIdentifierUpdater implements Comparable { private static final Logger logger = LogManager.getLogger(); - private static GKInstance instanceEditNewCOSV; - private static GKInstance instanceEditPrependCOSM; private String identifier; - private long dbID; + private GKInstance cosmicDatabaseIdentifierInstance; private String suggestedPrefix; private boolean valid; private Set mutationIDs = new HashSet<>(); private String cosvIdentifier; public String getIdentifier() { - return identifier; + return this.identifier; } public void setIdentifier(String identifier) { this.identifier = identifier; } - public long getDbID() { - return dbID; + public GKInstance getCosmicDatabaseIdentifierInstance() { + return this.cosmicDatabaseIdentifierInstance; } - public void setDbID(long dbID) { - this.dbID = dbID; + public void setCosmicDatabaseIdentifierInstance(GKInstance cosmicDatabaseIdentifierInstance) { + this.cosmicDatabaseIdentifierInstance = cosmicDatabaseIdentifierInstance; } public String getSuggestedPrefix() { - return suggestedPrefix; + return this.suggestedPrefix; } public void setSuggestedPrefix(String suggestedPrefix) { @@ -66,15 +64,15 @@ public void setValid(boolean valid) { } public Set getMutationIDs() { - return mutationIDs; + return this.mutationIDs; } - public void setMutationIDs(Set mutationIDs) { - this.mutationIDs = mutationIDs; + public void addMutationID(String mutationID) { + this.mutationIDs.add(mutationID); } public String getCosvIdentifier() { - return cosvIdentifier; + return this.cosvIdentifier; } public void setCosvIdentifier(String cosvIdentifier) { @@ -83,7 +81,7 @@ public void setCosvIdentifier(String cosvIdentifier) { @Override public String toString() { - return "[" + this.getDbID() + "; " + return "[" + this.getCosmicDatabaseIdentifierInstance() + "; " + this.getIdentifier()+ "; " + this.getSuggestedPrefix() + "; " + this.isValid() + "; " @@ -108,75 +106,86 @@ public int compareTo(COSMICIdentifierUpdater other) { /** * Perform an update of a COSMIC identifier. - * @param adaptor - the database adapter to use. - * @param creatorID - the DB_ID of the Creator of this update. + * @param modifiedInstanceEdit * @throws Exception */ - public void updateIdentifier(MySQLAdaptor adaptor, long creatorID) throws Exception { + public void updateIdentifier(GKInstance modifiedInstanceEdit) throws Exception { // If there is a COSV identifier, we'll update using that. - if (this.getCosvIdentifier() != null && !this.getCosvIdentifier().isEmpty()) { - // Create the InstanceEdit, if necessary. - synchronized (COSMICIdentifierUpdater.class) { - if (COSMICIdentifierUpdater.instanceEditNewCOSV == null) { - COSMICIdentifierUpdater.instanceEditNewCOSV = InstanceEditUtils.createDefaultIE(adaptor, creatorID, true, "Identifier was automatically updated to new \"COSV\" identifier by COSMIC Update process."); - } - } - GKInstance identifierObject = adaptor.fetchInstance( this.getDbID()); - - updateIdentifierObject(adaptor, COSMICIdentifierUpdater.instanceEditNewCOSV, identifierObject, this.getCosvIdentifier()); + if (cosvIdentifierExists()) { + updateUsingCOSVIdentifier(modifiedInstanceEdit); } // If no COSV identifier was found, update using the suggested prefix (determined computationally). - else if (this.getSuggestedPrefix() != null && this.getSuggestedPrefix().equalsIgnoreCase(COSMICUpdateUtil.COSMIC_LEGACY_PREFIX)) - { - GKInstance identifierObject = adaptor.fetchInstance( this.getDbID()); - String currentIdentifier = (String) identifierObject.getAttributeValue(ReactomeJavaConstants.identifier); - // If the current identifier already begins with "C" then leave it alone. - // This code is for updating numeric identifiers that have a suggested prefix. - if (!COSMICUpdateUtil.stringStartsWithC(currentIdentifier.toUpperCase())) { - // Create the InstanceEdit, if necessary. - synchronized (COSMICIdentifierUpdater.class) { - if (COSMICIdentifierUpdater.instanceEditPrependCOSM == null) { - COSMICIdentifierUpdater.instanceEditPrependCOSM = InstanceEditUtils.createDefaultIE(adaptor, creatorID, true, "Identifier was automatically prepended with \"COSM\" by COSMIC Update process."); - } - } - updateIdentifierObject(adaptor, COSMICIdentifierUpdater.instanceEditPrependCOSM, identifierObject, this.getSuggestedPrefix() + currentIdentifier); - } + else if (suggestedPrefixIsCOSMICLegacyPrefix()) { + updateUsingSuggestedCOSMICPrefix(modifiedInstanceEdit); } // Some identifiers won't have a COSV identifier in the COSMIC files, and they might not have a suggested prefix either. else { - logger.info("No suggested prefix OR corresponding COSV identifier for {} (DBID: {}) - identifier will not be updated.", this.getIdentifier(), this.getDbID()); + logger.info( + "No suggested prefix OR COSV identifier for {} (DBID: {}) - identifier will not be updated.", + this.getIdentifier(), this.getDbID()); + } + } + + private boolean cosvIdentifierExists() { + return this.getCosvIdentifier() != null && !this.getCosvIdentifier().isEmpty(); + } + + private boolean suggestedPrefixIsCOSMICLegacyPrefix() { + return this.getSuggestedPrefix() != null && + this.getSuggestedPrefix().equalsIgnoreCase(COSMICUpdateUtil.COSMIC_LEGACY_PREFIX); + } + + private void updateUsingCOSVIdentifier(GKInstance modifiedInstanceEdit) throws Exception { + updateCOSMICDatabaseIdentifierInstance(this.getCosvIdentifier(), modifiedInstanceEdit); + } + + private void updateUsingSuggestedCOSMICPrefix(GKInstance modifiedInstanceEdit) throws Exception { + GKInstance cosmicDatabaseIdentifierInstance = this.getCosmicDatabaseIdentifierInstance(); + String currentCOSMICIdentifier = (String) cosmicDatabaseIdentifierInstance.getAttributeValue(ReactomeJavaConstants.identifier); + // If the current identifier already begins with "C" then leave it alone. + // This code is for updating numeric identifiers that have a suggested prefix. + if (!COSMICUpdateUtil.stringStartsWithC(currentCOSMICIdentifier.toUpperCase())) { + String newCOSMICIdentifier = this.getSuggestedPrefix() + currentCOSMICIdentifier; + updateCOSMICDatabaseIdentifierInstance(newCOSMICIdentifier, modifiedInstanceEdit); } } /** * Executes an update on an instance. * Sets the identifier attribute of identifierObject to the value of identifierValue. - * identifierObject (which must be an InstanceEdit) will also have modifiedForCOSMICUpdate added to its modified list. - * The display name of identifierObject will also be regenerated to reflect changes in identifierValue. - * @param adaptor - * @param modifiedForCOSMICUpdate An InstanceEdit which explains why an instance was modified. - * @param identifierObject An object (probably a DatabaseIdentifier, though there is no actual restriction on type at this point) that represents a COSMIC identifier. + * identifierObject (which must be an InstanceEdit) will also have modifiedForCOSMICUpdate + * added to its modified list. + * The display name of identifierObject will also be regenerated to reflect changes in + * identifierValue. * @param identifierValue An identifier value that will be set on identifierObject + * @param modifiedInstanceEdit An InstanceEdit which explains why an instance was modified. * @throws InvalidAttributeException * @throws Exception * @throws InvalidAttributeValueException */ - private void updateIdentifierObject( - MySQLAdaptor adaptor, GKInstance modifiedForCOSMICUpdate, GKInstance identifierObject, String identifierValue + private void updateCOSMICDatabaseIdentifierInstance( + String identifierValue, GKInstance modifiedInstanceEdit ) throws InvalidAttributeException, Exception, InvalidAttributeValueException { + GKInstance cosmicDatabaseIdentifierInstance = getCosmicDatabaseIdentifierInstance(); // Set the identifier value. - identifierObject.setAttributeValue(ReactomeJavaConstants.identifier, identifierValue); + cosmicDatabaseIdentifierInstance.setAttributeValue(ReactomeJavaConstants.identifier, identifierValue); // Add the instance edit to the modified list - List modifications = (List) identifierObject.getAttributeValuesList(ReactomeJavaConstants.modified); - modifications.add(modifiedForCOSMICUpdate); - identifierObject.setAttributeValue(ReactomeJavaConstants.modified, modifications); + List modifications = + (List) cosmicDatabaseIdentifierInstance.getAttributeValuesList(ReactomeJavaConstants.modified); + modifications.add(modifiedInstanceEdit); + cosmicDatabaseIdentifierInstance.setAttributeValue(ReactomeJavaConstants.modified, modifications); // Update the displayname after other changes (setDisplayName will generate a new value and then set it) - InstanceDisplayNameGenerator.setDisplayName(identifierObject); - - adaptor.updateInstanceAttribute(identifierObject, ReactomeJavaConstants.identifier); - adaptor.updateInstanceAttribute(identifierObject, ReactomeJavaConstants.modified); - adaptor.updateInstanceAttribute(identifierObject, ReactomeJavaConstants._displayName); + InstanceDisplayNameGenerator.setDisplayName(cosmicDatabaseIdentifierInstance); + + MySQLAdaptor adaptor = (MySQLAdaptor) cosmicDatabaseIdentifierInstance.getDbAdaptor(); + adaptor.updateInstanceAttribute(cosmicDatabaseIdentifierInstance, ReactomeJavaConstants.identifier); + adaptor.updateInstanceAttribute(cosmicDatabaseIdentifierInstance, ReactomeJavaConstants.modified); + adaptor.updateInstanceAttribute(cosmicDatabaseIdentifierInstance, ReactomeJavaConstants._displayName); + } + + private long getDbID() { + return getCosmicDatabaseIdentifierInstance().getDBID(); } } From 906353de41e5722870d29700a35d4b604ca3346e Mon Sep 17 00:00:00 2001 From: Joel Weiser Date: Fri, 15 Aug 2025 03:33:09 -0400 Subject: [PATCH 07/13] moves reports into own class and other refactorings --- .../cosmicupdate/COSMICUpdateUtil.java | 495 +++++++++--------- .../reactome/release/cosmicupdate/Report.java | 113 ++++ 2 files changed, 359 insertions(+), 249 deletions(-) create mode 100644 src/main/java/org/reactome/release/cosmicupdate/Report.java diff --git a/src/main/java/org/reactome/release/cosmicupdate/COSMICUpdateUtil.java b/src/main/java/org/reactome/release/cosmicupdate/COSMICUpdateUtil.java index 0a29311..6368233 100644 --- a/src/main/java/org/reactome/release/cosmicupdate/COSMICUpdateUtil.java +++ b/src/main/java/org/reactome/release/cosmicupdate/COSMICUpdateUtil.java @@ -1,27 +1,13 @@ package org.reactome.release.cosmicupdate; -import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; -import java.io.FileWriter; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.sql.SQLException; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.BiFunction; +import java.util.*; import java.util.stream.Collectors; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVParser; -import org.apache.commons.csv.CSVPrinter; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.gk.model.GKInstance; @@ -30,264 +16,272 @@ import org.gk.schema.InvalidAttributeException; /* - * Thie class contains utility methods that are to be used for updating COSMIC identifiers. + * This class contains utility methods that are to be used for updating COSMIC identifiers. */ -public class COSMICUpdateUtil -{ +public class COSMICUpdateUtil { static final String COSMIC_LEGACY_PREFIX = "COSM"; + static final String COSMIC_FUSION_PREFIX = "COSF"; + private static final String COSMIC_FUSION_ID = "FUSION_ID"; private static final String COSMIC_GENOMIC_MUTATION_ID = "GENOMIC_MUTATION_ID"; private static final String COSMIC_MUTATION_ID = "MUTATION_ID"; private static final String COSMIC_LEGACY_MUTATION_ID = "LEGACY_MUTATION_ID"; - static final String COSMIC_FUSION_PREFIX = "COSF"; private static final Logger logger = LogManager.getLogger(); - private static String dateSuffix; - private static String reportsDirectoryPath = "reports"; + + private static Report report = new Report(); + // Private constructor to prevent instantiation of utility class - private COSMICUpdateUtil() - { + private COSMICUpdateUtil() { // ...no-op } - - static - { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_kkmmss"); - COSMICUpdateUtil.dateSuffix = formatter.format(LocalDateTime.now()); - } - + /** * Validate the identifiers in the database by comparing them to the identifiers in the file. - * @param updaters A map of updaters (actually, it's a LIST of updaters, in case > 1 object is identified by the same identifier value), keyed by COSMIC identifier. + * @param updaters A map of updaters (actually, it's a LIST of updaters, in case > 1 object is identified by the + * same identifier value), keyed by COSMIC identifier. * @param COSMICFusionExportFile The path to the COSMIC Fusion Export file. * @param COSMICMutationTrackingFile The path to the COSMIC Mutation Tracking file. * @param COSMICMutantExportFile The path to the COMSIC Mutant Export file. * @throws IOException * @throws FileNotFoundException */ - static void validateIdentifiersAgainstFiles(Map> updaters, String COSMICFusionExportFile, String COSMICMutationTrackingFile, String COSMICMutantExportFile) throws IOException, FileNotFoundException - { - // A COSMIC identifier is "valid" if it can be mapped in the COMSIC files. - // First, process COSF identifiers. A COSMIC Fustion (COSF) identifier is valid if it can be found in the COSMIC Fusion Export file. Pretty simple, right? It gets better, below. ;) + static void validateIdentifiersAgainstFiles( + Map> updaters, + String COSMICFusionExportFile, + String COSMICMutationTrackingFile, + String COSMICMutantExportFile + ) throws IOException, FileNotFoundException { + // A COSMIC identifier is "valid" if it can be mapped in the COSMIC files. + // First, process COSF identifiers. A COSMIC Fusion (COSF) identifier is valid if it can be found in the + // COSMIC Fusion Export file. Pretty simple, right? It gets better, below. ;) // // Handle the other COSMIC identifiers (COSM/COSV) - // Step 1: Look at the COSMIC Mutation Tracking file (a file that maps from old legacy COSM identifiers to new COSV identifiers), and create mappings. - // Step 2: Look at the COSMIC Mutant Export file (a file with all COSMIC coding point mutations from targeted and genome wide screens from the current release). - // IFF an identifier is in Mutant Export, add (to the Updater object) any additional mutations from Mutant Export, set COSV identifier, - // and indicate that the identifier is VALID. + // Step 1: Look at the COSMIC Mutation Tracking file (a file that maps from old legacy COSM identifiers to new + // COSV identifiers), and create mappings. + // Step 2: Look at the COSMIC Mutant Export file (a file with all COSMIC coding point mutations from targeted + // and genome wide screens from the current release). + // IFF an identifier is in Mutant Export, add (to the Updater object) any additional mutations from + // Mutant Export, set COSV identifier, and indicate that the identifier is VALID. // - // The goal is to set valid = true for an identifier that is currently valid in COSMIC - if you search that identifier, or create a link containing it, you will get - // a result. Sometimes, there is no mapping to a COSV identifier for a given COSM identifier. This will result in "valid == false". - // It may also happen that a mapping from a COSM to a COSV does exist in Mutation Tracking, but the COSM is not in Mutant Export, meaning it is not - // a *current* identifier in the current COSMIC database, so it will also have "valid == false". + // The goal is to set valid = true for an identifier that is currently valid in COSMIC - if you search that + // identifier or create a link containing it, you will get a result. Sometimes, there is no mapping to a + // COSV identifier for a given COSM identifier. This will result in "valid == false". + // It may also happen that a mapping from a COSM to a COSV does exist in Mutation Tracking, but the COSM is + // not in Mutant Export, meaning it is not a *current* identifier in the current COSMIC database, so it will + // also have "valid == false". - validateAgainstCosmicFusionExport(updaters, COSMICFusionExportFile); - validateAgainstCosmicMutationTracking(updaters, COSMICMutationTrackingFile); - validateAgainstCosmicMutantExport(updaters, COSMICMutantExportFile); + validateAgainstCosmicFusionExportFile(updaters, COSMICFusionExportFile); + validateAgainstCosmicMutationTrackingFile(updaters, COSMICMutationTrackingFile); + validateAgainstCosmicMutantExportFile(updaters, COSMICMutantExportFile); } - - private static void validateAgainstCosmicMutantExport(Map> updaters, String COSMICMutantExportFile) throws IOException, FileNotFoundException - { - logger.info("Now checking with CosmicMutantExport.tsv..."); - try(CSVParser parser = new CSVParser(new FileReader(COSMICMutantExportFile), CSVFormat.DEFAULT.withFirstRecordAsHeader().withDelimiter('\t')); ) - { - parser.forEach(record -> { - String legacyID = record.get(COSMIC_LEGACY_MUTATION_ID); - String mutationID = record.get(COSMIC_MUTATION_ID); - String genomicID = record.get(COSMIC_GENOMIC_MUTATION_ID); - if (updaters.containsKey(legacyID)) - { - updaters.get(legacyID).forEach(updater -> { - updater.setValid(true); // only VALID if in MutantExport... - updater.getMutationIDs().add(mutationID); - updater.setCosvIdentifier(genomicID); - }); + private static void validateAgainstCosmicFusionExportFile( + Map> updaters, String COSMICFusionExportFile) throws IOException { + + Set fusionIDs = getCOSMICFusionIds(updaters); + logger.info("Now checking with CosmicFusionExport.tsv..."); + try(CSVParser parser = getCSVParser(COSMICFusionExportFile)) { + parser.forEach( record -> { + String fusionID = record.get(COSMIC_FUSION_ID); + if (fusionIDs.contains(fusionID)) { + // COSF identifiers are valid if they are in the Fusion Export mapping. + updaters.get(COSMIC_FUSION_PREFIX+fusionID).forEach(updater -> updater.setValid(true)); } }); } } - private static void validateAgainstCosmicMutationTracking(Map> updaters, String COSMICMutationTrackingFile) throws IOException, FileNotFoundException - { + private static void validateAgainstCosmicMutationTrackingFile( + Map> updaters, String COSMICMutationTrackingFile) throws IOException { + logger.info("Now checking with CosmicMutationTracking.tsv..."); // Now we need to look through the HUGE file from COSMIC and see if we can map the identifiers... - try(CSVParser parser = new CSVParser(new FileReader(COSMICMutationTrackingFile), CSVFormat.DEFAULT.withFirstRecordAsHeader().withDelimiter('\t'));) - { + try(CSVParser parser = getCSVParser(COSMICMutationTrackingFile)) { parser.forEach(record -> { String legacyID = record.get(COSMIC_LEGACY_MUTATION_ID); String mutationID = record.get(COSMIC_MUTATION_ID); String genomicID = record.get(COSMIC_GENOMIC_MUTATION_ID); - if (updaters.containsKey(legacyID)) - { + if (updaters.containsKey(legacyID)) { updaters.get(legacyID).forEach(updater -> { // It is not yet known if this identifier will be valid as per COSMIC's data. - updater.getMutationIDs().add(mutationID); + updater.addMutationID(mutationID); updater.setCosvIdentifier(genomicID); }); } - }); } } + + private static void validateAgainstCosmicMutantExportFile( + Map> updaters, String COSMICMutantExportFile) throws IOException { - private static void validateAgainstCosmicFusionExport(Map> updaters, String COSMICFusionExportFile) throws IOException, FileNotFoundException - { - Set fusionIDs = updaters.keySet().parallelStream().filter(id -> id.toUpperCase().startsWith(COSMIC_FUSION_PREFIX)).map(id -> id.toUpperCase().replace(COSMIC_FUSION_PREFIX,"") ).collect(Collectors.toSet()); - logger.info("Now checking with CosmicFusionExport.tsv..."); - try(CSVParser parser = new CSVParser(new FileReader(COSMICFusionExportFile), CSVFormat.DEFAULT.withFirstRecordAsHeader().withDelimiter('\t')); ) - { - parser.forEach( record -> { - String fusionID = record.get(COSMIC_FUSION_ID); - if (fusionIDs.contains(fusionID)) - { - // COSF identifiers are valid if they are in the Fusion Export mapping. - updaters.get(COSMIC_FUSION_PREFIX+fusionID).forEach(updater -> updater.setValid(true)); + logger.info("Now checking with CosmicMutantExport.tsv..."); + try(CSVParser parser = getCSVParser(COSMICMutantExportFile)) { + parser.forEach(record -> { + String legacyID = record.get(COSMIC_LEGACY_MUTATION_ID); + String mutationID = record.get(COSMIC_MUTATION_ID); + String genomicID = record.get(COSMIC_GENOMIC_MUTATION_ID); + if (updaters.containsKey(legacyID)) { + updaters.get(legacyID).forEach(updater -> { + updater.setValid(true); // only VALID if in MutantExport... + updater.addMutationID(mutationID); + updater.setCosvIdentifier(genomicID); + }); } }); } } + private static CSVParser getCSVParser(String cosmicFileName) throws IOException { + return new CSVParser( + new FileReader(cosmicFileName), + CSVFormat.DEFAULT.withFirstRecordAsHeader().withDelimiter('\t') + ); + } + + private static Set getCOSMICFusionIds(Map> updaters) { + return updaters.keySet() + .parallelStream() + .filter(id -> id.toUpperCase().startsWith(COSMIC_FUSION_PREFIX)) + .map(id -> id.toUpperCase().replace(COSMIC_FUSION_PREFIX,"")) + .collect(Collectors.toSet()); + } + /** * Determines the prefixes for COSMIC identifiers. The rule is: * IF an object has EWASes and there is an EWAS with a FragmentReplacedModification or a FragmentInsertionModification whose referenceSequence * is NOT the referenceEntity of the EWAS... then the suggested prefix will be COSF (for Fusion), otherwise, COSM is suggested. * @param cosmicObjects Objects that are identified by a COSMIC identifier. * @return A map of COSMICIdentifierUpdater, keyed by COSMIC identifier. - * @throws InvalidAttributeException * @throws Exception - * @throws IOException */ - static Map> determinePrefixes(Collection cosmicObjects) throws InvalidAttributeException, Exception, IOException - { + static Map> determinePrefixes(Collection cosmicObjects) + throws Exception { + Map> updates = new HashMap<>(); - // Create the reports directory if it's missing. - Files.createDirectories(Paths.get(COSMICUpdateUtil.reportsDirectoryPath)); - - try(CSVPrinter nonEWASPrinter = new CSVPrinter(new FileWriter(COSMICUpdateUtil.reportsDirectoryPath + File.separator + "nonEWASObjectsWithCOSMICIdentifiers_"+dateSuffix+".csv"), CSVFormat.DEFAULT.withHeader("COSMIC identifier", "non-EWAS entity")); - CSVPrinter identifiersWithNoReferrerPrinter = new CSVPrinter(new FileWriter(COSMICUpdateUtil.reportsDirectoryPath + File.separator + "COSMICIdentifiersNoReferrers_"+dateSuffix+".csv"), CSVFormat.DEFAULT.withHeader("COSMIC identifier"))) - { - for (GKInstance cosmicObject : cosmicObjects) - { - String identifier = (String)cosmicObject.getAttributeValue(ReactomeJavaConstants.identifier); - COSMICIdentifierUpdater updater = new COSMICIdentifierUpdater(); - updater.setIdentifier(identifier); - updater.setDbID(cosmicObject.getDBID()); - - @SuppressWarnings("unchecked") - Collection EWASes = cosmicObject.getReferers(ReactomeJavaConstants.crossReference); - // If NO EWASes exist, then log this information. - if (EWASes == null || EWASes.isEmpty()) - { - identifiersWithNoReferrerPrinter.printRecord(identifier); - } - else - { - // Check the EWASes for mismatches between referenceSequence identifier and main identifier. - // If there's a mismatch then suggest COSF, else suggest COSM. - checkEWASes(nonEWASPrinter, identifier, updater, EWASes); - } - - // support function for populating list. - BiFunction, ? extends List> listPopulator = (k,v) -> { - if (v == null) - { - List updaters = new ArrayList<>(); - updaters.add(updater); - return updaters; - } - else - { - v.add(updater); - return v; - } - }; - - // If the identifier starts with C it's not a numeric identifier. - if (COSMICUpdateUtil.stringStartsWithC(identifier)) - { - updates.compute(updater.getIdentifier(), listPopulator ); - - } - else - { - updates.compute(updater.getSuggestedPrefix() + updater.getIdentifier(), listPopulator ); - } - } + for (GKInstance cosmicObject : cosmicObjects) { + processCosmicObject(cosmicObject, updates); } + return updates; } + private static void processCosmicObject( + GKInstance cosmicObject, + Map> updates + ) throws Exception { + + String identifier = (String) cosmicObject.getAttributeValue(ReactomeJavaConstants.identifier); + COSMICIdentifierUpdater updater = new COSMICIdentifierUpdater(); + updater.setIdentifier(identifier); + updater.setCosmicDatabaseIdentifierInstance(cosmicObject); + + @SuppressWarnings("unchecked") + Collection ewases = cosmicObject.getReferers(ReactomeJavaConstants.crossReference); + + if (ewases == null || ewases.isEmpty()) { + report.printIdentifierWithNoReferrerRecord(identifier); + } else { + checkEWASes(identifier, updater, ewases); + } + + addUpdaterToMap(updates, updater); + } + + private static void addUpdaterToMap( + Map> updates, + COSMICIdentifierUpdater updater + ) { + String cosmicIdentifier = COSMICUpdateUtil.stringStartsWithC(updater.getIdentifier()) + ? updater.getIdentifier() + : updater.getSuggestedPrefix() + updater.getIdentifier(); + + updates.computeIfAbsent(cosmicIdentifier, k -> new ArrayList<>()).add(updater); + } + + /** - * Checks EWASes to see if they have modifiedResidues that have a referenceSequence that is NOT the same as the EWASes referenceEntity. - * The suggested prefix will be set to COSF on the update record if mismatches are found, otherwise COSM will be set. - * @param nonEWASPrinter CSVPrinter for reporting. + * Checks EWASes to see if they have modifiedResidues that have a referenceSequence that is NOT the same as the + * EWASes referenceEntity. + * The suggested prefix will be set to COSF on the update record if mismatches are found, otherwise COSM will be + * set. * @param identifier Identifier of the object being checked, used for reporting. * @param updater A COSMICIdentifierUpdater whose suggested prefix will be updated. * @param EWASes The EWASes to check. If a non-EWAS is in this list, it will be reported. * @throws InvalidAttributeException * @throws Exception - * @throws IOException */ - private static void checkEWASes(CSVPrinter nonEWASPrinter, String identifier, COSMICIdentifierUpdater updater, Collection EWASes) throws InvalidAttributeException, Exception, IOException - { - String prefix; - GKInstance[] EWASArray = EWASes.toArray(new GKInstance[0]); - boolean done = false; - int i = 0; - while(!done) - { - boolean foundMismatchedRefSequence = false; - GKInstance ewas = EWASArray[i]; - if (ewas.getSchemClass().getName().equals(ReactomeJavaConstants.EntityWithAccessionedSequence)) - { - GKInstance refSequence = (GKInstance) ewas.getAttributeValue(ReactomeJavaConstants.referenceEntity); - // get hasModifiedResidue - @SuppressWarnings("unchecked") - List modResidues = (List) ewas.getAttributeValuesList(ReactomeJavaConstants.hasModifiedResidue); - - foundMismatchedRefSequence = referenceSequenceMismatchesResidues(refSequence, modResidues); - - // If there is any mismatch, then COSF. - prefix = foundMismatchedRefSequence ? COSMIC_FUSION_PREFIX : COSMIC_LEGACY_PREFIX; - updater.setSuggestedPrefix(prefix); + private static void checkEWASes( + String identifier, + COSMICIdentifierUpdater updater, + Collection EWASes + ) throws InvalidAttributeException, Exception { + + for (GKInstance potentialEWAS : EWASes) { + if (!isValidEWAS(potentialEWAS)) { + report.printNonEWASRecord(identifier, potentialEWAS.toString()); + continue; } - else - { - nonEWASPrinter.printRecord(identifier, ewas.toString()); + + GKInstance refSequence = (GKInstance) potentialEWAS.getAttributeValue(ReactomeJavaConstants.referenceEntity); + + @SuppressWarnings("unchecked") + List modResidues = + (List) potentialEWAS.getAttributeValuesList(ReactomeJavaConstants.hasModifiedResidue); + + boolean foundMismatchedRefSequence = referenceSequenceMismatchesResidues(refSequence, modResidues); + + String prefix = foundMismatchedRefSequence + ? COSMIC_FUSION_PREFIX + : COSMIC_LEGACY_PREFIX; + + updater.setSuggestedPrefix(prefix); + + if (foundMismatchedRefSequence) { + break; // stop processing once a mismatch is found } - i++; - done = foundMismatchedRefSequence || i >= EWASArray.length; } } + private static boolean isValidEWAS(GKInstance potentialEWAS) { + return potentialEWAS.getSchemClass().getName().equals(ReactomeJavaConstants.EntityWithAccessionedSequence); + } + + /** - * Checks modifiedResidues (only FragmentReplacedModification and FragmentInsertionModification are of interest) to see if they match - * refSequence. + * Checks modifiedResidues (only FragmentReplacedModification and FragmentInsertionModification are of interest) to + * see if they match refSequence. * @param refSequence A Reference Sequence * @param modResidues The modified residues. - * @return TRUE if there is a mismatch: a mismatch is when the reference sequence DBID != the modifiedResidues' referenceSequence's DBID. FALSE, otherwise. + * @return TRUE if there is a mismatch: a mismatch is when the reference sequence DBID != the modifiedResidues' + * referenceSequence's DBID. FALSE, otherwise. * @throws InvalidAttributeException * @throws Exception */ - private static boolean referenceSequenceMismatchesResidues(GKInstance refSequence, List modResidues) throws InvalidAttributeException, Exception - { - boolean foundMismatchedRefSequence = false; - int i = 0; - while (!foundMismatchedRefSequence && i < modResidues.size()) - { - GKInstance modResidue = modResidues.get(i); - if (modResidue.getSchemClass().getName().contains(ReactomeJavaConstants.FragmentReplacedModification) - || modResidue.getSchemClass().getName().contains(ReactomeJavaConstants.FragmentInsertionModification)) - { - GKInstance residueRefSequence = (GKInstance) modResidue.getAttributeValue(ReactomeJavaConstants.referenceSequence); - foundMismatchedRefSequence = !residueRefSequence.getDBID().equals(refSequence.getDBID()); + private static boolean referenceSequenceMismatchesResidues(GKInstance refSequence, List modResidues) + throws InvalidAttributeException, Exception { + + long refSequenceId = refSequence.getDBID(); + + for (GKInstance modResidue : modResidues) { + String className = modResidue.getSchemClass().getName(); + + if (className.contains(ReactomeJavaConstants.FragmentReplacedModification) || + className.contains(ReactomeJavaConstants.FragmentInsertionModification)) { + + GKInstance residueRefSequence = + (GKInstance) modResidue.getAttributeValue(ReactomeJavaConstants.referenceSequence); + + if (!residueRefSequence.getDBID().equals(refSequenceId)) { + return true; // Found a mismatch + } } - i++; } - return foundMismatchedRefSequence; + return false; // No mismatches found } + /** * Gets COSMIC identifiers from the database. * Queries the database for a ReferenceDatabase named "COSMIC" and then gets all DatabaseIdentifier objects @@ -297,82 +291,85 @@ private static boolean referenceSequenceMismatchesResidues(GKInstance refSequenc * ReferenceDatabase. * @param adaptor * @return A Collection of DatabaseIdentifier objects. - * @throws SQLException * @throws Exception - * @throws InvalidAttributeException */ - static Collection getCOSMICIdentifiers(MySQLAdaptor adaptor) throws SQLException, Exception, InvalidAttributeException - { - @SuppressWarnings("unchecked") - Collection refDBs = adaptor.fetchInstanceByAttribute(ReactomeJavaConstants.ReferenceDatabase, ReactomeJavaConstants.name, " = ", "COSMIC"); - GKInstance cosmicRefDB = null; - if (refDBs.size() == 1) - { - cosmicRefDB = new ArrayList<>(refDBs).get(0); - } - else - { - logger.fatal("Wrong number of \"COSMIC\" refDBs: {} ; only 1 was expected. Cannot proceed.", refDBs.size()); - System.exit(1); - } + static Collection getCOSMICDatabaseIdentifierInstances(MySQLAdaptor adaptor) + throws Exception { + GKInstance cosmicReferenceDatabase = getCOSMICReferenceDatabaseOrThrow(adaptor); @SuppressWarnings("unchecked") - Collection cosmicObjects = adaptor.fetchInstanceByAttribute(ReactomeJavaConstants.DatabaseIdentifier, ReactomeJavaConstants.referenceDatabase, " = ", cosmicRefDB.getAttributeValue(ReactomeJavaConstants.DB_ID)); + Collection cosmicDatabaseIdentifierInstances = adaptor.fetchInstanceByAttribute( + ReactomeJavaConstants.DatabaseIdentifier, + ReactomeJavaConstants.referenceDatabase, + " = ", + cosmicReferenceDatabase.getDBID() + ); - return cosmicObjects; + return cosmicDatabaseIdentifierInstances; } /** - * Produces a report on identifiers. Report indicates old/"legacy" identifiers, suggested prefixes, new identifiers suggested from COSMIC files, - * and validity of old identifiers. + * Produces a report on identifiers. Report indicates old/"legacy" identifiers, suggested prefixes, new + * identifiers suggested from COSMIC files, and validity of old identifiers. * @param updaters The map of identifier updaters. - * @throws IOException */ - public static void printIdentifierUpdateReport(Map> updaters) throws IOException - { - // Create the reports directory if it's missing. - Files.createDirectories(Paths.get(COSMICUpdateUtil.reportsDirectoryPath)); - try(CSVPrinter printer = new CSVPrinter(new FileWriter(COSMICUpdateUtil.reportsDirectoryPath + "/COSMIC-identifiers-report_"+dateSuffix+".csv"), CSVFormat.DEFAULT.withHeader("DB_ID", "Identifier", "Suggested Prefix", "Valid (according to COSMIC files)?", "COSV identifier", "Mutation IDs", "COSMIC Search URL"))) - { - for (COSMICIdentifierUpdater record : updaters.values().parallelStream().flatMap(Collection::stream).sorted().collect(Collectors.toList())) - { - // Include a COSMIC Search URL for the identifier in the report, to make it easier for Curators to follow up on identifiers that might need attention. - String url; - String identifierForUrl = ""; - if (COSMICUpdateUtil.stringStartsWithC(record.getIdentifier())) - { - identifierForUrl = record.getIdentifier(); - } - else - { - if (record.getSuggestedPrefix() != null) - { - identifierForUrl = record.getSuggestedPrefix() + record.getIdentifier(); - } - else - { - identifierForUrl = record.getIdentifier(); - } - } - url = "https://cancer.sanger.ac.uk/cosmic/search?q=" + identifierForUrl; - printer.printRecord(record.getDbID(), record.getIdentifier(), record.getSuggestedPrefix(), record.isValid(), record.getCosvIdentifier(), record.getMutationIDs().toString(), url); - } + public static void printIdentifierUpdateReport(Map> updaters) { + + for (COSMICIdentifierUpdater record : getCosmicRecords(updaters)) { + report.printIdentifierUpdateRecord(getIdentifierUpdateReportLineValues(record)); } } + + public static boolean stringStartsWithC(String s) { + return s.startsWith("C"); + } + - public static synchronized String getReportsDirectoryPath() - { - return reportsDirectoryPath; + private static List getCosmicRecords(Map> updaters) { + return updaters.values().parallelStream().flatMap(Collection::stream).sorted().collect(Collectors.toList()); } - public static synchronized void setReportsDirectoryPath(String reportsDirectoryPath) - { - COSMICUpdateUtil.reportsDirectoryPath = reportsDirectoryPath; + private static Object[] getIdentifierUpdateReportLineValues(COSMICIdentifierUpdater record) { + return Arrays.asList( + record.getCosmicDatabaseIdentifierInstance().getDBID(), + record.getIdentifier(), + record.getSuggestedPrefix(), + record.isValid(), + record.getCosvIdentifier(), + record.getMutationIDs().toString(), + getCosmicSearchURL(record) + ).toArray(new Object[0]); } - - public static boolean stringStartsWithC(String s) - { - return s.startsWith("C"); + + private static String getCosmicSearchURL(COSMICIdentifierUpdater record) { + return "https://cancer.sanger.ac.uk/cosmic/search?q=" + getIdentifierForUrl(record); + } + + private static String getIdentifierForUrl(COSMICIdentifierUpdater cosmicIdentifierRecord) { + String identifier = cosmicIdentifierRecord.getIdentifier(); + + if (COSMICUpdateUtil.stringStartsWithC(identifier)) { + return identifier; + } + + String prefix = cosmicIdentifierRecord.getSuggestedPrefix(); + return (prefix != null) ? prefix + identifier : identifier; + } + + + private static GKInstance getCOSMICReferenceDatabaseOrThrow(MySQLAdaptor adaptor) throws Exception { + @SuppressWarnings("unchecked") + Collection cosmicReferenceDatabaseInstances = adaptor.fetchInstanceByAttribute( + ReactomeJavaConstants.ReferenceDatabase, ReactomeJavaConstants.name, " = ", "COSMIC"); + + if (cosmicReferenceDatabaseInstances.size() != 1) { + String errorMessage = "Wrong number of \"COSMIC\" refDBs: " + cosmicReferenceDatabaseInstances.size() + + " ; only 1 was expected. Cannot proceed."; + logger.fatal(errorMessage); + throw new RuntimeException(errorMessage); + } + + return cosmicReferenceDatabaseInstances.iterator().next(); } -} +} \ No newline at end of file diff --git a/src/main/java/org/reactome/release/cosmicupdate/Report.java b/src/main/java/org/reactome/release/cosmicupdate/Report.java new file mode 100644 index 0000000..8261a77 --- /dev/null +++ b/src/main/java/org/reactome/release/cosmicupdate/Report.java @@ -0,0 +1,113 @@ +package org.reactome.release.cosmicupdate; + +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVPrinter; + +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; + +public class Report { + private static final String REPORTS_DIRECTORY_PATH = "reports"; + + private final String dateSuffix; + + private CSVPrinter nonEWASPrinter; + private CSVPrinter identifiersWithNoReferrerPrinter; + private CSVPrinter identifierUpdatePrinter; + + public Report() { + this.dateSuffix = setDateSuffix(); + initReports(); + } + + public void printIdentifierWithNoReferrerRecord(String identifier) { + try { + identifiersWithNoReferrerPrinter.printRecord(identifier); + identifiersWithNoReferrerPrinter.flush(); + } catch (IOException e) { + throw new RuntimeException("Unable to print identifier with no referrer record", e); + } + } + + public void printNonEWASRecord(String identifier, String instanceDisplayNameAndDbId) { + try { + nonEWASPrinter.printRecord(identifier, instanceDisplayNameAndDbId); + nonEWASPrinter.flush(); + } catch (IOException e) { + throw new RuntimeException("Unable to print non-EWAS record", e); + } + } + + public void printIdentifierUpdateRecord(Object[] identifierUpdateReportLineValues) { + try { + identifierUpdatePrinter.printRecord(identifierUpdateReportLineValues); + identifierUpdatePrinter.flush(); + } catch (IOException e) { + throw new RuntimeException("Unable to print identifier update record", e); + } + } + + private void initReports() { + try { + createReportDirectoryIfNotExists(); + + nonEWASPrinter = new CSVPrinter( + new FileWriter(getNonEWASReportFileName()), + CSVFormat.DEFAULT.withHeader("COSMIC identifier", "non-EWAS entity") + ); + + identifiersWithNoReferrerPrinter = new CSVPrinter( + new FileWriter(getIdentifiersWithNoReferrerReportFileName()), + CSVFormat.DEFAULT.withHeader("COSMIC identifier") + ); + identifierUpdatePrinter = new CSVPrinter( + new FileWriter(getIdentifierUpdateReportFileName()), + CSVFormat.DEFAULT.withHeader(getIdentifierUpdateReportHeader()) + ); + } catch (IOException e) { + throw new RuntimeException("Unable to initialize reports", e); + } + } + + private void createReportDirectoryIfNotExists() throws IOException { + Files.createDirectories(Paths.get(REPORTS_DIRECTORY_PATH)); + } + + private String getNonEWASReportFileName() { + return REPORTS_DIRECTORY_PATH + "/nonEWASObjectsWithCOSMICIdentifiers_" + getDateSuffix() + ".csv"; + } + + private String getIdentifiersWithNoReferrerReportFileName() { + return REPORTS_DIRECTORY_PATH + "/COSMICIdentifiersNoReferrers_" + getDateSuffix() + ".csv"; + } + + private String getIdentifierUpdateReportFileName() { + return REPORTS_DIRECTORY_PATH + "/COSMIC-identifiers-report_" + getDateSuffix() + ".csv"; + } + + private static String[] getIdentifierUpdateReportHeader() { + return Arrays.asList( + "DB_ID", + "Identifier", + "Suggested Prefix", + "Valid (according to COSMIC files)?", + "COSV identifier", + "Mutation IDs", + "COSMIC Search URL" + ).toArray(new String[0]); + } + + private String setDateSuffix() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_kkmmss"); + return formatter.format(LocalDateTime.now()); + } + + private String getDateSuffix() { + return this.dateSuffix; + } +} From a5c25763cae8385d5435f4189b4b444fbe55f78d Mon Sep 17 00:00:00 2001 From: Joel Weiser Date: Fri, 15 Aug 2025 03:45:20 -0400 Subject: [PATCH 08/13] updates config credential key names --- src/main/resources/config.properties | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/resources/config.properties b/src/main/resources/config.properties index 717f8ba..15e9a6f 100644 --- a/src/main/resources/config.properties +++ b/src/main/resources/config.properties @@ -1,8 +1,8 @@ -db.host=localhost -db.user=root -db.password=root -db.name=target_database -db.port=3306 +curator.database.host=localhost +curator.database.user=root +curator.database.password=root +curator.database.name=target_database +curator.database.port=3306 testMode=true pathToMutantExportFile=./CosmicMutantExport.tsv pathToMutationTrackingFile=./CosmicMutationTracking.tsv From 103cbaf751304ed53bb182998eda26fa4b507cee Mon Sep 17 00:00:00 2001 From: Joel Weiser Date: Wed, 20 Aug 2025 22:39:19 -0400 Subject: [PATCH 09/13] adds configurable directory path to report --- .../reactome/release/cosmicupdate/Report.java | 51 +++++++++++-------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/reactome/release/cosmicupdate/Report.java b/src/main/java/org/reactome/release/cosmicupdate/Report.java index 8261a77..12a8d94 100644 --- a/src/main/java/org/reactome/release/cosmicupdate/Report.java +++ b/src/main/java/org/reactome/release/cosmicupdate/Report.java @@ -12,8 +12,8 @@ import java.util.Arrays; public class Report { - private static final String REPORTS_DIRECTORY_PATH = "reports"; - + private String reportsDirectoryPath; + private final String dateSuffix; private CSVPrinter nonEWASPrinter; @@ -21,6 +21,13 @@ public class Report { private CSVPrinter identifierUpdatePrinter; public Report() { + this.reportsDirectoryPath = "reports"; + this.dateSuffix = setDateSuffix(); + initReports(); + } + + public Report(String reportsDirectoryPath) { + this.reportsDirectoryPath = reportsDirectoryPath; this.dateSuffix = setDateSuffix(); initReports(); } @@ -55,19 +62,19 @@ public void printIdentifierUpdateRecord(Object[] identifierUpdateReportLineValue private void initReports() { try { createReportDirectoryIfNotExists(); - + nonEWASPrinter = new CSVPrinter( - new FileWriter(getNonEWASReportFileName()), - CSVFormat.DEFAULT.withHeader("COSMIC identifier", "non-EWAS entity") + new FileWriter(getNonEWASReportFileName()), + CSVFormat.DEFAULT.withHeader("COSMIC identifier", "non-EWAS entity") ); identifiersWithNoReferrerPrinter = new CSVPrinter( - new FileWriter(getIdentifiersWithNoReferrerReportFileName()), - CSVFormat.DEFAULT.withHeader("COSMIC identifier") + new FileWriter(getIdentifiersWithNoReferrerReportFileName()), + CSVFormat.DEFAULT.withHeader("COSMIC identifier") ); identifierUpdatePrinter = new CSVPrinter( - new FileWriter(getIdentifierUpdateReportFileName()), - CSVFormat.DEFAULT.withHeader(getIdentifierUpdateReportHeader()) + new FileWriter(getIdentifierUpdateReportFileName()), + CSVFormat.DEFAULT.withHeader(getIdentifierUpdateReportHeader()) ); } catch (IOException e) { throw new RuntimeException("Unable to initialize reports", e); @@ -75,30 +82,30 @@ private void initReports() { } private void createReportDirectoryIfNotExists() throws IOException { - Files.createDirectories(Paths.get(REPORTS_DIRECTORY_PATH)); + Files.createDirectories(Paths.get(getReportsDirectoryPath())); } private String getNonEWASReportFileName() { - return REPORTS_DIRECTORY_PATH + "/nonEWASObjectsWithCOSMICIdentifiers_" + getDateSuffix() + ".csv"; + return getReportsDirectoryPath() + "/nonEWASObjectsWithCOSMICIdentifiers_" + getDateSuffix() + ".csv"; } private String getIdentifiersWithNoReferrerReportFileName() { - return REPORTS_DIRECTORY_PATH + "/COSMICIdentifiersNoReferrers_" + getDateSuffix() + ".csv"; + return getReportsDirectoryPath() + "/COSMICIdentifiersNoReferrers_" + getDateSuffix() + ".csv"; } private String getIdentifierUpdateReportFileName() { - return REPORTS_DIRECTORY_PATH + "/COSMIC-identifiers-report_" + getDateSuffix() + ".csv"; + return getReportsDirectoryPath() + "/COSMIC-identifiers-report_" + getDateSuffix() + ".csv"; } private static String[] getIdentifierUpdateReportHeader() { return Arrays.asList( - "DB_ID", - "Identifier", - "Suggested Prefix", - "Valid (according to COSMIC files)?", - "COSV identifier", - "Mutation IDs", - "COSMIC Search URL" + "DB_ID", + "Identifier", + "Suggested Prefix", + "Valid (according to COSMIC files)?", + "COSV identifier", + "Mutation IDs", + "COSMIC Search URL" ).toArray(new String[0]); } @@ -110,4 +117,8 @@ private String setDateSuffix() { private String getDateSuffix() { return this.dateSuffix; } + + private String getReportsDirectoryPath() { + return this.reportsDirectoryPath; + } } From 93f968fc5ce99f34b08d99187ada289ae7c9ea46 Mon Sep 17 00:00:00 2001 From: Joel Weiser Date: Wed, 20 Aug 2025 22:50:15 -0400 Subject: [PATCH 10/13] adds method to get and set report --- .../cosmicupdate/COSMICUpdateUtil.java | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/reactome/release/cosmicupdate/COSMICUpdateUtil.java b/src/main/java/org/reactome/release/cosmicupdate/COSMICUpdateUtil.java index 6368233..3243cf4 100644 --- a/src/main/java/org/reactome/release/cosmicupdate/COSMICUpdateUtil.java +++ b/src/main/java/org/reactome/release/cosmicupdate/COSMICUpdateUtil.java @@ -28,7 +28,7 @@ public class COSMICUpdateUtil { private static final String COSMIC_LEGACY_MUTATION_ID = "LEGACY_MUTATION_ID"; private static final Logger logger = LogManager.getLogger(); - private static Report report = new Report(); + private static Report report; // Private constructor to prevent instantiation of utility class private COSMICUpdateUtil() { @@ -181,7 +181,7 @@ private static void processCosmicObject( Collection ewases = cosmicObject.getReferers(ReactomeJavaConstants.crossReference); if (ewases == null || ewases.isEmpty()) { - report.printIdentifierWithNoReferrerRecord(identifier); + getReport().printIdentifierWithNoReferrerRecord(identifier); } else { checkEWASes(identifier, updater, ewases); } @@ -220,7 +220,7 @@ private static void checkEWASes( for (GKInstance potentialEWAS : EWASes) { if (!isValidEWAS(potentialEWAS)) { - report.printNonEWASRecord(identifier, potentialEWAS.toString()); + getReport().printNonEWASRecord(identifier, potentialEWAS.toString()); continue; } @@ -317,7 +317,7 @@ static Collection getCOSMICDatabaseIdentifierInstances(MySQLAdaptor public static void printIdentifierUpdateReport(Map> updaters) { for (COSMICIdentifierUpdater record : getCosmicRecords(updaters)) { - report.printIdentifierUpdateRecord(getIdentifierUpdateReportLineValues(record)); + getReport().printIdentifierUpdateRecord(getIdentifierUpdateReportLineValues(record)); } } @@ -372,4 +372,16 @@ private static GKInstance getCOSMICReferenceDatabaseOrThrow(MySQLAdaptor adaptor return cosmicReferenceDatabaseInstances.iterator().next(); } + + static void setReport(Report report) { + COSMICUpdateUtil.report = report; + } + + private static Report getReport() { + if (report == null) { + setReport(new Report()); + } + + return report; + } } \ No newline at end of file From 2dde3d48001b666cc952c74913287dfc294839dc Mon Sep 17 00:00:00 2001 From: Joel Weiser Date: Wed, 20 Aug 2025 22:55:06 -0400 Subject: [PATCH 11/13] updates tests --- .../COSMICIdentifierUpdaterTest.java | 70 +++++++------------ .../cosmicupdate/COSMICUpdateUtilTest.java | 60 ++++++---------- 2 files changed, 47 insertions(+), 83 deletions(-) diff --git a/src/test/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdaterTest.java b/src/test/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdaterTest.java index 9ae11de..56ec70b 100644 --- a/src/test/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdaterTest.java +++ b/src/test/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdaterTest.java @@ -15,11 +15,7 @@ import org.mockito.MockitoAnnotations; import org.reactome.release.common.database.InstanceEditUtils; -public class COSMICIdentifierUpdaterTest -{ - - private long creatorID = 112233445566L; - +public class COSMICIdentifierUpdaterTest { @Mock private MySQLAdaptor mockAdaptor; @@ -30,8 +26,7 @@ public class COSMICIdentifierUpdaterTest private GKInstance mockIdentifierObject; @Before - public void set() - { + public void set() { MockitoAnnotations.openMocks(this); } @@ -39,24 +34,19 @@ public void set() * Tests attempting to update, but with no COSV identifier set, no update will happen. */ @Test - public void testUpdateIdentifierNoUpdate() - { + public void testUpdateIdentifierNoUpdate() { COSMICIdentifierUpdater updater = new COSMICIdentifierUpdater(); updater.setIdentifier("123456"); // We don't set a COSV identifier, triggering the "no update" execution path. updater.setValid(true); - updater.setDbID(123465789L); - - try - { - try(MockedStatic mockedStatic = Mockito.mockStatic(InstanceEditUtils.class)) - { + updater.setCosmicDatabaseIdentifierInstance(mockIdentifierObject); + + try { + try(MockedStatic mockedStatic = Mockito.mockStatic(InstanceEditUtils.class)) { Mockito.when(InstanceEditUtils.createDefaultIE(any(MySQLAdaptor.class), any(Long.class), any(Boolean.class), any(String.class))).thenReturn(mockInstanceEdit); - updater.updateIdentifier(mockAdaptor, creatorID); + updater.updateIdentifier(mockInstanceEdit); } - } - catch (Exception e) - { + } catch (Exception e) { e.printStackTrace(); fail(); } @@ -66,28 +56,25 @@ public void testUpdateIdentifierNoUpdate() * Tests an update. */ @Test - public void testUpdateIdentifier() - { + public void testUpdateIdentifier() { COSMICIdentifierUpdater updater = new COSMICIdentifierUpdater(); updater.setIdentifier("123456"); updater.setSuggestedPrefix("COSV"); updater.setCosvIdentifier("COSV9393993"); updater.setValid(true); - updater.setDbID(123465789L); - - try - { + updater.setCosmicDatabaseIdentifierInstance(mockIdentifierObject); + + try { try(MockedStatic mockedInstEdUtils = Mockito.mockStatic(InstanceEditUtils.class); - MockedStatic mockedInstDisNameGen = Mockito.mockStatic(InstanceDisplayNameGenerator.class)) - { + MockedStatic mockedInstDisNameGen = Mockito.mockStatic(InstanceDisplayNameGenerator.class)) { + + Mockito.when(mockIdentifierObject.getDbAdaptor()).thenReturn(mockAdaptor); Mockito.when(InstanceEditUtils.createDefaultIE(any(MySQLAdaptor.class), any(Long.class), any(Boolean.class), any(String.class))).thenReturn(mockInstanceEdit); Mockito.when(InstanceDisplayNameGenerator.generateDisplayName(any(GKInstance.class))).thenReturn("TestDisplayName"); Mockito.when(mockAdaptor.fetchInstance(any(Long.class))).thenReturn(mockIdentifierObject); - updater.updateIdentifier(mockAdaptor, creatorID); + updater.updateIdentifier(mockInstanceEdit); } - } - catch (Exception e) - { + } catch (Exception e) { e.printStackTrace(); fail(); } @@ -97,30 +84,27 @@ public void testUpdateIdentifier() * Tests update with a COSM suggested prefix and no COSV identifier. */ @Test - public void testUpdateCOSMIdentifier() - { + public void testUpdateCOSMIdentifier() { COSMICIdentifierUpdater updater = new COSMICIdentifierUpdater(); updater.setIdentifier("123456"); updater.setSuggestedPrefix("COSM"); // testing COSM so don't set a COSV identifier. updater.setValid(true); - updater.setDbID(123465789L); - - try - { + updater.setCosmicDatabaseIdentifierInstance(mockIdentifierObject); + + try { try(MockedStatic mockedInstEdUtils = Mockito.mockStatic(InstanceEditUtils.class); - MockedStatic mockedInstDisNameGen = Mockito.mockStatic(InstanceDisplayNameGenerator.class)) - { + MockedStatic mockedInstDisNameGen = Mockito.mockStatic(InstanceDisplayNameGenerator.class)) { + + Mockito.when(mockIdentifierObject.getDbAdaptor()).thenReturn(mockAdaptor); Mockito.when(InstanceEditUtils.createDefaultIE(any(MySQLAdaptor.class), any(Long.class), any(Boolean.class), any(String.class))).thenReturn(mockInstanceEdit); Mockito.when(InstanceDisplayNameGenerator.generateDisplayName(any(GKInstance.class))).thenReturn("TestDisplayName"); Mockito.when(mockIdentifierObject.getAttributeValue(ReactomeJavaConstants.identifier)).thenReturn("3333"); Mockito.when(mockAdaptor.fetchInstance(any(Long.class))).thenReturn(mockIdentifierObject); - updater.updateIdentifier(mockAdaptor, creatorID); + updater.updateIdentifier(mockInstanceEdit); } - } - catch (Exception e) - { + } catch (Exception e) { e.printStackTrace(); fail(); } diff --git a/src/test/java/org/reactome/release/cosmicupdate/COSMICUpdateUtilTest.java b/src/test/java/org/reactome/release/cosmicupdate/COSMICUpdateUtilTest.java index 71ca38a..8a23eaf 100644 --- a/src/test/java/org/reactome/release/cosmicupdate/COSMICUpdateUtilTest.java +++ b/src/test/java/org/reactome/release/cosmicupdate/COSMICUpdateUtilTest.java @@ -24,8 +24,7 @@ import org.junit.Test; import org.mockito.Mockito; -public class COSMICUpdateUtilTest -{ +public class COSMICUpdateUtilTest { private static final String IDENTIFIER_COSF1234 = "COSF1234"; private static final String IDENTIFIER_1234 = "1234"; @@ -47,8 +46,7 @@ public class COSMICUpdateUtilTest private static final String MUTANT_HEADER = COSMIC_LEGACY_MUTATION_ID + "\t" + COSMIC_MUTATION_ID+ "\t" + COSMIC_GENOMIC_MUTATION_ID + "\n"; @Before - public void setup() throws IOException - { + public void setup() throws IOException { // need to create temp files to read. createTestCosmicFusionExport(); createTestCosmicMutantExport(); @@ -57,8 +55,7 @@ public void setup() throws IOException } - private void createTestCosmicMutationTracking() throws IOException - { + private void createTestCosmicMutationTracking() throws IOException { Path pathToMutationTracking = Files.createTempFile("mutationTracking", "csv"); this.COSMICMutationTrackingFile = pathToMutationTracking.toString(); Files.writeString(pathToMutationTracking, MUTANT_HEADER); @@ -67,8 +64,7 @@ private void createTestCosmicMutationTracking() throws IOException } - private void createTestCosmicMutantExport() throws IOException - { + private void createTestCosmicMutantExport() throws IOException { Path pathToMutantExport = Files.createTempFile("mutantExport", "csv"); this.COSMICMutantExportFile = pathToMutantExport.toString(); Files.writeString(pathToMutantExport, MUTANT_HEADER); @@ -77,8 +73,7 @@ private void createTestCosmicMutantExport() throws IOException } - private void createTestCosmicFusionExport() throws IOException - { + private void createTestCosmicFusionExport() throws IOException { Path pathToCOSF = Files.createTempFile("COSF", "csv"); this.COSMICFusionExportFile = pathToCOSF.toString(); // we only use the FUSION_ID field from the COSMIC Fusion Export. @@ -90,8 +85,7 @@ private void createTestCosmicFusionExport() throws IOException @Test - public void testValidateAgainstFiles() - { + public void testValidateAgainstFiles() { Map> updates = new HashMap<>(); COSMICIdentifierUpdater updater1 = new COSMICIdentifierUpdater(); @@ -100,20 +94,16 @@ public void testValidateAgainstFiles() updates.put(IDENTIFIER_COSF1234, Arrays.asList(updater1)); updates.put(IDENTIFIER_5678, Arrays.asList(updater2)); - try - { + try { COSMICUpdateUtil.validateIdentifiersAgainstFiles(updates, COSMICFusionExportFile, COSMICMutationTrackingFile, COSMICMutantExportFile); - } - catch (IOException e) - { + } catch (IOException e) { e.printStackTrace(); fail(); } } @Test - public void testDeterminePrefixes() throws InvalidAttributeException, IOException, Exception - { + public void testDeterminePrefixes() throws InvalidAttributeException, IOException, Exception { Collection cosmicObjects = new ArrayList<>(); Collection EWASes = new ArrayList<>(); List mockModResidues = new ArrayList<>(); @@ -182,23 +172,21 @@ public void testDeterminePrefixes() throws InvalidAttributeException, IOExceptio cosmicObjects.add(mockCosmicObject3); Path reportPath = Files.createTempDirectory("cosmic_update"); - COSMICUpdateUtil.setReportsDirectoryPath(reportPath.toAbsolutePath().toString()); System.out.println("Reports will be in " + reportPath.toAbsolutePath().toString()); + COSMICUpdateUtil.setReport(new Report(reportPath.toAbsolutePath().toString())); + // test with list Map> result = COSMICUpdateUtil.determinePrefixes(cosmicObjects); assertNotNull(result); assertTrue(!result.isEmpty()); - for (String s : result.keySet()) - { + for (String s : result.keySet()) { System.out.println(s + "\t" + result.get(s).toString()); - if (s.contains(IDENTIFIER_44444)) - { + if (s.contains(IDENTIFIER_44444)) { // The 44444 COSMIC object should get COSF because of mismatch in one of the modified residues. assertTrue(result.get(s).get(0).getSuggestedPrefix().equals("COSF")); } - if (s.contains(IDENTIFIER_5678)) - { + if (s.contains(IDENTIFIER_5678)) { // This should have a COSM prefix. assertTrue(result.get(s).get(0).getSuggestedPrefix().equals("COSM")); } @@ -209,21 +197,14 @@ public void testDeterminePrefixes() throws InvalidAttributeException, IOExceptio boolean nonEWASReportExists = false; DirectoryStream dirStream = Files.newDirectoryStream(reportPath); - for (Path p : dirStream) - { + for (Path p : dirStream) { String fileName = p.getFileName().toString(); - if (fileName.endsWith(".csv")) - { - if (fileName.startsWith("COSMIC-identifiers-report")) - { + if (fileName.endsWith(".csv")) { + if (fileName.startsWith("COSMIC-identifiers-report")) { identifersReportExists = true; - } - else if (fileName.startsWith("COSMICIdentifiersNoReferrers")) - { + } else if (fileName.startsWith("COSMICIdentifiersNoReferrers")) { noReferrersReportExists = true; - } - else if (fileName.startsWith("nonEWASObjectsWithCOSMICIdentifiers")) - { + } else if (fileName.startsWith("nonEWASObjectsWithCOSMICIdentifiers")) { nonEWASReportExists = true; } } @@ -232,5 +213,4 @@ else if (fileName.startsWith("nonEWASObjectsWithCOSMICIdentifiers")) assertTrue(noReferrersReportExists); assertTrue(nonEWASReportExists); } -} - +} \ No newline at end of file From ab4dacd7f403c113a0b9b6264edb4db28c19a9e5 Mon Sep 17 00:00:00 2001 From: Joel Weiser Date: Wed, 20 Aug 2025 23:15:47 -0400 Subject: [PATCH 12/13] Update pom.xml --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b328db4..4e84b85 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ org.reactome.release release-common-lib - 2.0.0-SNAPSHOT + 2.0.0 com.beust From e0049fad93dba50e07faff5d4d2b6a3f56a702ca Mon Sep 17 00:00:00 2001 From: Joel Weiser Date: Wed, 20 Aug 2025 23:21:48 -0400 Subject: [PATCH 13/13] updates line length --- .../cosmicupdate/COSMICIdentifierUpdater.java | 10 ++++++---- .../release/cosmicupdate/COSMICUpdateUtil.java | 13 ++++++++----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdater.java b/src/main/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdater.java index 6105544..3b62f20 100644 --- a/src/main/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdater.java +++ b/src/main/java/org/reactome/release/cosmicupdate/COSMICIdentifierUpdater.java @@ -118,7 +118,8 @@ public void updateIdentifier(GKInstance modifiedInstanceEdit) throws Exception { else if (suggestedPrefixIsCOSMICLegacyPrefix()) { updateUsingSuggestedCOSMICPrefix(modifiedInstanceEdit); } - // Some identifiers won't have a COSV identifier in the COSMIC files, and they might not have a suggested prefix either. + // Some identifiers won't have a COSV identifier in the COSMIC files, and they might not have a suggested + // prefix either. else { logger.info( "No suggested prefix OR COSV identifier for {} (DBID: {}) - identifier will not be updated.", @@ -141,7 +142,8 @@ private void updateUsingCOSVIdentifier(GKInstance modifiedInstanceEdit) throws E private void updateUsingSuggestedCOSMICPrefix(GKInstance modifiedInstanceEdit) throws Exception { GKInstance cosmicDatabaseIdentifierInstance = this.getCosmicDatabaseIdentifierInstance(); - String currentCOSMICIdentifier = (String) cosmicDatabaseIdentifierInstance.getAttributeValue(ReactomeJavaConstants.identifier); + String currentCOSMICIdentifier = (String) + cosmicDatabaseIdentifierInstance.getAttributeValue(ReactomeJavaConstants.identifier); // If the current identifier already begins with "C" then leave it alone. // This code is for updating numeric identifiers that have a suggested prefix. if (!COSMICUpdateUtil.stringStartsWithC(currentCOSMICIdentifier.toUpperCase())) { @@ -153,8 +155,8 @@ private void updateUsingSuggestedCOSMICPrefix(GKInstance modifiedInstanceEdit) t /** * Executes an update on an instance. * Sets the identifier attribute of identifierObject to the value of identifierValue. - * identifierObject (which must be an InstanceEdit) will also have modifiedForCOSMICUpdate - * added to its modified list. + * identifierObject (which must be an InstanceEdit) will also have + * modifiedForCOSMICUpdate added to its modified list. * The display name of identifierObject will also be regenerated to reflect changes in * identifierValue. * @param identifierValue An identifier value that will be set on identifierObject diff --git a/src/main/java/org/reactome/release/cosmicupdate/COSMICUpdateUtil.java b/src/main/java/org/reactome/release/cosmicupdate/COSMICUpdateUtil.java index 3243cf4..29db840 100644 --- a/src/main/java/org/reactome/release/cosmicupdate/COSMICUpdateUtil.java +++ b/src/main/java/org/reactome/release/cosmicupdate/COSMICUpdateUtil.java @@ -149,8 +149,9 @@ private static Set getCOSMICFusionIds(MapCOSMICIdentifierUpdater, keyed by COSMIC identifier. * @throws Exception @@ -287,8 +288,8 @@ private static boolean referenceSequenceMismatchesResidues(GKInstance refSequenc * Queries the database for a ReferenceDatabase named "COSMIC" and then gets all DatabaseIdentifier objects * that refer to the COSMIC ReferenceDatabase via the referenceDatabase attribute. * This method will terminate the execution of the program if more than 1 "COSMIC" ReferenceDatabase is found. - * If you plan to add more "COSMIC" ReferenceDatabase objects, this code will need to be changed to use the correct "COSMIC" - * ReferenceDatabase. + * If you plan to add more "COSMIC" ReferenceDatabase objects, this code will need to be changed to use the + * correct "COSMIC" ReferenceDatabase. * @param adaptor * @return A Collection of DatabaseIdentifier objects. * @throws Exception @@ -326,7 +327,9 @@ public static boolean stringStartsWithC(String s) { } - private static List getCosmicRecords(Map> updaters) { + private static List getCosmicRecords( + Map> updaters) { + return updaters.values().parallelStream().flatMap(Collection::stream).sorted().collect(Collectors.toList()); }