From f61d11e754a71e5447e7c49cd822470711674bde Mon Sep 17 00:00:00 2001 From: labkey-tchad Date: Tue, 30 Jan 2024 16:50:10 -0800 Subject: [PATCH] Add support for custom webapp resources --- server/configs/application.properties | 8 +++ .../src/org/labkey/embedded/LabKeyServer.java | 58 +++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/server/configs/application.properties b/server/configs/application.properties index 4964190273..2d7d503383 100644 --- a/server/configs/application.properties +++ b/server/configs/application.properties @@ -64,6 +64,14 @@ management.endpoints.web.exposure.include=* # Don't show the Spring banner on startup spring.main.banner-mode=off +# Optional - JMS configuration for remote ActiveMQ message management for distributed pipeline jobs +# https://www.labkey.org/Documentation/wiki-page.view?name=jmsQueue +#context.resources.jms.name=jms/ConnectionFactory +#context.resources.jms.type=org.apache.activemq.ActiveMQConnectionFactory +#context.resources.jms.factory=org.apache.activemq.jndi.JNDIReferenceFactory +#context.resources.jms.description=JMS Connection Factory +#context.resources.jms.brokerURL=vm://localhost?broker.persistent=false&broker.useJmx=false +#context.resources.jms.brokerName=LocalActiveMQBroker # Turn on JSON-formatted HTTP access logging to stdout. See issue 48565 # https://tomcat.apache.org/tomcat-9.0-doc/config/valve.html#JSON_Access_Log_Valve diff --git a/server/embedded/src/org/labkey/embedded/LabKeyServer.java b/server/embedded/src/org/labkey/embedded/LabKeyServer.java index b0fb943b1f..918ab34ecf 100644 --- a/server/embedded/src/org/labkey/embedded/LabKeyServer.java +++ b/server/embedded/src/org/labkey/embedded/LabKeyServer.java @@ -4,6 +4,7 @@ import org.apache.catalina.loader.WebappLoader; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.valves.JsonAccessLogValve; +import org.apache.tomcat.util.collections.CaseInsensitiveKeyMap; import org.apache.tomcat.util.descriptor.web.ContextResource; import org.labkey.bootstrap.ConfigException; import org.springframework.boot.SpringApplication; @@ -25,8 +26,10 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.jar.JarFile; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -144,6 +147,9 @@ protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) // Push the JDBC connection for the primary DB into the context so that the LabKey webapp finds them getDataSourceResources(contextProperties).forEach(contextResource -> context.getNamingResources().addResource(contextResource)); + // Add extra resources to context (e.g. LDAP, JMS) + getExtraContextResources(contextProperties).forEach(contextResource -> context.getNamingResources().addResource(contextResource)); + // Add the SMTP config context.getNamingResources().addResource(getMailResource()); @@ -246,6 +252,47 @@ private List getDataSourceResources(ContextProperties props) th return dataSourceResources; } + private List getExtraContextResources(ContextProperties contextProperties) throws ConfigException + { + List contextResources = new ArrayList<>(); + Map> resourceMaps = Objects.requireNonNullElse(contextProperties.getResources(), Collections.emptyMap()); + + for (Map.Entry> entry : resourceMaps.entrySet()) + { + Map resourceMap = new CaseInsensitiveKeyMap<>(); + resourceMap.putAll(entry.getValue()); + if (!resourceMap.containsKey("name")) + { + logger.error("Resource configuration error: Ignoring unnamed resource 'context.resources.%s'".formatted(entry.getKey())); + continue; + } + if (!resourceMap.containsKey("type")) + { + logger.error("Resource configuration error: type is not defined for resource '%s'".formatted(resourceMap.get("name"))); + continue; + } + + ContextResource contextResource = new ContextResource(); + contextResource.setName(resourceMap.remove("name")); + contextResource.setType(resourceMap.remove("type")); + contextResource.setDescription(resourceMap.remove("description")); + contextResource.setLookupName(resourceMap.remove("lookupName")); + if (resourceMap.containsKey("scope")) + { + contextResource.setScope(resourceMap.remove("scope")); + } + contextResource.setAuth(Objects.requireNonNullElse(resourceMap.remove("auth"), "Container")); + for (Map.Entry prop : resourceMap.entrySet()) + { + contextResource.setProperty(prop.getKey(), prop.getValue()); + } + + contextResources.add(contextResource); + } + + return contextResources; + } + private String getPropValue(Map propValues, Integer resourceKey, String defaultValue, String propName) { if (propValues == null) @@ -484,6 +531,7 @@ public static class ContextProperties private Map maxWaitMillis; private Map accessToUnderlyingConnectionAllowed; private Map validationQuery; + private Map> resources; public List getDataSourceName() { @@ -655,6 +703,16 @@ public void setValidationQuery(Map validationQuery) { this.validationQuery = validationQuery; } + + public Map> getResources() + { + return resources; + } + + public void setResources(Map> resources) + { + this.resources = resources; + } } @Configuration