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/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 {
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);
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);
}
/**
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
+
+