diff --git a/docs/deployment/customization/application.properties-Reference.md b/docs/deployment/customization/application.properties-Reference.md index cbab1aa5374..2780fe8b6a9 100644 --- a/docs/deployment/customization/application.properties-Reference.md +++ b/docs/deployment/customization/application.properties-Reference.md @@ -800,9 +800,9 @@ enable_study_tags=true|false ``` # Add Custom Buttons to data tables -Custom Buttons can be defined which will conditionally appear in all group comparison data tables (with CopyDownloadControls) to launch a custom URL. This can be used, for example, to launch a software application (that is installed on the user's system) with the data. This configuration can also customize new elements on the Visualize page. It points to a JSON file on the classpath. (See [download_custom_buttons reference](download_custom_buttons-Reference.md)). +Custom Buttons can be defined which will conditionally appear in all group comparison data tables (with CopyDownloadControls) to launch a custom URL. This can be used, for example, to launch a software application (that is installed on the user's system) with the data. This configuration can also customize new elements on the Visualize page. It points to a JSON file. (See [download_custom_buttons reference](download_custom_buttons-Reference.md)). ``` -download_custom_buttons_json=classpath:/custom_buttons/download_custom_button_avm.json +download_custom_buttons_json=classpath:custom_buttons/download_custom_button_avm.json ``` diff --git a/docs/deployment/customization/download_custom_buttons-Reference.md b/docs/deployment/customization/download_custom_buttons-Reference.md index 7050021376d..f6defe75b47 100644 --- a/docs/deployment/customization/download_custom_buttons-Reference.md +++ b/docs/deployment/customization/download_custom_buttons-Reference.md @@ -4,8 +4,7 @@ Custom Buttons can be defined which will conditionally appear in all group compa ## Configuration File -The Custom Buttons are defined in a JSON file in the classpath. Set `download_custom_buttons_json` to refer to the file in the -`application.properties` (See [application.properties reference](application.properties-Reference.md#add-custom-buttons-to-data-tables)). +The Custom Buttons are defined in a JSON file on the classpath. Set `download_custom_buttons_json` to refer to the file (see [application.properties reference](application.properties-Reference.md#add-custom-buttons-to-data-tables)). ## JSON format @@ -67,6 +66,4 @@ To modify software to leverage this: - Modify your software to read data from clipboard. - Modify your software or installer to register a URL protocol to launch. -- Modify your software or installer to install a custom font. - - +- Modify your software or installer to install a custom font. \ No newline at end of file diff --git a/src/main/java/org/cbioportal/service/FrontendPropertiesServiceImpl.java b/src/main/java/org/cbioportal/service/FrontendPropertiesServiceImpl.java index 304ca3853f7..eb2c94c43a2 100644 --- a/src/main/java/org/cbioportal/service/FrontendPropertiesServiceImpl.java +++ b/src/main/java/org/cbioportal/service/FrontendPropertiesServiceImpl.java @@ -8,6 +8,11 @@ import org.springframework.stereotype.Service; import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; @@ -291,18 +296,66 @@ private Map cloneProperties() { ); } - private String readFile(String fileName) { - if (fileName != null && !fileName.isEmpty()) { - try (BufferedReader br = Files.newBufferedReader(Paths.get(fileName))) { - return br.lines().map(String::trim).collect(Collectors.joining("")); - } catch (Exception e) { - log.error("Error reading frontend config file: {}", e.getMessage()); - return null; + /** + * Find the file, either on the file system or in a .jar, and return as an InputStream. + * @propertiesFileName: the file path + * @return: a valid InputStream (not null), otherwise throws FileNotFoundException + * TECH: file system locations have precedence over classpath + * REF: based on getResourceStream() in WebServletContextListener.java + */ + private InputStream locateFile(String filePath) throws FileNotFoundException { + // try absolute or relative to working directory + File file = new File(filePath); + if (file.exists()) { + // throws if is a directory or cannot be opened + log.info("Found frontend config file: {}", file.getAbsolutePath()); + return new FileInputStream(file); + } + + // try relative to PORTAL_HOME + String home = System.getenv("PORTAL_HOME"); + if (home != null) { + file = new File(Paths.get(home, filePath).toString()); + if (file.exists()) { + log.info("Found frontend config file: {}", file.getAbsolutePath()); + return new FileInputStream(file); } + } + + // try resource (e.g. app.jar) + InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(filePath); + if (inputStream != null) { + log.info("Found frontend config resource: {}", filePath); + return inputStream; + } else { + throw new FileNotFoundException("File not found in system or classpath: " + filePath); } - return null; } - + + /** + * Read the file, either on the file system or in a .jar, and return the content as a single-line string. + * @propertiesFileName: the file path + */ + private String readFile(String propertiesFileName) { + if (propertiesFileName == null || propertiesFileName.isEmpty()) { + return null; + } + + // strip off classpath prefix and always check all locations (ClassLoader and file system) + String filePath = propertiesFileName.startsWith("classpath:") + ? propertiesFileName.substring("classpath:".length()) + : propertiesFileName; + + try { + InputStream inputStream = locateFile(filePath); + BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); + return br.lines().map(String::trim).collect(Collectors.joining("")); + } catch (Exception e) { + log.error("Error reading frontend config file: {}", e.getMessage()); + return null; + } + } + public String getFrontendUrl(String propertyValue) { String frontendUrlRuntime = env.getProperty("frontend.url.runtime", ""); if (frontendUrlRuntime.length() > 0) { diff --git a/src/main/resources/application.properties.EXAMPLE b/src/main/resources/application.properties.EXAMPLE index b2c80337eae..77846a3cf60 100644 --- a/src/main/resources/application.properties.EXAMPLE +++ b/src/main/resources/application.properties.EXAMPLE @@ -427,7 +427,7 @@ spring.devtools.restart.enabled=false #enable_study_tags=true|false ## Custom Buttons -# download_custom_buttons_json=classpath:/custom_buttons/download_custom_button_avm.json +# download_custom_buttons_json=classpath:custom_buttons/download_custom_button_avm.json # EOL - Do not delete the following lines