From e7bd5da6fa437029e64ec4d31adf5dcc3a4ddd87 Mon Sep 17 00:00:00 2001 From: Andrew DeMaria Date: Sat, 27 Jul 2019 11:25:59 -0500 Subject: [PATCH] Precompile jsp Signed-off-by: Andrew DeMaria --- airsonic-main/pom.xml | 21 ++++++ .../player/security/GlobalSecurityConfig.java | 2 +- .../player/service/SettingsService.java | 2 +- .../RegisterPrecompiledJSPInitializer.java | 73 +++++++++++++++++++ .../spring/webxmldomain/ServletDef.java | 32 ++++++++ .../webxmldomain/ServletMappingDef.java | 33 +++++++++ .../player/spring/webxmldomain/WebApp.java | 34 +++++++++ pom.xml | 1 + 8 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 airsonic-main/src/main/java/org/airsonic/player/spring/RegisterPrecompiledJSPInitializer.java create mode 100644 airsonic-main/src/main/java/org/airsonic/player/spring/webxmldomain/ServletDef.java create mode 100644 airsonic-main/src/main/java/org/airsonic/player/spring/webxmldomain/ServletMappingDef.java create mode 100644 airsonic-main/src/main/java/org/airsonic/player/spring/webxmldomain/WebApp.java diff --git a/airsonic-main/pom.xml b/airsonic-main/pom.xml index cd6d1fd9..3aad5905 100755 --- a/airsonic-main/pom.xml +++ b/airsonic-main/pom.xml @@ -638,6 +638,27 @@ net.nicoulaj.maven.plugins checksum-maven-plugin + + org.eclipse.jetty + jetty-jspc-maven-plugin + 9.4.19.v20190610 + + + jspc + + jspc + + compile + + + false + ${project.build.outputDirectory}/precompiled-jsp-web.xml + + + + diff --git a/airsonic-main/src/main/java/org/airsonic/player/security/GlobalSecurityConfig.java b/airsonic-main/src/main/java/org/airsonic/player/security/GlobalSecurityConfig.java index 7415b568..c5297384 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/security/GlobalSecurityConfig.java +++ b/airsonic-main/src/main/java/org/airsonic/player/security/GlobalSecurityConfig.java @@ -139,7 +139,7 @@ public class GlobalSecurityConfig extends GlobalAuthenticationConfigurerAdapter // See: https://docs.spring.io/spring-security/site/docs/3.0.x/reference/remember-me.html String rememberMeKey = settingsService.getRememberMeKey(); - boolean development = settingsService.isDevelopmentMode(); + boolean development = SettingsService.isDevelopmentMode(); if (StringUtils.isBlank(rememberMeKey) && !development) { // ...if it is empty, generate a random key on startup (default). logger.debug("Generating a new ephemeral 'remember me' key in a secure way."); diff --git a/airsonic-main/src/main/java/org/airsonic/player/service/SettingsService.java b/airsonic-main/src/main/java/org/airsonic/player/service/SettingsService.java index ac4612de..8ede464d 100644 --- a/airsonic-main/src/main/java/org/airsonic/player/service/SettingsService.java +++ b/airsonic-main/src/main/java/org/airsonic/player/service/SettingsService.java @@ -791,7 +791,7 @@ public class SettingsService { * * @return true if we are in Development mode. */ - public boolean isDevelopmentMode() { + public static boolean isDevelopmentMode() { return System.getProperty("airsonic.development") != null; } diff --git a/airsonic-main/src/main/java/org/airsonic/player/spring/RegisterPrecompiledJSPInitializer.java b/airsonic-main/src/main/java/org/airsonic/player/spring/RegisterPrecompiledJSPInitializer.java new file mode 100644 index 00000000..1f5779c6 --- /dev/null +++ b/airsonic-main/src/main/java/org/airsonic/player/spring/RegisterPrecompiledJSPInitializer.java @@ -0,0 +1,73 @@ +package org.airsonic.player.spring; + +import org.airsonic.player.service.SettingsService; +import org.airsonic.player.spring.webxmldomain.ServletDef; +import org.airsonic.player.spring.webxmldomain.ServletMappingDef; +import org.airsonic.player.spring.webxmldomain.WebApp; +import org.apache.commons.io.IOUtils; +import org.apache.cxf.jaxb.JAXBDataBinding; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.web.servlet.ServletContextInitializer; +import org.springframework.stereotype.Component; + +import javax.servlet.ServletContext; +import javax.servlet.ServletRegistration; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; + +import java.io.InputStream; +import java.io.SequenceInputStream; +import java.nio.charset.Charset; + +@Component +public class RegisterPrecompiledJSPInitializer implements ServletContextInitializer { + + private static final Logger logger = LoggerFactory.getLogger(RegisterPrecompiledJSPInitializer.class); + + @Override + public void onStartup(ServletContext servletContext) { + if(SettingsService.isDevelopmentMode()) { + logger.debug("Not registering precompiled jsps"); + } else { + logger.debug("Registering precompiled jsps"); + registerPrecompiledJSPs(servletContext); + } + } + + private static void registerPrecompiledJSPs(ServletContext servletContext) { + WebApp webApp = parseXmlFragment(); + for (ServletDef def : webApp.getServletDefs()) { + logger.trace("Registering precompiled JSP: {} -> {}", def.getName(), def.getSclass()); + ServletRegistration.Dynamic reg = servletContext.addServlet(def.getName(), def.getSclass()); + // Need to set loadOnStartup somewhere between 0 and 128. 0 is highest priority. 99 should be fine + reg.setLoadOnStartup(99); + } + + for (ServletMappingDef mapping : webApp.getServletMappingDefs()) { + logger.trace("Mapping servlet: {} -> {}", mapping.getName(), mapping.getUrlPattern()); + servletContext.getServletRegistration(mapping.getName()).addMapping(mapping.getUrlPattern()); + } + } + + private static WebApp parseXmlFragment() { + InputStream precompiledJspWebXml = RegisterPrecompiledJSPInitializer.class.getResourceAsStream("/precompiled-jsp-web.xml"); + InputStream webXmlIS = new SequenceInputStream( + new SequenceInputStream( + IOUtils.toInputStream("", Charset.defaultCharset()), + precompiledJspWebXml), + IOUtils.toInputStream("", Charset.defaultCharset())); + + JAXBContext jaxbContext; + try { + jaxbContext = new JAXBDataBinding(WebApp.class).getContext(); + Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + WebApp webapp = (WebApp) unmarshaller.unmarshal(webXmlIS); + return webapp; + } catch (JAXBException e) { + throw new RuntimeException("Could not parse precompiled-jsp-web.xml", e); + } + } + +} diff --git a/airsonic-main/src/main/java/org/airsonic/player/spring/webxmldomain/ServletDef.java b/airsonic-main/src/main/java/org/airsonic/player/spring/webxmldomain/ServletDef.java new file mode 100644 index 00000000..c7b924e5 --- /dev/null +++ b/airsonic-main/src/main/java/org/airsonic/player/spring/webxmldomain/ServletDef.java @@ -0,0 +1,32 @@ +package org.airsonic.player.spring.webxmldomain; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class ServletDef { + @XmlElement(name="servlet-name") + private String name; + + @XmlElement(name="servlet-class") + private String sclass; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSclass() { + return sclass; + } + + public void setSclass(String sclass) { + this.sclass = sclass; + } +} diff --git a/airsonic-main/src/main/java/org/airsonic/player/spring/webxmldomain/ServletMappingDef.java b/airsonic-main/src/main/java/org/airsonic/player/spring/webxmldomain/ServletMappingDef.java new file mode 100644 index 00000000..c3274788 --- /dev/null +++ b/airsonic-main/src/main/java/org/airsonic/player/spring/webxmldomain/ServletMappingDef.java @@ -0,0 +1,33 @@ +package org.airsonic.player.spring.webxmldomain; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class ServletMappingDef { + @XmlElement(name="servlet-name") + private String name; + + @XmlElement(name="url-pattern") + private String urlPattern; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrlPattern() { + return urlPattern; + } + + public void setUrlPattern(String urlPattern) { + this.urlPattern = urlPattern; + } + +} diff --git a/airsonic-main/src/main/java/org/airsonic/player/spring/webxmldomain/WebApp.java b/airsonic-main/src/main/java/org/airsonic/player/spring/webxmldomain/WebApp.java new file mode 100644 index 00000000..3c5f518e --- /dev/null +++ b/airsonic-main/src/main/java/org/airsonic/player/spring/webxmldomain/WebApp.java @@ -0,0 +1,34 @@ +package org.airsonic.player.spring.webxmldomain; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import java.util.List; + +@XmlRootElement(name="web-app") +@XmlAccessorType(XmlAccessType.FIELD) +public class WebApp { + @XmlElement(name="servlet") + private List servletDefs; + + @XmlElement(name="servlet-mapping") + private List servletMappingDefs; + + public List getServletDefs() { + return servletDefs; + } + + public void setServletDefs(List servletDefs) { + this.servletDefs = servletDefs; + } + + public List getServletMappingDefs() { + return servletMappingDefs; + } + + public void setServletMappingDefs(List servletMappingDefs) { + this.servletMappingDefs = servletMappingDefs; + } +} diff --git a/pom.xml b/pom.xml index 3a32e056..9293a0c6 100644 --- a/pom.xml +++ b/pom.xml @@ -381,6 +381,7 @@ org.springframework.boot:* org.apache.tomcat.embed:tomcat-embed-core* org.apache.tomcat:tomcat-annotations-api:* + org.apache.tomcat.embed:tomcat-embed-el* com.sun.mail:javax.mail*