From 49dc5176d58e12c8412adcb7cc24f5f480972513 Mon Sep 17 00:00:00 2001 From: Andrew DeMaria Date: Sun, 1 Jan 2017 22:28:12 -0700 Subject: [PATCH 1/4] General fixups - Fixed tomcat deployment - Removed web.xml - Migrated to servlet api 3 - Added back in logging error resolver - Fixed error jsp page not working - Fixed login path when deployed to tomcat - Cleanup custom liquibase precondition class - Made the hsql index check more robust Signed-off-by: Andrew DeMaria --- libresonic-main/pom.xml | 23 +- .../libresonic/player/boot/Application.java | 123 +++++++++- .../spring/DbmsVersionPrecondition.java | 54 +---- .../player/spring/SpringLiquibase.java | 1 - .../src/main/resources/application.properties | 3 + .../src/main/resources/libresonic-servlet.xml | 2 + .../resources/liquibase/legacy/schema47.xml | 2 +- .../resources/liquibase/legacy/schema53.xml | 2 +- .../main/webapp/{ => WEB-INF/jsp}/error.jsp | 24 +- .../src/main/webapp/WEB-INF/jsp/login.jsp | 2 +- .../src/main/webapp/WEB-INF/web.xml | 225 ------------------ pom.xml | 6 + 12 files changed, 177 insertions(+), 290 deletions(-) create mode 100644 libresonic-main/src/main/resources/application.properties rename libresonic-main/src/main/webapp/{ => WEB-INF/jsp}/error.jsp (73%) delete mode 100644 libresonic-main/src/main/webapp/WEB-INF/web.xml diff --git a/libresonic-main/pom.xml b/libresonic-main/pom.xml index 40ae8b15..ac1fe759 100644 --- a/libresonic-main/pom.xml +++ b/libresonic-main/pom.xml @@ -77,14 +77,15 @@ - javax.servlet - jstl - 1.2 + org.apache.taglibs + taglibs-standard-impl + 1.2.5 taglibs string 1.1.0 + runtime @@ -223,6 +224,20 @@ 2.5.1 + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + + javax.servlet + jstl + 1.2 + runtime + + javax.mail javax.mail-api @@ -284,7 +299,6 @@ spring-web - runtime @@ -372,6 +386,7 @@ spring-boot-maven-plugin org.libresonic.player.boot.Application + WAR diff --git a/libresonic-main/src/main/java/org/libresonic/player/boot/Application.java b/libresonic-main/src/main/java/org/libresonic/player/boot/Application.java index 86f40157..6e05cc4a 100644 --- a/libresonic-main/src/main/java/org/libresonic/player/boot/Application.java +++ b/libresonic-main/src/main/java/org/libresonic/player/boot/Application.java @@ -1,10 +1,18 @@ package org.libresonic.player.boot; +import javax.servlet.Filter; +import javax.servlet.ServletContextListener; +import net.sf.ehcache.constructs.web.ShutdownListener; import org.directwebremoting.servlet.DwrServlet; +import org.libresonic.player.filter.BootstrapVerificationFilter; +import org.libresonic.player.filter.ParameterDecodingFilter; +import org.libresonic.player.filter.RESTFilter; +import org.libresonic.player.filter.RequestEncodingFilter; +import org.libresonic.player.filter.ResponseHeaderFilter; import org.libresonic.player.spring.AdditionalPropertySourceConfigurer; -import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.boot.web.support.SpringBootServletInitializer; import org.springframework.context.annotation.Bean; @@ -31,19 +39,124 @@ public class Application extends SpringBootServletInitializer { return servlet; } + @Bean + public ServletRegistrationBean cxfServletBean() { + return new ServletRegistrationBean(new org.apache.cxf.transport.servlet.CXFServlet(), "/ws/*"); + } + + @Bean + public ServletContextListener ehCacheShutdownListener() { + return new ShutdownListener(); + } + + @Bean + public FilterRegistrationBean bootstrapVerificationFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(bootstrapVerificationFiler()); + registration.addUrlPatterns("/*"); + registration.setName("BootstrapVerificationFilter"); + registration.setOrder(1); + return registration; + } + + @Bean + public Filter bootstrapVerificationFiler() { + return new BootstrapVerificationFilter(); + } + + @Bean + public FilterRegistrationBean parameterDecodingFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(parameterDecodingFilter()); + registration.addUrlPatterns("/*"); + registration.setName("ParameterDecodingFilter"); + registration.setOrder(2); + return registration; + } + + @Bean + public Filter parameterDecodingFilter() { + return new ParameterDecodingFilter(); + } + + @Bean + public FilterRegistrationBean restFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(restFilter()); + registration.addUrlPatterns("/rest/*"); + registration.setName("RESTFilter"); + registration.setOrder(3); + return registration; + } + + @Bean + public Filter restFilter() { + return new RESTFilter(); + } + + @Bean + public FilterRegistrationBean requestEncodingFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(requestEncodingFilter()); + registration.addUrlPatterns("/*"); + registration.addInitParameter("encoding", "UTF-8"); + registration.setName("RequestEncodingFilter"); + registration.setOrder(4); + return registration; + } + + @Bean + public Filter requestEncodingFilter() { + return new RequestEncodingFilter(); + } + + @Bean + public FilterRegistrationBean cacheFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(cacheFilter()); + registration.addUrlPatterns("/icons/*", "/style/*"); + registration.addInitParameter("Cache-Control", "max-age=36000"); + registration.setName("CacheFilter"); + registration.setOrder(5); + return registration; + } + + @Bean + public Filter cacheFilter() { + return new ResponseHeaderFilter(); + } + + @Bean + public FilterRegistrationBean noCacheFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(noCacheFilter()); + registration.addUrlPatterns("/statusChart.view", "/userChart.view", "/playQueue.view", "/podcastChannels.view", "/podcastChannel.view", "/help.view", "/top.view", "/home.view"); + registration.addInitParameter("Cache-Control", "no-cache, post-check=0, pre-check=0"); + registration.addInitParameter("Pragma", "no-cache"); + registration.addInitParameter("Expires", "Thu, 01 Dec 1994 16:00:00 GMT"); + registration.setName("NoCacheFilter"); + registration.setOrder(6); + return registration; + } + + @Bean + public Filter noCacheFilter() { + return new ResponseHeaderFilter(); + } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { // Customize the application or call application.sources(...) to add sources // Since our example is itself a @Configuration class (via @SpringBootApplication) // we actually don't need to override this method. - return application; + return application.sources(Application.class); } public static void main(String[] args) { - SpringApplication springApplication = new SpringApplication(Application.class); - springApplication.addInitializers(new AdditionalPropertySourceConfigurer()); - springApplication.run(args); + new Application().configure(new SpringApplicationBuilder(Application.class)) + .web(true) + .initializers(new AdditionalPropertySourceConfigurer()) + .run(args); } } \ No newline at end of file diff --git a/libresonic-main/src/main/java/org/libresonic/player/spring/DbmsVersionPrecondition.java b/libresonic-main/src/main/java/org/libresonic/player/spring/DbmsVersionPrecondition.java index 0b16fc04..89161061 100644 --- a/libresonic-main/src/main/java/org/libresonic/player/spring/DbmsVersionPrecondition.java +++ b/libresonic-main/src/main/java/org/libresonic/player/spring/DbmsVersionPrecondition.java @@ -1,64 +1,31 @@ package org.libresonic.player.spring; -import liquibase.changelog.ChangeSet; -import liquibase.changelog.DatabaseChangeLog; import liquibase.database.Database; -import liquibase.exception.PreconditionErrorException; -import liquibase.exception.PreconditionFailedException; -import liquibase.exception.ValidationErrors; -import liquibase.exception.Warnings; -import liquibase.precondition.Precondition; -import liquibase.serializer.AbstractLiquibaseSerializable; +import liquibase.exception.CustomPreconditionErrorException; +import liquibase.exception.CustomPreconditionFailedException; +import liquibase.exception.DatabaseException; +import liquibase.precondition.CustomPrecondition; -public class DbmsVersionPrecondition extends AbstractLiquibaseSerializable implements Precondition { +public class DbmsVersionPrecondition implements CustomPrecondition { private Integer major; private Integer minor; @Override - public String getName() { - return "dbmsVersion"; - } - - @Override - public Warnings warn(Database database) { - return new Warnings(); - } - - @Override - public ValidationErrors validate(Database database) { - return new ValidationErrors(); - } - - @Override - public void check( - Database database, DatabaseChangeLog changeLog, ChangeSet changeSet - ) throws PreconditionFailedException, PreconditionErrorException { + public void check(Database database) throws CustomPreconditionFailedException, CustomPreconditionErrorException { try { int dbMajor = database.getDatabaseMajorVersion(); int dbMinor = database.getDatabaseMinorVersion(); if(major != null && !major.equals(dbMajor)) { - throw new PreconditionFailedException("DBMS Major Version Precondition failed: expected " + major + ", got " + dbMajor, changeLog, this); + throw new CustomPreconditionFailedException("DBMS Major Version Precondition failed: expected " + major + ", got " + dbMajor); } if(minor != null && !minor.equals(dbMinor)) { - throw new PreconditionFailedException("DBMS Minor Version Precondition failed: expected " + minor + ", got " + dbMinor, changeLog, this); + throw new CustomPreconditionFailedException("DBMS Minor Version Precondition failed: expected " + minor + ", got " + dbMinor); } - } catch (PreconditionFailedException e) { - throw e; - } catch (Exception e) { - throw new PreconditionErrorException(e, changeLog, this); + } catch (DatabaseException e) { + throw new CustomPreconditionErrorException(e.getMessage()); } } - @Override - public String getSerializedObjectName() { - return getName(); - } - - @Override - public String getSerializedObjectNamespace() { - return GENERIC_CHANGELOG_EXTENSION_NAMESPACE; - } - public Integer getMajor() { return major; } @@ -74,4 +41,5 @@ public class DbmsVersionPrecondition extends AbstractLiquibaseSerializable imple public void setMinor(Integer minor) { this.minor = minor; } + } diff --git a/libresonic-main/src/main/java/org/libresonic/player/spring/SpringLiquibase.java b/libresonic-main/src/main/java/org/libresonic/player/spring/SpringLiquibase.java index 4eda164a..0ff200b4 100644 --- a/libresonic-main/src/main/java/org/libresonic/player/spring/SpringLiquibase.java +++ b/libresonic-main/src/main/java/org/libresonic/player/spring/SpringLiquibase.java @@ -51,7 +51,6 @@ public class SpringLiquibase extends liquibase.integration.spring.SpringLiquibas if (StringUtils.trimToNull(this.defaultSchema) != null) { database.setDefaultSchemaName(this.defaultSchema); } - liquibase.precondition.PreconditionFactory.getInstance().register(DbmsVersionPrecondition.class); return database; } diff --git a/libresonic-main/src/main/resources/application.properties b/libresonic-main/src/main/resources/application.properties new file mode 100644 index 00000000..d8a35e3b --- /dev/null +++ b/libresonic-main/src/main/resources/application.properties @@ -0,0 +1,3 @@ +spring.mvc.view.prefix: /WEB-INF/jsp/ +spring.mvc.view.suffix: .jsp +server.error.includeStacktrace: ALWAYS diff --git a/libresonic-main/src/main/resources/libresonic-servlet.xml b/libresonic-main/src/main/resources/libresonic-servlet.xml index 5ae4d97e..c34faccd 100644 --- a/libresonic-main/src/main/resources/libresonic-servlet.xml +++ b/libresonic-main/src/main/resources/libresonic-servlet.xml @@ -47,4 +47,6 @@ + + diff --git a/libresonic-main/src/main/resources/liquibase/legacy/schema47.xml b/libresonic-main/src/main/resources/liquibase/legacy/schema47.xml index df3eb9f7..ba176727 100644 --- a/libresonic-main/src/main/resources/liquibase/legacy/schema47.xml +++ b/libresonic-main/src/main/resources/liquibase/legacy/schema47.xml @@ -238,7 +238,7 @@ select count(*) from INFORMATION_SCHEMA.SYSTEM_INDEXINFO where - TABLE_NAME = 'album' and INDEX_NAME = 'idx_album_name'; + lower(TABLE_NAME) = 'album' and lower(INDEX_NAME) = 'idx_album_name'; diff --git a/libresonic-main/src/main/resources/liquibase/legacy/schema53.xml b/libresonic-main/src/main/resources/liquibase/legacy/schema53.xml index f8bad2fd..5a053df4 100644 --- a/libresonic-main/src/main/resources/liquibase/legacy/schema53.xml +++ b/libresonic-main/src/main/resources/liquibase/legacy/schema53.xml @@ -39,7 +39,7 @@ select count(*) from INFORMATION_SCHEMA.SYSTEM_INDEXINFO where - TABLE_NAME = 'podcast_episode' and INDEX_NAME = 'idx_podcast_episode_url'; + lower(TABLE_NAME) = 'podcast_episode' and lower(INDEX_NAME) = 'idx_podcast_episode_url'; diff --git a/libresonic-main/src/main/webapp/error.jsp b/libresonic-main/src/main/webapp/WEB-INF/jsp/error.jsp similarity index 73% rename from libresonic-main/src/main/webapp/error.jsp rename to libresonic-main/src/main/webapp/WEB-INF/jsp/error.jsp index e1b4d758..841a7279 100644 --- a/libresonic-main/src/main/webapp/error.jsp +++ b/libresonic-main/src/main/webapp/WEB-INF/jsp/error.jsp @@ -1,5 +1,7 @@ -<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="iso-8859-1" isErrorPage="true" %> -<%@ page import="java.io.PrintWriter, java.io.StringWriter"%> +<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="UTF-8" isErrorPage="true" %> +<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + - - contextConfigLocation - - /WEB-INF/applicationContext-service.xml - /WEB-INF/applicationContext-security.xml - /WEB-INF/applicationContext-cache.xml - /WEB-INF/applicationContext-sonos.xml - - - - - contextInitializerClasses - org.libresonic.player.spring.AdditionalPropertySourceConfigurer - - - - org.springframework.web.context.ContextLoaderListener - - - net.sf.ehcache.constructs.web.ShutdownListener - - - - libresonic - org.springframework.web.servlet.DispatcherServlet - 1 - - - - CFX Servlet - cxfservlet - org.apache.cxf.transport.servlet.CXFServlet - 1 - - - - DWR Servlet - dwr-invoker - org.directwebremoting.servlet.DwrServlet - - crossDomainSessionSecurity - false - - - - - libresonic - *.view - - - libresonic - /podcast - - - libresonic - /wap - - - libresonic - /play.m3u - - - libresonic - /stream/* - - - libresonic - /rest/* - - - libresonic - /hls/* - - - libresonic - /share/* - - - dwr-invoker - /dwr/* - - - cxfservlet - /ws/* - - - - index.html - index.jsp - - - - java.lang.Throwable - /error.jsp - - - - BootstrapVerificationFilter - org.libresonic.player.filter.BootstrapVerificationFilter - - - BootstrapVerificationFilter - /* - - - - ParameterDecodingFilter - org.libresonic.player.filter.ParameterDecodingFilter - - - ParameterDecodingFilter - /* - - - - RESTFilter - org.libresonic.player.filter.RESTFilter - - - RESTFilter - /rest/* - - - - RequestEncodingFilter - org.libresonic.player.filter.RequestEncodingFilter - - encoding - UTF-8 - - - - RequestEncodingFilter - /* - - - - Sets HTTP headers to enable browser caching. - CacheFilter - org.libresonic.player.filter.ResponseHeaderFilter - - Cache-Control - max-age=36000 - - - - - Sets HTTP headers to disable browser caching. - NoCacheFilter - org.libresonic.player.filter.ResponseHeaderFilter - - Cache-Control - no-cache, post-check=0, pre-check=0 - - - Pragma - no-cache - - - Expires - Thu, 01 Dec 1994 16:00:00 GMT - - - - - CacheFilter - /icons/* - - - CacheFilter - /style/* - - - - NoCacheFilter - /statusChart.view - - - NoCacheFilter - /userChart.view - - - NoCacheFilter - /playQueue.view - - - NoCacheFilter - /podcastChannels.view - - - NoCacheFilter - /podcastChannel.view - - - NoCacheFilter - /help.view - - - NoCacheFilter - /top.view - - - NoCacheFilter - /home.view - - - - springSecurityFilterChain - org.springframework.web.filter.DelegatingFilterProxy - - - - springSecurityFilterChain - /* - - - \ No newline at end of file diff --git a/pom.xml b/pom.xml index e0b6a88d..ee8c42c9 100644 --- a/pom.xml +++ b/pom.xml @@ -142,6 +142,12 @@ maven-jaxb2-plugin 0.13.1 + + maven-war-plugin + + false + + From 7b304cf57d2d48343369e557fc5b1378793c9e78 Mon Sep 17 00:00:00 2001 From: Andrew DeMaria Date: Tue, 27 Dec 2016 22:41:12 -0700 Subject: [PATCH 2/4] Fix sql type error for postgres Signed-off-by: Andrew DeMaria --- .../src/main/java/org/libresonic/player/dao/MusicFolderDao.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libresonic-main/src/main/java/org/libresonic/player/dao/MusicFolderDao.java b/libresonic-main/src/main/java/org/libresonic/player/dao/MusicFolderDao.java index 705739f0..21b88606 100644 --- a/libresonic-main/src/main/java/org/libresonic/player/dao/MusicFolderDao.java +++ b/libresonic-main/src/main/java/org/libresonic/player/dao/MusicFolderDao.java @@ -59,7 +59,7 @@ public class MusicFolderDao extends AbstractDao { */ public void createMusicFolder(MusicFolder musicFolder) { String sql = "insert into music_folder (" + INSERT_COLUMNS + ") values (?, ?, ?, ?)"; - update(sql, musicFolder.getPath(), musicFolder.getName(), musicFolder.isEnabled(), musicFolder.getChanged()); + update(sql, musicFolder.getPath().getPath(), musicFolder.getName(), musicFolder.isEnabled(), musicFolder.getChanged()); Integer id = queryForInt("select max(id) from music_folder", 0); update("insert into music_folder_user (music_folder_id, username) select ?, username from " + userDao.getUserTable(), id); From f57da83df187bbd7083e3382bb2190491534acee Mon Sep 17 00:00:00 2001 From: Andrew DeMaria Date: Mon, 2 Jan 2017 15:44:10 -0700 Subject: [PATCH 3/4] Removed checkpoint call Signed-off-by: Andrew DeMaria --- .../src/main/java/org/libresonic/player/dao/MediaFileDao.java | 1 - 1 file changed, 1 deletion(-) diff --git a/libresonic-main/src/main/java/org/libresonic/player/dao/MediaFileDao.java b/libresonic-main/src/main/java/org/libresonic/player/dao/MediaFileDao.java index 7dc7ffd5..dd111334 100644 --- a/libresonic-main/src/main/java/org/libresonic/player/dao/MediaFileDao.java +++ b/libresonic-main/src/main/java/org/libresonic/player/dao/MediaFileDao.java @@ -676,7 +676,6 @@ public class MediaFileDao extends AbstractDao { for (int id = minId; id <= maxId; id += batchSize) { update("delete from media_file where id between ? and ? and not present", id, id + batchSize); } - update("checkpoint"); } private static class MediaFileMapper implements RowMapper { From bbe20e25562b2a52f3ed90f0ee8359e30bb815f2 Mon Sep 17 00:00:00 2001 From: Andrew DeMaria Date: Mon, 2 Jan 2017 18:25:53 -0700 Subject: [PATCH 4/4] Fix podcast query Signed-off-by: Andrew DeMaria --- .../src/main/java/org/libresonic/player/dao/PodcastDao.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libresonic-main/src/main/java/org/libresonic/player/dao/PodcastDao.java b/libresonic-main/src/main/java/org/libresonic/player/dao/PodcastDao.java index 3940435e..8d4890bc 100644 --- a/libresonic-main/src/main/java/org/libresonic/player/dao/PodcastDao.java +++ b/libresonic-main/src/main/java/org/libresonic/player/dao/PodcastDao.java @@ -122,7 +122,7 @@ public class PodcastDao extends AbstractDao { public List getEpisodes(int channelId) { String sql = "select " + EPISODE_QUERY_COLUMNS + " from podcast_episode where channel_id = ? " + "and status != ? order by publish_date desc"; - return query(sql, episodeRowMapper, channelId, PodcastStatus.DELETED); + return query(sql, episodeRowMapper, channelId, PodcastStatus.DELETED.name()); } /** @@ -135,7 +135,7 @@ public class PodcastDao extends AbstractDao { String sql = "select " + EPISODE_QUERY_COLUMNS + " from podcast_episode where status = ? and publish_date is not null " + "order by publish_date desc limit ?"; - return query(sql, episodeRowMapper, PodcastStatus.COMPLETED, count); + return query(sql, episodeRowMapper, PodcastStatus.COMPLETED.name(), count); } /**