diff --git a/configs/app/index.html b/configs/app/index.html new file mode 100644 index 0000000..a5ecf1b --- /dev/null +++ b/configs/app/index.html @@ -0,0 +1,3 @@ +

+ Greetings from the custom web app page! +

\ No newline at end of file diff --git a/custom/about.html b/custom/about.html new file mode 100644 index 0000000..f1064a9 --- /dev/null +++ b/custom/about.html @@ -0,0 +1,14 @@ +

+ This is a custom about page! It means you have configured 'custom_content_path: ./custom' in the application.yaml +

+

+ This server provides a complete implementation of the FHIR Specification + using a 100% open source software stack. +

+

+ This server is built + from a number of modules of the + HAPI FHIR + project, which is a 100% open-source (Apache 2.0 Licensed) Java based + implementation of the FHIR specification. +

\ No newline at end of file diff --git a/custom/logo.jpg b/custom/logo.jpg new file mode 100644 index 0000000..3a5aad0 Binary files /dev/null and b/custom/logo.jpg differ diff --git a/custom/welcome.html b/custom/welcome.html new file mode 100644 index 0000000..40aa399 --- /dev/null +++ b/custom/welcome.html @@ -0,0 +1,14 @@ +

+ This is a custom welcome page! It means you have configured 'custom_content_path: ./custom' in the application.yaml +

+

+ This server provides a complete implementation of the FHIR Specification + using a 100% open source software stack. +

+

+ This server is built + from a number of modules of the + HAPI FHIR + project, which is a 100% open-source (Apache 2.0 Licensed) Java based + implementation of the FHIR specification. +

\ No newline at end of file diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java b/src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java index 451c19d..16e8964 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java @@ -79,9 +79,8 @@ public class AppProperties { private Boolean install_transitive_ig_dependencies = true; private Map implementationGuides = null; - private String staticLocation = null; - - private String staticLocationPrefix = "/static"; + private String custom_content_path = null; + private String app_content_path = null; private Boolean lastn_enabled = false; private boolean store_resource_in_lucene_index_enabled = false; @@ -94,16 +93,9 @@ public class AppProperties { private Integer bundle_batch_pool_max_size = 100; private final Set local_base_urls = new HashSet<>(); private final Set logical_urls = new HashSet<>(); - + private final List custom_interceptor_classes = new ArrayList<>(); - public String getStaticLocationPrefix() { - return staticLocationPrefix; - } - - public void setStaticLocationPrefix(String staticLocationPrefix) { - this.staticLocationPrefix = staticLocationPrefix; - } public List getCustomInterceptorClasses() { @@ -111,14 +103,6 @@ public class AppProperties { } - public String getStaticLocation() { - return staticLocation; - } - - public void setStaticLocation(String staticLocation) { - this.staticLocation = staticLocation; - } - public Boolean getOpenapi_enabled() { return openapi_enabled; @@ -575,7 +559,7 @@ public Cors getCors() { public void setInstall_transitive_ig_dependencies(boolean install_transitive_ig_dependencies) { this.install_transitive_ig_dependencies = install_transitive_ig_dependencies; } - + public Integer getBundle_batch_pool_size() { return this.bundle_batch_pool_size; } @@ -600,6 +584,7 @@ public Cors getCors() { return logical_urls; } + public Boolean getIg_runtime_upload_enabled() { return ig_runtime_upload_enabled; } @@ -608,6 +593,22 @@ public Cors getCors() { this.ig_runtime_upload_enabled = ig_runtime_upload_enabled; } + public String getCustom_content_path() { + return custom_content_path; + } + + public void setCustom_content_path(String custom_content_path) { + this.custom_content_path = custom_content_path; + } + + public String getApp_content_path() { + return app_content_path; + } + + public void setApp_content_path(String app_content_path) { + this.app_content_path = app_content_path; + } + public static class Cors { private Boolean allow_Credentials = true; private List allowed_origin = List.of("*"); diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/ExtraStaticFilesConfigurer.java b/src/main/java/ca/uhn/fhir/jpa/starter/ExtraStaticFilesConfigurer.java deleted file mode 100644 index 2edb3aa..0000000 --- a/src/main/java/ca/uhn/fhir/jpa/starter/ExtraStaticFilesConfigurer.java +++ /dev/null @@ -1,50 +0,0 @@ -package ca.uhn.fhir.jpa.starter; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.Ordered; -import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; -import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -import java.net.URI; - -@Configuration -@ConditionalOnProperty(prefix = "hapi.fhir", name = "staticLocation") -public class ExtraStaticFilesConfigurer implements WebMvcConfigurer { - - private String staticLocation; - private String rootContextPath; - - public ExtraStaticFilesConfigurer(AppProperties appProperties) { - - rootContextPath = appProperties.getStaticLocationPrefix(); - if (rootContextPath.endsWith("/")) - rootContextPath = rootContextPath.substring(0, rootContextPath.lastIndexOf('/')); - - staticLocation = appProperties.getStaticLocation(); - if (staticLocation.endsWith("/")) staticLocation = staticLocation.substring(0, staticLocation.lastIndexOf('/')); - } - - @Override - public void addResourceHandlers(ResourceHandlerRegistry theRegistry) { - theRegistry.addResourceHandler(rootContextPath + "/**").addResourceLocations(staticLocation); - } - - @Override - public void addViewControllers(ViewControllerRegistry registry) { - String path = URI.create(staticLocation).getPath(); - String lastSegment = path.substring(path.lastIndexOf('/') + 1); - - registry.addViewController(rootContextPath) - .setViewName("redirect:" + rootContextPath + "/" + lastSegment + "/index.html"); - - registry.addViewController(rootContextPath + "/*") - .setViewName("redirect:" + rootContextPath + "/" + lastSegment + "/index.html"); - - registry.addViewController(rootContextPath + "/" + lastSegment + "/") - .setViewName("redirect:" + rootContextPath + "/" + lastSegment + "/index.html"); - - registry.setOrder(Ordered.HIGHEST_PRECEDENCE); - } -} diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/common/StarterJpaConfig.java b/src/main/java/ca/uhn/fhir/jpa/starter/common/StarterJpaConfig.java index cc8eb18..2a2de60 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/common/StarterJpaConfig.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/common/StarterJpaConfig.java @@ -44,6 +44,7 @@ import ca.uhn.fhir.jpa.starter.annotations.OnImplementationGuidesPresent; import ca.uhn.fhir.jpa.starter.common.validation.IRepositoryValidationInterceptorFactory; import ca.uhn.fhir.jpa.starter.ig.IImplementationGuideOperationProvider; import ca.uhn.fhir.jpa.starter.util.EnvironmentHelper; +import ca.uhn.fhir.jpa.starter.ig.IImplementationGuideOperationProvider; import ca.uhn.fhir.jpa.subscription.util.SubscriptionDebugLogInterceptor; import ca.uhn.fhir.jpa.util.ResourceCountCache; import ca.uhn.fhir.jpa.validation.JpaValidationSupportChain; @@ -272,8 +273,7 @@ public class StarterJpaConfig { IPackageInstallerSvc packageInstallerSvc, ThreadSafeResourceDeleterSvc theThreadSafeResourceDeleterSvc, ApplicationContext appContext, - Optional theIpsOperationProvider, - Optional implementationGuideOperationProvider) { + Optional theIpsOperationProvider, Optional implementationGuideOperationProvider) { RestfulServer fhirServer = new RestfulServer(fhirSystemDao.getContext()); List supportedResourceTypes = appProperties.getSupported_resource_types(); diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/ig/IImplementationGuideOperationProvider.java b/src/main/java/ca/uhn/fhir/jpa/starter/ig/IImplementationGuideOperationProvider.java index 13a659e..b6ed5fa 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/ig/IImplementationGuideOperationProvider.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/ig/IImplementationGuideOperationProvider.java @@ -9,20 +9,10 @@ import java.io.IOException; public interface IImplementationGuideOperationProvider { static PackageInstallationSpec toPackageInstallationSpec(byte[] npmPackageAsByteArray) throws IOException { NpmPackage npmPackage = NpmPackage.fromPackage(new ByteArrayInputStream(npmPackageAsByteArray)); - return new PackageInstallationSpec() - .setName(npmPackage.name()) - .setPackageContents(npmPackageAsByteArray) - .setVersion(npmPackage.version()) - .setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL) - .setFetchDependencies(false); + return new PackageInstallationSpec().setName(npmPackage.name()).setPackageContents(npmPackageAsByteArray).setVersion(npmPackage.version()).setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL).setFetchDependencies(false); } - // The following declaration is the one that counts but cannot be used across different versions as stating - // Base64BinaryType would bind to a separate version - // @Operation(name = "$install", typeName = "ImplementationGuide") - + // The following declaration is the one that counts but cannot be used across different versions as stating Base64BinaryType would bind to a separate version // Parameters install(@OperationParam(name = "npmContent",min = 1, max = 1) Base64BinaryType implementationGuide); - // Parameters uninstall(@OperationParam(name = "name", min = 1, max = 1) String name, @OperationParam(name = "version", min = 1, max = 1) String version) ; - } diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/ig/ImplementationGuideR4OperationProvider.java b/src/main/java/ca/uhn/fhir/jpa/starter/ig/ImplementationGuideR4OperationProvider.java index 0c9405f..da2b6d2 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/ig/ImplementationGuideR4OperationProvider.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/ig/ImplementationGuideR4OperationProvider.java @@ -23,12 +23,10 @@ public class ImplementationGuideR4OperationProvider implements IImplementationGu } @Operation(name = "$install", typeName = "ImplementationGuide") - public Parameters install( - @OperationParam(name = "npmContent", min = 1, max = 1) Base64BinaryType implementationGuide) { + public Parameters install(@OperationParam(name = "npmContent", min = 1, max = 1) Base64BinaryType implementationGuide) { try { - packageInstallerSvc.install( - IImplementationGuideOperationProvider.toPackageInstallationSpec(implementationGuide.getValue())); + packageInstallerSvc.install(IImplementationGuideOperationProvider.toPackageInstallationSpec(implementationGuide.getValue())); } catch (IOException e) { throw new RuntimeException(e); } @@ -36,10 +34,10 @@ public class ImplementationGuideR4OperationProvider implements IImplementationGu } @Operation(name = "$uninstall", typeName = "ImplementationGuide") - public Parameters uninstall( - @OperationParam(name = "name", min = 1, max = 1) String name, @OperationParam(name = "version", min = 1, max = 1) String version) { + public Parameters uninstall(@OperationParam(name = "name", min = 1, max = 1) String name, @OperationParam(name = "version", min = 1, max = 1) String version) { packageInstallerSvc.uninstall(new PackageInstallationSpec().setName(name).setVersion(version)); return new Parameters(); } + } diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/ig/ImplementationGuideR5OperationProvider.java b/src/main/java/ca/uhn/fhir/jpa/starter/ig/ImplementationGuideR5OperationProvider.java index 50ba6b6..962820d 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/ig/ImplementationGuideR5OperationProvider.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/ig/ImplementationGuideR5OperationProvider.java @@ -23,21 +23,19 @@ public class ImplementationGuideR5OperationProvider implements IImplementationGu } @Operation(name = "$install", typeName = "ImplementationGuide") - public Parameters install( - @OperationParam(name = "npmContent", min = 1, max = 1) Base64BinaryType implementationGuide) { + public Parameters install(@OperationParam(name = "npmContent", min = 1, max = 1) Base64BinaryType implementationGuide) { try { - packageInstallerSvc.install( - IImplementationGuideOperationProvider.toPackageInstallationSpec(implementationGuide.getValue())); + packageInstallerSvc.install(IImplementationGuideOperationProvider.toPackageInstallationSpec(implementationGuide.getValue())); } catch (IOException e) { throw new RuntimeException(e); } return new Parameters(); } + @Operation(name = "$uninstall", typeName = "ImplementationGuide") - public org.hl7.fhir.r4.model.Parameters uninstall( - @OperationParam(name = "name", min = 1, max = 1) String name, @OperationParam(name = "version", min = 1, max = 1) String version) { + public org.hl7.fhir.r4.model.Parameters uninstall(@OperationParam(name = "name", min = 1, max = 1) String name, @OperationParam(name = "version", min = 1, max = 1) String version) { packageInstallerSvc.uninstall(new PackageInstallationSpec().setName(name).setVersion(version)); return new org.hl7.fhir.r4.model.Parameters(); diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/web/CustomContentFilesConfigurer.java b/src/main/java/ca/uhn/fhir/jpa/starter/web/CustomContentFilesConfigurer.java new file mode 100644 index 0000000..de9714e --- /dev/null +++ b/src/main/java/ca/uhn/fhir/jpa/starter/web/CustomContentFilesConfigurer.java @@ -0,0 +1,40 @@ +package ca.uhn.fhir.jpa.starter.web; + +import ca.uhn.fhir.jpa.starter.AppProperties; +import org.jetbrains.annotations.NotNull; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.FileUrlResource; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.net.MalformedURLException; + +@Configuration +@ConditionalOnProperty(prefix = "hapi.fhir", name = "custom_content_path") +public class CustomContentFilesConfigurer implements WebMvcConfigurer { + + public static final String CUSTOM_CONTENT = "/content"; + private String customContentPath; + + + public CustomContentFilesConfigurer(AppProperties appProperties) { + customContentPath = appProperties.getCustom_content_path(); + if (customContentPath.endsWith("/")) + customContentPath = customContentPath.substring(0, customContentPath.lastIndexOf('/')); + + } + + + @Override + public void addResourceHandlers(@NotNull ResourceHandlerRegistry theRegistry) { + if (!theRegistry.hasMappingForPattern(CUSTOM_CONTENT + "/**")) { + + try { + theRegistry.addResourceHandler(CUSTOM_CONTENT + "/**").addResourceLocations(new FileUrlResource(customContentPath)); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/web/WebAppFilesConfigurer.java b/src/main/java/ca/uhn/fhir/jpa/starter/web/WebAppFilesConfigurer.java new file mode 100644 index 0000000..fb20901 --- /dev/null +++ b/src/main/java/ca/uhn/fhir/jpa/starter/web/WebAppFilesConfigurer.java @@ -0,0 +1,56 @@ +package ca.uhn.fhir.jpa.starter.web; + +import ca.uhn.fhir.jpa.starter.AppProperties; +import org.jetbrains.annotations.NotNull; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.core.io.FileUrlResource; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.net.MalformedURLException; +import java.net.URI; + +@Configuration +@ConditionalOnProperty(prefix = "hapi.fhir", name = "app_content_path") +public class WebAppFilesConfigurer implements WebMvcConfigurer { + + public static final String WEB_CONTENT = "web"; + private String appContentPath; + + + public WebAppFilesConfigurer(AppProperties appProperties) { + appContentPath = appProperties.getApp_content_path(); + if (appContentPath.endsWith("/")) + appContentPath = appContentPath.substring(0, appContentPath.lastIndexOf('/')); + + } + + + @Override + public void addResourceHandlers(@NotNull ResourceHandlerRegistry theRegistry) { + if (!theRegistry.hasMappingForPattern(WEB_CONTENT + "/**")) { + { + try { + theRegistry.addResourceHandler(WEB_CONTENT + "/**").addResourceLocations(new FileUrlResource(appContentPath)); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + } + } + + @Override + public void addViewControllers(@NotNull ViewControllerRegistry registry) { + String path = URI.create(appContentPath).getPath(); + String lastSegment = path.substring(path.lastIndexOf('/') + 1); + + registry.addViewController(WEB_CONTENT + "/" + lastSegment).setViewName("redirect:" + lastSegment + "/index.html"); + registry.addViewController(WEB_CONTENT + "/" + lastSegment + "/").setViewName("redirect:index.html"); + + registry.setOrder(Ordered.HIGHEST_PRECEDENCE); + + } +} \ No newline at end of file diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 95ebfec..df14c31 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -14,8 +14,8 @@ spring: check-location: false baselineOnMigrate: true datasource: - url: 'jdbc:h2:file:./target/database/h2' - #url: jdbc:h2:mem:test_mem + #url: 'jdbc:h2:file:./target/database/h2' + url: jdbc:h2:mem:test_mem username: sa password: null driverClassName: org.h2.Driver @@ -76,10 +76,12 @@ hapi: ### forces the use of the https:// protocol for the returned server address. ### alternatively, it may be set using the X-Forwarded-Proto header. # use_apache_address_strategy_https: false - ### enables the server to host content like HTML, css, etc. under the url pattern of eg. /static/** - # staticLocationPrefix: /static - ### the deepest folder level will be used. E.g. - if you put file:/foo/bar/bazz as value then the files are resolved under /static/bazz/** - #staticLocation: file:/foo/bar/bazz + ### enables the server to overwrite defaults on HTML, css, etc. under the url pattern of eg. /content/custom ** + ### Folder with custom content MUST be named custom. If omitted then default content applies + #custom_content_path: ./custom + ### enables the server host custom content. If e.g. the value ./configs/app is supplied then the content + ### will be served under /web/app + #app_content_path: ./configs/app ### enable to set the Server URL # server_address: http://hapi.fhir.org/baseR4 # defer_indexing_for_codesystems_of_size: 101 diff --git a/src/main/webapp/WEB-INF/templates/about.html b/src/main/webapp/WEB-INF/templates/about.html index 0811965..4859418 100644 --- a/src/main/webapp/WEB-INF/templates/about.html +++ b/src/main/webapp/WEB-INF/templates/about.html @@ -21,21 +21,23 @@

About This Server

-

- This server provides a complete implementation of the FHIR Specification - using a 100% open source software stack. -

-

- This server is built - from a number of modules of the - HAPI FHIR - project, which is a 100% open-source (Apache 2.0 Licensed) Java based - implementation of the FHIR specification. -

-

+

+

+ This server provides a complete implementation of the FHIR Specification + using a 100% open source software stack. +

+

+ This server is built + from a number of modules of the + HAPI FHIR + project, which is a 100% open-source (Apache 2.0 Licensed) Java based + implementation of the FHIR specification. +

-

+
+ +
@@ -55,6 +57,41 @@
- + + \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/templates/tmpl-banner.html b/src/main/webapp/WEB-INF/templates/tmpl-banner.html index abbe718..bfcc01b 100644 --- a/src/main/webapp/WEB-INF/templates/tmpl-banner.html +++ b/src/main/webapp/WEB-INF/templates/tmpl-banner.html @@ -1,20 +1,41 @@
-
-
- Sample Logo -
-
- -
-
- - -
- Warning! -

-
- +
+
+ +
+
+ +
+
+ + + +
+ Warning! +

+
+
diff --git a/src/main/webapp/WEB-INF/templates/tmpl-home-welcome.html b/src/main/webapp/WEB-INF/templates/tmpl-home-welcome.html index 97747f4..f9bfcd9 100644 --- a/src/main/webapp/WEB-INF/templates/tmpl-home-welcome.html +++ b/src/main/webapp/WEB-INF/templates/tmpl-home-welcome.html @@ -1,16 +1,58 @@ -
-

- This server provides a complete implementation of the FHIR Specification - using a 100% open source software stack. -

-

- This server is built - from a number of modules of the - HAPI FHIR - project, which is a 100% open-source (Apache 2.0 Licensed) Java based - implementation of the FHIR specification. -

+ +
+ +
+
+

+ This server provides a complete implementation of the FHIR Specification + using a 100% open source software stack. +

+

+ This server is built + from a number of modules of the + HAPI FHIR + project, which is a 100% open-source (Apache 2.0 Licensed) Java based + implementation of the FHIR specification. +

+
+
- + + \ No newline at end of file