Merge Pull Request #124 into develop

master
Eugene E. Kashpureff Jr 8 years ago
commit 9d3d6ce52d
  1. 13
      libresonic-main/pom.xml
  2. 5
      libresonic-main/src/main/java/org/libresonic/player/service/MediaScannerService.java
  3. 123
      libresonic-main/src/test/java/org/libresonic/player/TestCaseUtils.java
  4. 3
      libresonic-main/src/test/java/org/libresonic/player/dao/DaoTestCaseBase.java
  5. 39
      libresonic-main/src/test/java/org/libresonic/player/dao/MusicFolderDaoMock.java
  6. 120
      libresonic-main/src/test/java/org/libresonic/player/service/MediaScannerServiceTestCase.java
  7. 10
      libresonic-main/src/test/java/org/libresonic/player/service/SettingsServiceTestCase.java
  8. BIN
      libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Céline Frisch- Café Zimmermann - Bach- Goldberg Variations, Canons [Disc 1]/01 - Bach- Goldberg Variations, BWV 988 - Aria.flac
  9. BIN
      libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Céline Frisch- Café Zimmermann - Bach- Goldberg Variations, Canons [Disc 1]/02 - Bach- Goldberg Variations, BWV 988 - Variatio 1 A 1 Clav..flac
  10. BIN
      libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Céline Frisch- Café Zimmermann - Bach- Goldberg Variations, Canons [Disc 1]/Folder.jpg
  11. BIN
      libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Chamber Music With Voice/01 - Sonata Violin & Cello I. Allegro.ogg
  12. BIN
      libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Chamber Music With Voice/02 - Sonata Violin & Cello II. Tres Vif.ogg
  13. BIN
      libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Chamber Music With Voice/Folder.jpg
  14. BIN
      libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Complete Piano Works/01 - Gaspard de la Nuit - i. Ondine.mp3
  15. BIN
      libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Complete Piano Works/02 - Gaspard de la Nuit - ii. Le Gibet.mp3
  16. BIN
      libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Complete Piano Works/Folder.jpeg
  17. BIN
      libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Sixteen Horsepower/_DIR_ Sackcloth 'n' Ashes/Sixteen Horsepower - 01 I Seen What I Saw.mp3
  18. BIN
      libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Sixteen Horsepower/_DIR_ Sackcloth 'n' Ashes/Sixteen Horsepower - 02 Black Soul Choir.mp3
  19. BIN
      libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Sixteen Horsepower/_DIR_ Sackcloth 'n' Ashes/Sixteen Horsepower - 10 Reed Neck Reel.mp3
  20. BIN
      libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Sixteen Horsepower/_DIR_ Sackcloth 'n' Ashes/cover.jpg
  21. BIN
      libresonic-main/src/test/resources/MEDIAS/Music2/_DIR_ chrome hoof - 2004/02 eyes like dull hazlenuts.mp3
  22. BIN
      libresonic-main/src/test/resources/MEDIAS/Music2/_DIR_ chrome hoof - 2004/10 telegraph hill.mp3
  23. BIN
      libresonic-main/src/test/resources/MEDIAS/Music2/_DIR_ chrome hoof - 2004/Folder.jpg
  24. 17
      libresonic-main/src/test/resources/org/libresonic/player/service/mediaScannerServiceTestCase/applicationContext-cache.xml
  25. 186
      libresonic-main/src/test/resources/org/libresonic/player/service/mediaScannerServiceTestCase/applicationContext-service.xml

@ -12,6 +12,10 @@
<version>6.1.beta2</version>
</parent>
<properties>
<metrics.version>3.1.0</metrics.version>
</properties>
<dependencies>
<dependency>
@ -26,6 +30,15 @@
<version>${project.version}</version>
</dependency>
<!-- Metrics -->
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId>
<version>${metrics.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>

@ -70,6 +70,11 @@ public class MediaScannerService {
schedule();
}
public void initNoSchedule() {
deleteOldIndexFiles();
statistics = settingsService.getMediaLibraryStatistics();
}
/**
* Schedule background execution of media library scanning.
*/

@ -0,0 +1,123 @@
package org.libresonic.player;
import org.apache.commons.io.FileUtils;
import org.libresonic.player.dao.DaoHelper;
import org.libresonic.player.service.MediaScannerService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class TestCaseUtils {
private static final String LIBRESONIC_HOME_FOR_TEST = "/tmp/libresonic";
private static File libresonicHomeDirForTest = null;
/**
* Returns the path of the LIBRESONIC_HOME directory to use for tests.
* This will create a temporary directory.
*
* @return LIBRESONIC_HOME directory path.
* @throws RuntimeException if it fails to create the temp directory.
*/
public static String libresonicHomePathForTest() {
if (libresonicHomeDirForTest == null) {
try {
libresonicHomeDirForTest = Files.createTempDirectory("libresonic_test_").toFile();
} catch (IOException e) {
throw new RuntimeException("Error while creating temporary LIBRESONIC_HOME directory for tests");
}
System.out.println("LIBRESONIC_HOME directory will be "+libresonicHomeDirForTest.getAbsolutePath());
}
return libresonicHomeDirForTest.getAbsolutePath();
}
/**
* Cleans the LIBRESONIC_HOME directory used for tests.
*
* @throws IOException
*/
public static void cleanLibresonicHomeForTest() throws IOException {
File libresonicHomeDir = new File(libresonicHomePathForTest());
if (libresonicHomeDir.exists() && libresonicHomeDir.isDirectory()) {
System.out.println("Delete libresonic home (ie. "+libresonicHomeDir.getAbsolutePath()+").");
try {
FileUtils.deleteDirectory(libresonicHomeDir);
} catch (IOException e) {
System.out.println("Error while deleting libresonic home.");
e.printStackTrace();
throw e;
}
}
}
/**
* Constructs a map of records count per table.
*
* @param daoHelper DaoHelper object
* @return Map table name -> records count
*/
public static Map<String, Integer> recordsInAllTables(DaoHelper daoHelper) {
List<String> tableNames = daoHelper.getJdbcTemplate().queryForList("" +
"select table_name " +
"from information_schema.system_tables " +
"where table_name not like 'SYSTEM%'"
, String.class);
Map<String, Integer> nbRecords =
tableNames.stream()
.collect(Collectors.toMap(table -> table, table -> recordsInTable(table,daoHelper)));
return nbRecords;
}
/**
* Counts records in a table.
*
* @param tableName
* @param daoHelper
* @return
*/
public static Integer recordsInTable(String tableName, DaoHelper daoHelper) {
return daoHelper.getJdbcTemplate().queryForInt("select count(1) from " + tableName);
}
public static ApplicationContext loadSpringApplicationContext(String baseResources) {
String applicationContextService = baseResources + "applicationContext-service.xml";
String applicationContextCache = baseResources + "applicationContext-cache.xml";
String[] configLocations = new String[]{
TestCaseUtils.class.getClass().getResource(applicationContextCache).toString(),
TestCaseUtils.class.getClass().getResource(applicationContextService).toString()
};
return new ClassPathXmlApplicationContext(configLocations);
}
/**
* Scans the music library * @param mediaScannerService
*/
public static void execScan(MediaScannerService mediaScannerService) {
mediaScannerService.scanLibrary();
while (mediaScannerService.isScanning()) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

@ -1,6 +1,7 @@
package org.libresonic.player.dao;
import junit.framework.TestCase;
import org.libresonic.player.TestCaseUtils;
import org.libresonic.player.util.FileUtil;
import org.springframework.jdbc.core.JdbcTemplate;
@ -61,7 +62,7 @@ public abstract class DaoTestCaseBase extends TestCase {
}
private static void deleteDatabase() {
File libresonicHome = new File("/tmp/libresonic");
File libresonicHome = new File(TestCaseUtils.libresonicHomePathForTest());
File dbHome = new File(libresonicHome, "db");
System.setProperty("libresonic.home", libresonicHome.getPath());

@ -0,0 +1,39 @@
package org.libresonic.player.dao;
import org.libresonic.player.domain.MusicFolder;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class MusicFolderDaoMock extends MusicFolderDao {
private static String baseResources = "/MEDIAS/";
public static String resolveBaseMediaPath() {
String baseDir = MusicFolderDaoMock.class.getResource(baseResources).toString().replace("file:","");
return baseDir;
}
public static String resolveMusicFolderPath() {
return (MusicFolderDaoMock.resolveBaseMediaPath() + "Music");
}
public static String resolveMusic2FolderPath() {
return (MusicFolderDaoMock.resolveBaseMediaPath() + "Music2");
}
@Override
public List<MusicFolder> getAllMusicFolders() {
List<MusicFolder> liste = new ArrayList<>();
File musicDir = new File(MusicFolderDaoMock.resolveMusicFolderPath());
MusicFolder musicFolder = new MusicFolder(1,musicDir,"Music",true,new Date());
liste.add(musicFolder);
File music2Dir = new File(MusicFolderDaoMock.resolveMusic2FolderPath());
MusicFolder musicFolder2 = new MusicFolder(2,music2Dir,"Music2",true,new Date());
liste.add(musicFolder2);
return liste;
}
}

@ -0,0 +1,120 @@
package org.libresonic.player.service;
import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.JmxReporter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import junit.framework.Assert;
import junit.framework.TestCase;
import org.libresonic.player.TestCaseUtils;
import org.libresonic.player.dao.*;
import org.libresonic.player.domain.Album;
import org.libresonic.player.domain.Artist;
import org.libresonic.player.domain.MediaFile;
import org.springframework.context.ApplicationContext;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* A unit test class to test the MediaScannerService.
*
* This class uses the Spring application context configuration present in the
* /org/libresonic/player/service/mediaScannerServiceTestCase/ directory.
*
* The media library is found in the /MEDIAS directory.
* It is composed of 2 musicFolders (Music and Music2) and several little weight audio files.
*
* At runtime, the subsonic_home dir is set to target/test-classes/org/libresonic/player/service/mediaScannerServiceTestCase.
* An empty database is created on the fly.
*
*/
public class MediaScannerServiceTestCase extends TestCase {
private static String baseResources = "/org/libresonic/player/service/mediaScannerServiceTestCase/";
private final MetricRegistry metrics = new MetricRegistry();
private MediaScannerService mediaScannerService = null;
private MediaFileDao mediaFileDao = null;
private MusicFolderDao musicFolderDao = null;
private DaoHelper daoHelper = null;
private MediaFileService mediaFileService = null;
private ArtistDao artistDao = null;
private AlbumDao albumDao = null;
@Override
protected void setUp() throws Exception {
super.setUp();
System.setProperty("libresonic.home", TestCaseUtils.libresonicHomePathForTest());
TestCaseUtils.cleanLibresonicHomeForTest();
// load spring context
ApplicationContext context = TestCaseUtils.loadSpringApplicationContext(baseResources);
mediaScannerService = (MediaScannerService)context.getBean("mediaScannerService");
mediaFileDao = (MediaFileDao)context.getBean("mediaFileDao");
musicFolderDao = (MusicFolderDao) context.getBean("musicFolderDao");
daoHelper = (DaoHelper) context.getBean("daoHelper");
mediaFileService = (MediaFileService) context.getBean("mediaFileService");
artistDao = (ArtistDao) context.getBean("artistDao");
albumDao = (AlbumDao) context.getBean("albumDao");
}
/**
* Tests the MediaScannerService by scanning the test media library into an empty database.
*/
public void testScanLibrary() {
Timer globalTimer = metrics.timer(MetricRegistry.name(MediaScannerServiceTestCase.class, "Timer.global"));
Timer.Context globalTimerContext = globalTimer.time();
TestCaseUtils.execScan(mediaScannerService);
globalTimerContext.stop();
System.out.println("--- Report of records count per table ---");
Map<String,Integer> records = TestCaseUtils.recordsInAllTables(daoHelper);
records.keySet().forEach(tableName -> System.out.println(tableName+" : "+records.get(tableName).toString() ));
System.out.println("--- *********************** ---");
// Music Folder Music must have 3 children
List<MediaFile> listeMusicChildren = mediaFileDao.getChildrenOf(MusicFolderDaoMock.resolveMusicFolderPath());
Assert.assertEquals(3,listeMusicChildren.size());
// Music Folder Music2 must have 1 children
List<MediaFile> listeMusic2Children = mediaFileDao.getChildrenOf(MusicFolderDaoMock.resolveMusic2FolderPath());
Assert.assertEquals(1,listeMusic2Children.size());
System.out.println("--- List of all artists ---");
System.out.println("artistName#albumCount");
List<Artist> allArtists = artistDao.getAlphabetialArtists(0,0,musicFolderDao.getAllMusicFolders());
allArtists.forEach(artist -> System.out.println(artist.getName()+"#"+artist.getAlbumCount()));
System.out.println("--- *********************** ---");
System.out.println("--- List of all albums ---");
System.out.println("name#artist");
List<Album> allAlbums = albumDao.getAlphabetialAlbums(0,0,true,musicFolderDao.getAllMusicFolders());
allAlbums.forEach(album -> System.out.println(album.getName()+"#"+album.getArtist()));
Assert.assertEquals(5,allAlbums.size());
System.out.println("--- *********************** ---");
List<MediaFile> listeSongs = mediaFileDao.getSongsByGenre("Baroque Instrumental",0,0,musicFolderDao.getAllMusicFolders());
Assert.assertEquals(2,listeSongs.size());
// display out metrics report
ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics)
.convertRatesTo(TimeUnit.SECONDS.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.build();
reporter.report();
System.out.print("End");
}
}

@ -25,6 +25,7 @@ import java.util.Date;
import java.util.Locale;
import junit.framework.TestCase;
import org.libresonic.player.TestCaseUtils;
/**
* Unit test of {@link SettingsService}.
@ -33,19 +34,18 @@ import junit.framework.TestCase;
*/
public class SettingsServiceTestCase extends TestCase {
private static final File LIBRESONIC_HOME = new File("/tmp/libresonic");
private SettingsService settingsService;
@Override
protected void setUp() throws Exception {
System.setProperty("libresonic.home", LIBRESONIC_HOME.getPath());
new File(LIBRESONIC_HOME, "libresonic.properties").delete();
String libresonicHome = TestCaseUtils.libresonicHomePathForTest();
System.setProperty("libresonic.home", libresonicHome);
new File(libresonicHome, "libresonic.properties").delete();
settingsService = new SettingsService();
}
public void testLibresonicHome() {
assertEquals("Wrong Libresonic home.", LIBRESONIC_HOME, SettingsService.getLibresonicHome());
assertEquals("Wrong Libresonic home.", TestCaseUtils.libresonicHomePathForTest(), SettingsService.getLibresonicHome().getAbsolutePath());
}
public void testDefaultValues() {

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="cacheFactory" class="org.libresonic.player.cache.CacheFactory"/>
<bean id="userCache" factory-bean="cacheFactory" factory-method="getCache">
<constructor-arg value="userCache"/>
</bean>
<bean id="mediaFileMemoryCache" factory-bean="cacheFactory" factory-method="getCache">
<constructor-arg value="mediaFileMemoryCache"/>
</bean>
</beans>

@ -0,0 +1,186 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!-- DAO's -->
<bean id="playerDao" class="org.libresonic.player.dao.PlayerDao">
<property name="daoHelper" ref="daoHelper"/>
</bean>
<bean id="mediaFileDao" class="org.libresonic.player.dao.MediaFileDao">
<property name="daoHelper" ref="daoHelper"/>
</bean>
<bean id="artistDao" class="org.libresonic.player.dao.ArtistDao">
<property name="daoHelper" ref="daoHelper"/>
</bean>
<bean id="albumDao" class="org.libresonic.player.dao.AlbumDao">
<property name="daoHelper" ref="daoHelper"/>
</bean>
<bean id="playlistDao" class="org.libresonic.player.dao.PlaylistDao">
<property name="daoHelper" ref="daoHelper"/>
</bean>
<bean id="playQueueDao" class="org.libresonic.player.dao.PlayQueueDao">
<property name="daoHelper" ref="daoHelper"/>
</bean>
<bean id="internetRadioDao" class="org.libresonic.player.dao.InternetRadioDao">
<property name="daoHelper" ref="daoHelper"/>
</bean>
<bean id="musicFileInfoDao" class="org.libresonic.player.dao.RatingDao">
<property name="daoHelper" ref="daoHelper"/>
</bean>
<bean id="musicFolderDao" class="org.libresonic.player.dao.MusicFolderDaoMock">
<property name="daoHelper" ref="daoHelper"/>
</bean>
<bean id="userDao" class="org.libresonic.player.dao.UserDao">
<property name="daoHelper" ref="daoHelper"/>
</bean>
<bean id="transcodingDao" class="org.libresonic.player.dao.TranscodingDao">
<property name="daoHelper" ref="daoHelper"/>
</bean>
<bean id="podcastDao" class="org.libresonic.player.dao.PodcastDao">
<property name="daoHelper" ref="daoHelper"/>
</bean>
<bean id="avatarDao" class="org.libresonic.player.dao.AvatarDao">
<property name="daoHelper" ref="daoHelper"/>
</bean>
<bean id="shareDao" class="org.libresonic.player.dao.ShareDao">
<property name="daoHelper" ref="daoHelper"/>
</bean>
<bean id="bookmarkDao" class="org.libresonic.player.dao.BookmarkDao">
<property name="daoHelper" ref="daoHelper"/>
</bean>
<bean id="daoHelper" class="org.libresonic.player.dao.DaoHelperFactory" factory-method="create"/>
<!-- Services -->
<bean id="mediaFileService" class="org.libresonic.player.service.MediaFileService">
<property name="securityService" ref="securityService"/>
<property name="settingsService" ref="settingsService"/>
<property name="mediaFileMemoryCache" ref="mediaFileMemoryCache"/>
<property name="mediaFileDao" ref="mediaFileDao"/>
<property name="albumDao" ref="albumDao"/>
<property name="metaDataParserFactory" ref="metaDataParserFactory"/>
</bean>
<bean id="securityService" class="org.libresonic.player.service.SecurityService">
<property name="settingsService" ref="settingsService"/>
<property name="userDao" ref="userDao"/>
<property name="userCache" ref="userCache"/>
</bean>
<bean id="settingsService" class="org.libresonic.player.service.SettingsService" init-method="init">
<property name="internetRadioDao" ref="internetRadioDao"/>
<property name="musicFolderDao" ref="musicFolderDao"/>
<property name="userDao" ref="userDao"/>
<property name="avatarDao" ref="avatarDao"/>
<property name="versionService" ref="versionService"/>
</bean>
<bean id="mediaScannerService" class="org.libresonic.player.service.MediaScannerService" init-method="initNoSchedule" depends-on="metaDataParserFactory">
<property name="settingsService" ref="settingsService"/>
<property name="mediaFileService" ref="mediaFileService"/>
<property name="mediaFileDao" ref="mediaFileDao"/>
<property name="playlistService" ref="playlistService"/>
<property name="artistDao" ref="artistDao"/>
<property name="albumDao" ref="albumDao"/>
<property name="searchService" ref="searchService"/>
<!-- <property name="queueSender" ref="queueSender"/> -->
</bean>
<bean id="searchService" class="org.libresonic.player.service.SearchService">
<property name="mediaFileService" ref="mediaFileService"/>
<property name="artistDao" ref="artistDao"/>
<property name="albumDao" ref="albumDao"/>
</bean>
<bean id="networkService" class="org.libresonic.player.service.NetworkService" init-method="init">
<property name="settingsService" ref="settingsService"/>
</bean>
<bean id="playerService" class="org.libresonic.player.service.PlayerService" init-method="init">
<property name="playerDao" ref="playerDao"/>
<property name="statusService" ref="statusService"/>
<property name="securityService" ref="securityService"/>
<property name="transcodingService" ref="transcodingService"/>
</bean>
<bean id="playlistService" class="org.libresonic.player.service.PlaylistService">
<property name="mediaFileService" ref="mediaFileService"/>
<property name="securityService" ref="securityService"/>
<property name="settingsService" ref="settingsService"/>
<property name="mediaFileDao" ref="mediaFileDao"/>
<property name="playlistDao" ref="playlistDao"/>
</bean>
<bean id="versionService" class="org.libresonic.player.service.VersionService" init-method="init"/>
<bean id="statusService" class="org.libresonic.player.service.StatusService">
<property name="mediaFileService" ref="mediaFileService"/>
</bean>
<bean id="ratingService" class="org.libresonic.player.service.RatingService">
<property name="ratingDao" ref="musicFileInfoDao"/>
<property name="mediaFileService" ref="mediaFileService"/>
<property name="securityService" ref="securityService"/>
</bean>
<bean id="musicIndexService" class="org.libresonic.player.service.MusicIndexService">
<property name="settingsService" ref="settingsService"/>
<property name="mediaFileService" ref="mediaFileService"/>
</bean>
<bean id="transcodingService" class="org.libresonic.player.service.TranscodingService">
<property name="transcodingDao" ref="transcodingDao"/>
<property name="settingsService" ref="settingsService"/>
</bean>
<bean id="podcastService" class="org.libresonic.player.service.PodcastService" init-method="init">
<property name="podcastDao" ref="podcastDao"/>
<property name="settingsService" ref="settingsService"/>
<property name="securityService" ref="securityService"/>
<property name="mediaFileService" ref="mediaFileService"/>
<property name="metaDataParserFactory" ref="metaDataParserFactory"/>
</bean>
<bean id="metaDataParserFactory" class="org.libresonic.player.service.metadata.MetaDataParserFactory">
<property name="parsers">
<list>
<bean class="org.libresonic.player.service.metadata.JaudiotaggerParser"/>
<bean class="org.libresonic.player.service.metadata.FFmpegParser">
<property name="transcodingService" ref="transcodingService"/>
</bean>
<bean class="org.libresonic.player.service.metadata.DefaultMetaDataParser"/>
</list>
</property>
</bean>
<bean id="localeResolver" class="org.libresonic.player.i18n.LibresonicLocaleResolver">
<property name="securityService" ref="securityService"/>
<property name="settingsService" ref="settingsService"/>
</bean>
</beans>
Loading…
Cancel
Save