Jean-Francois Leveque

https://tree.taiga.io/project/jr-utily-grog-v3/us/188 Faire une recherche global…

…e qui renvoie les résultats full text sur toutes les entités
......@@ -2,5 +2,8 @@ package org.legrog.entities;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface AccountRepository extends JpaRepository<Account, Integer> {
List<Account> findByUserIdIn(List<Integer> integers);
}
......
package org.legrog.entities;
import java.util.List;
/**
*
*/
public interface AccountSearchRepository {
/**
*
* @param string String searched in indexed Accounts
* @return Accounts that match the string
*/
List<IndexedAccount> search(String string) throws SearchingException;
}
package org.legrog.entities;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
*
*/
public class AccountSearchRepositorySolrj implements AccountSearchRepository {
Logger logger = LoggerFactory.getLogger(getClass());
SolrClient solrClient;
@Inject
AccountSearchRepositorySolrj(SolrClient solrClient) {
this.solrClient = solrClient;
}
//no args constructor to make it proxyable
AccountSearchRepositorySolrj() {
}
@Override
public List<IndexedAccount> search(String string) throws SearchingException {
SolrQuery solrQuery = new SolrQuery(string);
QueryResponse queryResponse;
try {
queryResponse = solrClient.query("accounts", solrQuery);
} catch (IOException ioe) {
throw new SearchingException(ioe);
} catch (SolrServerException sse) {
logger.error("SolrServerException {}", sse);
throw new SearchingException(sse.getRootCause());
}
if (queryResponse != null) {
return queryResponse.getBeans(IndexedAccount.class);
} else {
return new ArrayList<>();
}
}
}
package org.legrog.web.account;
import org.legrog.entities.Account;
import org.legrog.entities.IndexedAccount;
import org.legrog.entities.PublisherVersion;
import org.legrog.entities.SearchingException;
import javax.validation.constraints.NotNull;
import java.util.List;
public interface AccountService {
......@@ -12,4 +16,18 @@ public interface AccountService {
Account findUserById(int id);
void updateUser(Account account);
/**
*
* @param string String searched in indexed Accounts
* @return indexed IndexedAccounts that match the String
*/
List<Account> search(@NotNull String string) throws SearchingException;
/**
*
* @param indexedAccounts IndexedAccount to convert
* @return Accounts
*/
List<Account> convert(List<IndexedAccount> indexedAccounts);
}
......
package org.legrog.web.account;
import org.legrog.entities.Account;
import org.legrog.entities.AccountRepository;
import org.legrog.entities.*;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
@Stateless
......@@ -12,6 +13,26 @@ public class AccountServiceDefault implements AccountService {
@Inject
AccountRepository accountRepository;
@Inject
AccountSearchRepository accountSearchRepository;
/**
* Le service s'appuie concrètement sur un ensemble de dépôts et sur le service auxiliaire SharedService.
*
* @param accountRepository
* @param accountSearchRepository
*/
@Inject
public AccountServiceDefault(AccountRepository accountRepository,
AccountSearchRepository accountSearchRepository) {
this.accountRepository = accountRepository;
this.accountSearchRepository = accountSearchRepository;
}
AccountServiceDefault() {
//no args constructor to make it proxyable
}
public void addUser(Account account) {
accountRepository.save(account);
}
......@@ -27,4 +48,21 @@ public class AccountServiceDefault implements AccountService {
public void updateUser(Account account) {
accountRepository.save(account);
}
@Override
public List<Account> search(@NotNull String string) throws SearchingException {
return convert(accountSearchRepository.search(string));
}
@Override
public List<Account> convert(List<IndexedAccount> indexedAccounts) {
List<Integer> integers = new ArrayList<>(indexedAccounts.size());
indexedAccounts.forEach(indexedAccount -> integers.add(indexedAccount.getUserId()));
if (integers.size() > 0) {
return accountRepository.findByUserIdIn(integers);
}
return new ArrayList<>();
}
}
\ No newline at end of file
......
......@@ -43,12 +43,8 @@ public class PublisherSearchView implements Serializable {
/**
*
*/
public void search() {
try {
public void search() throws SearchingException {
this.publisherVersions = publisherService.search(this.searchString);
} catch (SearchingException se) {
// TODO Handle Exception
}
}
public String getSearchString() {
......
package org.legrog.web.xyz;
import org.legrog.entities.Account;
import org.legrog.entities.PublisherVersion;
import org.legrog.entities.SearchingException;
import org.legrog.web.account.AccountService;
import org.legrog.web.publisher.PublisherService;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.ArrayList;
import java.util.List;
/**
* View behind search.xhtml
*/
@Named
@RequestScoped
public class SearchView {
List<PublisherVersion> publisherVersions = new ArrayList<>();
List<Account> accounts = new ArrayList<>();
String searchString = new String();
transient PublisherService publisherService;
transient AccountService accountService;
/**
* Uses PublisherService to access search repository
*
* @param publisherService injected PublisherService
*/
@Inject
public SearchView(PublisherService publisherService, AccountService accountService) {
this.publisherService = publisherService;
this.accountService = accountService;
}
SearchView() {
//no args constructor to make it proxyable
}
public boolean publisherSearchEmpty() {
return ((!searchString.isEmpty()) && publisherVersions.isEmpty());
}
public boolean accountSearchEmpty() {
return ((!searchString.isEmpty()) && accounts.isEmpty());
}
public void search() throws SearchingException {
this.publisherVersions = publisherService.search(this.searchString);
this.accounts = accountService.search(this.searchString);
}
public String getSearchString() {
return searchString;
}
public void setSearchString(String searchString) {
this.searchString = searchString;
}
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
public List<PublisherVersion> getPublisherVersions() {
return publisherVersions;
}
public void setPublisherVersions(List<PublisherVersion> publisherVersions) {
this.publisherVersions = publisherVersions;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:jsf="http://xmlns.jcp.org/jsf">
<head>
<link rel="stylesheet" type="text/css" href="/minimal.css"/>
</head>
<body>
<ul>
<li>
<a jsf:outcome="/index">Menu principal</a>
</li>
<li>Éditeurs
<ul>
<li>
<a jsf:outcome="/publisher/publisherSearch">Recherche dans les éditeurs</a>
</li>
<li>
<a jsf:outcome="/publisher/listPublisherVersions">Liste des versions des éditeurs</a>
</li>
<li>
<a jsf:outcome="/publisher/listPublisherActions">Liste des actions des éditeurs</a>
</li>
<li>
<a jsf:outcome="/publisher/publisherVersion">Ajouter un éditeur</a>
</li>
</ul>
</li>
<li>Pays
<ul>
<li>
<a jsf:outcome="listCountries">Liste des pays</a>
</li>
<li>
<a jsf:outcome="addCountry">Ajouter un pays</a>
</li>
</ul>
</li>
</ul>
<form action="" jsf:id="search">
<h:panelGrid columns="2">
<label for="searchString">Élément recherché dans l'ensemble de l'encyclopédie</label>
<input type="text" id="searchString" jsf:value='#{searchView.searchString}'/>
<button jsf:action="#{searchView.search}">Rechercher</button>
</h:panelGrid>
</form>
<p jsf:rendered="#{searchView.publisherSearchEmpty()}">Aucun éditeur ne correspond à votre recherche : ${searchView.searchString}.</p>
<h:dataTable rendered="#{!searchView.publisherVersions.isEmpty()}" value="#{searchView.publisherVersions}" var="version">
<h:column>
<f:facet name="header">Name</f:facet>
${version.publisherName}
</h:column>
<h:column>
<f:facet name="header">Address</f:facet>
${version.publisherPostOfficeBoxNumber}<br />
${version.publisherStreetAddress}<br />
${version.publisherPostalCode} ${version.publisherAddressLocality}<br />
${version.publisherAddressRegion}<br />
${version.publisherAddressCountry.countryName}
</h:column>
<h:column>
<f:facet name="header">Telephone</f:facet>
${version.publisherTelephone}
</h:column>
<h:column>
<f:facet name="header">Email</f:facet>
${version.publisherEmail}
</h:column>
<h:column>
<f:facet name="header">URL</f:facet>
${version.publisherURL}
</h:column>
<h:column>
<f:facet name="header">History</f:facet>
<h:outputText escape="false" value="#{version.publisherHistory}"/>
</h:column>
</h:dataTable>
<p jsf:rendered="#{searchView.accountSearchEmpty()}">Aucun compte ne correspond à votre recherche : ${searchView.searchString}.</p>
<h:dataTable rendered="#{!searchView.accounts.isEmpty()}" value="#{searchView.accounts}" var="account">
<h:column>
<f:facet name="header">Name</f:facet>
${account.getDisplayName()}
</h:column>
<h:column>
<f:facet name="header">Presentation</f:facet>
<h:outputText escape="false" value="#{account.presentation}"/>
</h:column>
</h:dataTable>
</body>
</html>
package org.legrog.web.account;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.legrog.entities.*;
import org.mockito.Mock;
import org.mockito.Mockito;
import java.util.ArrayList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Classe testing AccountServiceDefault.
*/
public class AccountServiceDefaultTest {
AccountServiceDefault accountServiceDefault;
@BeforeEach
public void setUp(@Mock AccountRepository accountRepository,
@Mock AccountSearchRepository accountSearchRepository) throws Exception {
accountServiceDefault = Mockito.spy(new AccountServiceDefault(accountRepository, accountSearchRepository));
}
@Nested
@DisplayName("search method")
class SearchTests {
@DisplayName("When called, should delegate search to AccountSearchRepository")
@Test
public void testDelegateSearchToAccountSearchRepository(@Mock AccountSearchRepository accountSearchRepository) throws SearchingException {
accountServiceDefault.search("3");
Mockito.verify(accountSearchRepository).search("3");
}
@DisplayName("When getting IndexedAccounts from search, should convert them")
@Test
public void testConvertReturnedIndexedAccounts(@Mock AccountSearchRepository accountSearchRepository) throws SearchingException {
List<IndexedAccount> indexedAccounts = new ArrayList<>();
when(accountSearchRepository.search("4")).thenReturn(indexedAccounts);
accountServiceDefault.search("4");
verify(accountServiceDefault, times(1)).convert(indexedAccounts);
}
@DisplayName("When called, should return the Accounts it gets from convert")
@Test
public void testReturnFromConvert(@Mock AccountSearchRepository accountSearchRepository) throws SearchingException {
List<Account> accounts = new ArrayList<>();
List<IndexedAccount> indexedAccounts = new ArrayList<>();
Mockito.doReturn(accounts).when(accountServiceDefault).convert(indexedAccounts);
when(accountSearchRepository.search("5")).thenReturn(indexedAccounts);
assertThat(accountServiceDefault.search("5")).isEqualTo(accounts);
}
}
@Nested
@DisplayName("convert method")
class ConvertTests {
@DisplayName("When called, should return the Accounts it gets from findByUserIdIn")
@Test
public void testReturnFromFind(@Mock AccountRepository accountRepository) {
List<Integer> integers = new ArrayList<>();
List<Account> accounts = new ArrayList<>();
List<IndexedAccount> indexedAccounts = new ArrayList<>();
when(accountRepository.findByUserIdIn(Mockito.any())).thenReturn(accounts);
assertThat(accountServiceDefault.convert(indexedAccounts)).isEqualTo(accounts);
}
}
}
package org.legrog.web.xyz;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
import org.legrog.entities.Account;
import org.legrog.entities.PublisherVersion;
import org.legrog.entities.SearchingException;
import org.legrog.test.MockitoExtension;
import org.legrog.web.account.AccountService;
import org.legrog.web.publisher.PublisherSearchView;
import org.legrog.web.publisher.PublisherService;
import org.mockito.Mock;
import org.mockito.Mockito;
import java.util.ArrayList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
/**
* Classe testant SearchView
*/
@RunWith(JUnitPlatform.class)
@ExtendWith(MockitoExtension.class)
@DisplayName("Searches for an indexed publisher")
public class SearchViewTest {
private SearchView searchView;
private PublisherService publisherService;
private AccountService accountService;
@BeforeEach
public void setUp(@Mock PublisherService publisherService, @Mock AccountService accountService) {
this.publisherService = publisherService;
this.accountService = accountService;
this.searchView = new SearchView(publisherService, accountService);
}
@Nested
@DisplayName("search method")
class SearchTests {
@Test
@DisplayName("when called, should delegate search to PublisherService and AccountService with same string")
public void searchUsesPublisherService(@Mock PublisherService publisherService, @Mock AccountService accountService) throws SearchingException{
searchView.setSearchString("1");
searchView.search();
Mockito.verify(publisherService).search("1");
Mockito.verify(accountService).search("1");
}
@Test
@DisplayName("when called, should return the answer it gets from PublisherService")
public void searchReturnsDataFromPublisherService(@Mock PublisherService publisherService) throws SearchingException {
List<PublisherVersion> publisherVersionList = new ArrayList<>();
when(publisherService.search("2")).thenReturn(publisherVersionList);
searchView.setSearchString("2");
searchView.search();
assertThat(searchView.getPublisherVersions()).isEqualTo(publisherVersionList);
}
@Test
@DisplayName("when called, should return the answer it gets from AccountService")
public void searchReturnsDataFromAccountService(@Mock AccountService accountService) throws SearchingException {
List<Account> publisherVersionList = new ArrayList<>();
when(accountService.search("3")).thenReturn(publisherVersionList);
searchView.setSearchString("3");
searchView.search();
assertThat(searchView.getPublisherVersions()).isEqualTo(publisherVersionList);
}
}
}