Jean-Francois Leveque

https://tree.taiga.io/project/jr-utily-grog-v3/us/44 Implementer l'historisation pour les éditeurs

https://tree.taiga.io/project/jr-utily-grog-v3/task/77 Présentation des versions d'un éditeur
https://tree.taiga.io/project/jr-utily-grog-v3/task/53 Validation d'une version
......@@ -15,10 +15,10 @@ public class Publisher /* extends org.roliste.data.DbLinkableEntity */ {
private int publisherId;
@OneToOne
private PublisherRevision activeRevision;
private PublisherRevision validatedRevision;
@OneToOne
private User activeValidator;
private User validator;
private Timestamp validationDateTime;
......@@ -33,12 +33,12 @@ public class Publisher /* extends org.roliste.data.DbLinkableEntity */ {
this.publisherId = publisherId;
}
public PublisherRevision getActiveRevision() {
return activeRevision;
public PublisherRevision getValidatedRevision() {
return validatedRevision;
}
public void setActiveRevision(PublisherRevision activeRevision) {
this.activeRevision = activeRevision;
public void setValidatedRevision(PublisherRevision activeRevision) {
this.validatedRevision = activeRevision;
}
public Set<PublisherRevision> getRevisions() {
......@@ -49,12 +49,12 @@ public class Publisher /* extends org.roliste.data.DbLinkableEntity */ {
this.revisions = revisions;
}
public User getActiveValidator() {
return activeValidator;
public User getValidator() {
return validator;
}
public void setActiveValidator(User activeValidator) {
this.activeValidator = activeValidator;
public void setValidator(User activeValidator) {
this.validator = activeValidator;
}
public Timestamp getValidationDateTime() {
......@@ -67,6 +67,6 @@ public class Publisher /* extends org.roliste.data.DbLinkableEntity */ {
@Override
public String toString() {
return "PUBLISHER_ID = " + publisherId + ", Active Revision = " + activeRevision + ", Validator = " + activeValidator + ", Validation DateTime = " + validationDateTime;
return "PUBLISHER_ID = " + publisherId + ", Active Revision = " + validatedRevision + ", Validator = " + validator + ", Validation DateTime = " + validationDateTime;
}
}
......
package org.legrog.web.publisher;
import org.legrog.web.xyz.SharedService;
import org.legrog.web.user.UserService;
import org.legrog.entities.Country;
import org.legrog.entities.Publisher;
import org.legrog.entities.PublisherRevision;
import org.legrog.entities.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
@Named
@RequestScoped
public class AddPublisherBean {
Logger logger = LoggerFactory.getLogger(getClass());
@Inject
private SharedService sharedService;
@Inject
private UserService userService;
@Inject
private PublisherService publisherService;
private String publisherName;
private String publisherStreetAddress;
private String publisherPostalCode;
private String publisherPostOfficeBoxNumber;
private String publisherAddressRegion;
private String publisherAddressLocality;
private Country publisherAddressCountry;
private String publisherTelephone;
private String publisherEmail;
private String publisherURL;
private boolean publisherActive;
private String publisherHistory;
private List<Country> availableCountries;
public String add() {
logger.info("add");
Publisher publisher = new Publisher();
PublisherRevision publisherRevision = new PublisherRevision();
HashSet<PublisherRevision> publisherRevisions = new HashSet<PublisherRevision>();
publisherRevisions.add(publisherRevision);
publisher.setRevisions(publisherRevisions);
logger.info(publisher.toString());
publisherRevision.setPublisher(publisher);
publisherRevision.setPublisherActive(publisherActive);
publisherRevision.setPublisherAddressCountry(publisherAddressCountry);
publisherRevision.setPublisherAddressLocality(publisherAddressLocality);
publisherRevision.setPublisherAddressRegion(publisherAddressRegion);
publisherRevision.setPublisherEmail(publisherEmail);
publisherRevision.setPublisherHistory(publisherHistory);
publisherRevision.setPublisherName(publisherName);
publisherRevision.setPublisherPostalCode(publisherPostalCode);
publisherRevision.setPublisherPostOfficeBoxNumber(publisherPostOfficeBoxNumber);
publisherRevision.setPublisherStreetAddress(publisherStreetAddress);
publisherRevision.setPublisherTelephone(publisherTelephone);
publisherRevision.setPublisherURL(publisherURL);
publisherRevision.setPublisherRevisionDatetime(new Timestamp(new Date().getTime()));
// TODO Remplacer l'astuce par une vraie récupération de l'utilisateur
List<User> users = userService.getAllUsers();
Random random = new Random();
User user = users.get(random.nextInt(users.size()));
// End TODO
publisherRevision.setPublisherRevisionAuthor(user);
logger.info(publisherRevision.toString());
// FIXME un seul appel logique à faire (pour la gestion du rollback)
publisherService.addPublisher(publisher);
publisherService.addPublisherRevision(publisherRevision);
// Test de récupération de l'Id
logger.info(publisherRevision.toString());
return "success";
}
@PostConstruct
public void init() {
availableCountries = sharedService.getAllCountries();
}
public String getPublisherName() {
return publisherName;
}
public void setPublisherName(String publisherName) {
this.publisherName = publisherName;
}
public String getPublisherStreetAddress() {
return publisherStreetAddress;
}
public void setPublisherStreetAddress(String publisherStreetAddress) {
this.publisherStreetAddress = publisherStreetAddress;
}
public String getPublisherPostalCode() {
return publisherPostalCode;
}
public void setPublisherPostalCode(String publisherPostalCode) {
this.publisherPostalCode = publisherPostalCode;
}
public String getPublisherPostOfficeBoxNumber() {
return publisherPostOfficeBoxNumber;
}
public void setPublisherPostOfficeBoxNumber(String publisherPostOfficeBoxNumber) {
this.publisherPostOfficeBoxNumber = publisherPostOfficeBoxNumber;
}
public String getPublisherAddressRegion() {
return publisherAddressRegion;
}
public void setPublisherAddressRegion(String publisherAddressRegion) {
this.publisherAddressRegion = publisherAddressRegion;
}
public String getPublisherAddressLocality() {
return publisherAddressLocality;
}
public void setPublisherAddressLocality(String publisherAddressLocality) {
this.publisherAddressLocality = publisherAddressLocality;
}
public Country getPublisherAddressCountry() {
return publisherAddressCountry;
}
public void setPublisherAddressCountry(Country publisherAddressCountry) {
this.publisherAddressCountry = publisherAddressCountry;
}
public String getPublisherTelephone() {
return publisherTelephone;
}
public void setPublisherTelephone(String publisherTelephone) {
this.publisherTelephone = publisherTelephone;
}
public String getPublisherEmail() {
return publisherEmail;
}
public void setPublisherEmail(String publisherEmail) {
this.publisherEmail = publisherEmail;
}
public String getPublisherURL() {
return publisherURL;
}
public void setPublisherURL(String publisherURL) {
this.publisherURL = publisherURL;
}
public boolean isPublisherActive() {
return publisherActive;
}
public void setPublisherActive(boolean publisherActive) {
this.publisherActive = publisherActive;
}
public String getPublisherHistory() {
return publisherHistory;
}
public void setPublisherHistory(String publisherHistory) {
this.publisherHistory = publisherHistory;
}
public List<Country> getAvailableCountries() {
return availableCountries;
}
public void setAvailableCountries(List<Country> availableCountries) {
this.availableCountries = availableCountries;
}
}
\ No newline at end of file
package org.legrog.web.publisher;
import org.legrog.entities.Publisher;
import org.legrog.entities.PublisherRevision;
import org.legrog.entities.User;
import org.legrog.web.user.UserService;
import org.legrog.web.xyz.SharedService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.sql.Timestamp;
import java.util.*;
@Named
@RequestScoped
......@@ -18,7 +22,11 @@ public class ListPublisherRevisionsBean {
Logger logger = LoggerFactory.getLogger(getClass());
@Inject
PublisherService publisherRevisionService;
PublisherService publisherService;
@Inject
SharedService sharedService;
@Inject
UserService userService;
private Integer publisherId;
......@@ -29,8 +37,26 @@ public class ListPublisherRevisionsBean {
public List<PublisherRevision> getPublisherRevisions() {
return publisherRevisions;
}
/*
*/
public void validate() {
logger.debug("validate");
Publisher publisher = publisherService.getPublisher(publisherId);
logger.debug("publisher (pre-validate) = {}", publisher);
FacesContext facesContext = FacesContext.getCurrentInstance();
Map<String,String> params =
facesContext.getExternalContext().getRequestParameterMap();
Integer publisherRevisionId = new Integer(params.get("publisherRevisionId"));
publisher.setValidatedRevision(publisherService.getPublisherRevision(publisherRevisionId));
User user = sharedService.getCurrentUser();
publisher.setValidator(user);
publisher.setValidationDateTime(new Timestamp(new Date().getTime()));
publisherService.updatePublisher(publisher);
// TODO : comprendre pourquoi ceci est nécessaire
publisherRevisions = publisherService.getAllPublisherRevisions();
publisherRevisions = filter();
logger.debug("publisher (post-validate) = {}", publisher);
}
@PostConstruct
public void init() {
publisherRevisions = publisherRevisionService.getAllPublisherRevisions();
......@@ -38,22 +64,24 @@ public class ListPublisherRevisionsBean {
}
List<PublisherRevision> filter() {
ArrayList<PublisherRevision> filteredPublisherRevisions= new ArrayList<PublisherRevision>();
for(PublisherRevision publisherRevision : publisherRevisions) {
if (publisherRevision.getPublisher().getPublisherId() == publisherId) {
filteredPublisherRevisions.add(publisherRevision);
}
}
return filteredPublisherRevisions;
}
public void setView() {
logger.info("setView");
logger.info("publisherId = " + publisherId);
viewAll = ( publisherId == null ) ;
if (!viewAll) {
logger.info("!viewAll");
ArrayList<PublisherRevision> filteredPublisherRevisions= new ArrayList<PublisherRevision>();
Iterator<PublisherRevision> publisherRevisionIterator = publisherRevisions.iterator();
for(PublisherRevision publisherRevision : publisherRevisions) {
if (publisherRevision.getPublisher().getPublisherId() == publisherId.intValue()) {
filteredPublisherRevisions.add(publisherRevision);
}
}
publisherRevisions = filteredPublisherRevisions;
publisherRevisions = filter();
}
}
......
......@@ -26,12 +26,11 @@ public class PublisherRevisionView implements Serializable {
Logger logger = LoggerFactory.getLogger(getClass());
@Inject
private PublisherService publisherService;
PublisherService publisherService;
@Inject
UserService userService;
@Inject
private SharedService sharedService;
SharedService sharedService;
private boolean editMode;
private boolean newPublisher;
......@@ -99,11 +98,8 @@ public class PublisherRevisionView implements Serializable {
publisherRevision.setPublisherRevisionDatetime(new Timestamp(new Date().getTime()));
// TODO Remplacer l'astuce par une vraie récupération de l'utilisateur
List<User> users = userService.getAllUsers();
Random random = new Random();
User user = users.get(random.nextInt(users.size()));
// End TODO
User user = sharedService.getCurrentUser();
publisherRevision.setPublisherRevisionAuthor(user);
}
......
......@@ -9,6 +9,8 @@ public interface PublisherService {
void addPublisher(Publisher publisher);
void updatePublisher(Publisher publisher);
void addRevisionToPublisher(Publisher publisher, PublisherRevision publisherRevision);
List<Publisher> getAllPublishers();
......
......@@ -35,6 +35,10 @@ public class PublisherServiceSpring implements PublisherService {
publisherRepository.save(publisher);
}
public void updatePublisher(Publisher publisher) {
publisherRepository.save(publisher);
}
public void addRevisionToPublisher(Publisher publisher, PublisherRevision publisherRevision) {
Set<PublisherRevision> publisherRevisionSet = publisher.getRevisions();
publisherRevisionSet.add(publisherRevision);
......
<?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">
<f:view>
<h:form>
<h:commandLink action="home">
<h:outputText value="Menu principal"/>
</h:commandLink>
<h:panelGrid columns="2">
<h:outputText value='publisherName'/>
<h:inputText value='#{addPublisherBean.publisherName}'/>
<h:outputText value='publisherStreetAddress'/>
<h:inputText value='#{addPublisherBean.publisherStreetAddress}'/>
<h:outputText value='publisherPostalCode'/>
<h:inputText value='#{addPublisherBean.publisherPostalCode}'/>
<h:outputText value='publisherPostOfficeBoxNumber'/>
<h:inputText value='#{addPublisherBean.publisherPostOfficeBoxNumber}'/>
<h:outputText value='publisherAddressRegion'/>
<h:inputText value='#{addPublisherBean.publisherAddressRegion}'/>
<h:outputText value='publisherAddressLocality'/>
<h:inputText value='#{addPublisherBean.publisherAddressLocality}'/>
<h:outputText value='publisherAddressCountry'/>
<h:selectOneMenu value="#{addPublisherBean.publisherAddressCountry}" converter="omnifaces.SelectItemsConverter">
<f:selectItems value="#{addPublisherBean.availableCountries}" var="country" itemLabel="#{country.countryName}"/>
</h:selectOneMenu>
<h:outputText value='publisherTelephone'/>
<h:inputText value='#{addPublisherBean.publisherTelephone}'/>
<h:outputText value='publisherEmail'/>
<h:inputText value='#{addPublisherBean.publisherEmail}'/>
<h:outputText value='publisherURL'/>
<h:inputText value='#{addPublisherBean.publisherURL}'/>
<h:outputText value='publisherActive'/>
<h:selectBooleanCheckbox value="#{addPublisherBean.publisherActive}"/>
<h:outputText value='publisherHistory'/>
<h:inputTextarea value='#{addPublisherBean.publisherHistory}'/>
<h:outputText value='Add'/>
<h:commandButton action="#{addPublisherBean.add}" value="Add"/>
</h:panelGrid>
</h:form>
</f:view>
</html>
......@@ -3,6 +3,7 @@
"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:jsf="http://xmlns.jcp.org/jsf"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<f:metadata>
......@@ -13,21 +14,26 @@
<h:form>
<ul>
<li>
<h:link outcome="/index">
<h:outputText value="Menu principal"/>
</h:link>
<a jsf:outcome="/index">Menu principal</a>
</li>
<li>
<h:link outcome="/publisherRevision">
<h:outputText value="Ajouter un éditeur"/>
</h:link>
<a jsf:outcome="publisherRevision">Ajouter un éditeur</a>
</li>
</ul>
</h:form>
<h:link rendered="#{not listPublisherRevisionsView.viewAll}" outcome="/listPublisherRevisions.xhtml">Voir tous les éditeurs</h:link>
<h:link rendered="#{not listPublisherRevisionsView.viewAll}" outcome="listPublisherRevisions">Voir tous les éditeurs</h:link>
<ui:remove>
<h:outputText rendered="#{not listPublisherRevisionsView.viewAll}">Révision valide #{listPublisherRevisionsView.publisherRevisions.get(0).publisher.validatedRevision.publisherRevisionId}</h:outputText>
</ui:remove>
<h:outputText rendered="#{listPublisherRevisionsView.publisherRevisions.isEmpty()}">Liste des révisions est vide</h:outputText>
<h:dataTable value="#{listPublisherRevisionsView.publisherRevisions}" var="revision">
<ui:remove>
<h:column>
<f:facet name="header">Id</f:facet>
#{revision.publisherRevisionId}
</h:column>
</ui:remove>
<h:column>
<f:facet name="header">Visualiser ou Modifier</f:facet>
<h:link outcome="view">Visualiser ou Modifier Version
......@@ -36,14 +42,21 @@
</h:column>
<h:column rendered="#{listPublisherRevisionsView.viewAll}">
<f:facet name="header">Editeur</f:facet>
<h:link outcome="/listPublisherRevisions">
#{revision.publisher.publisherId}
<h:link outcome="listPublisherRevisions">
Visualiser ou valider version éditeur
<f:param name="publisherId" value="#{revision.publisher.publisherId}"/>
</h:link>
</h:column>
<h:column rendered="#{not listPublisherRevisionsView.viewAll}">
<h:column>
<f:facet name="header">Valide</f:facet>
#{revision.publisherRevisionId == revision.publisher.activeRevision}
<h:outputText rendered="#{revision.publisherRevisionId == revision.publisher.validatedRevision.publisherRevisionId}">Validé</h:outputText>
<h:outputText rendered="#{listPublisherRevisionsView.viewAll and revision.publisherRevisionId != revision.publisher.validatedRevision.publisherRevisionId}">Non validé</h:outputText>
<!-- https://www.mkyong.com/jsf2/4-ways-to-pass-parameter-from-jsf-page-to-backing-bean/ f:param, problème avec Method expression -->
<h:form rendered="#{not listPublisherRevisionsView.viewAll and revision.publisherRevisionId != revision.publisher.validatedRevision.publisherRevisionId}">
<h:commandButton action="#{listPublisherRevisionsView.validate()}" value="Valider">
<f:param name="publisherRevisionId" value="#{revision.publisherRevisionId}"/>
</h:commandButton>
</h:form>
</h:column>
<h:column>
<f:facet name="header">Name</f:facet>
......
......@@ -18,14 +18,10 @@
<h:form>
<ul>
<li>
<h:link outcome="/index">
<h:outputText value="Menu principal"/>
</h:link>
<a jsf:outcome="/index">Menu principal</a>
</li>
<li>
<h:link outcome="/listPublisherRevisions">
<h:outputText value="Versions des éditeurs"/>
</h:link>
<a jsf:outcome="listPublisherRevisions">Versions des éditeurs</a>
</li>
</ul>
......
package org.legrog.web.xyz;
import org.legrog.entities.Country;
import org.legrog.entities.DisplayNameMask;
import org.legrog.entities.UserProperty;
import org.legrog.entities.UserRole;
import org.legrog.entities.*;
import java.util.List;
......@@ -19,4 +16,5 @@ public interface SharedService {
List<UserProperty> getAvailableUserProperties();
User getCurrentUser();
}
\ No newline at end of file
......
package org.legrog.web.xyz;
import org.legrog.entities.*;
import org.legrog.web.user.UserService;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
import javax.ejb.Stateless;
import javax.inject.Inject;
import java.util.List;
import java.util.Random;
import java.util.Vector;
@Stateless
......@@ -18,6 +20,8 @@ public class SharedServiceSpring implements SharedService {
UserRoleRepository userRoleRepository;
@Inject
UserPropertyRepository userPropertyRepository;
@Inject
UserService userService;
private List<DisplayNameMask> allDisplayNameMasks;
......@@ -47,4 +51,13 @@ public class SharedServiceSpring implements SharedService {
}
public List<UserProperty> getAvailableUserProperties() { return userPropertyRepository.findAll(); }
public User getCurrentUser() {
// TODO Remplacer l'astuce par une vraie récupération de l'utilisateur
List<User> users = userService.getAllUsers();
Random random = new Random();
User user = users.get(random.nextInt(users.size()));
// End TODO
return user;
}
}
......
......@@ -31,9 +31,9 @@ INSERT INTO PublisherRevision (publisher_PUBLISHER_ID, publisherName, publisherS
(3, 'La Vouivre', NULL, NULL, NULL, NULL, NULL, 1, NULL, NULL, 'la-vouivre.com', TRUE, 'Ouvert…', 1, {ts '2000-01-01 00:02:33'}),
(3, 'La Vouivre', NULL, NULL, NULL, NULL, NULL, 1, NULL, NULL, 'la-vouivre.com', FALSE, '… en 2015', 2, {ts '2015-01-01 00:05:22'}),
(4, 'Archmagus', NULL, NULL, NULL, NULL, NULL, 1, NULL, NULL, 'archimage.net', TRUE, 'Ouvert…', 4, {ts '2016-10-14 10:56:03'});
UPDATE Publisher SET (activeRevision_PUBLISHER_REVISION_ID, activeValidator_USER_ID, validationDateTime) VALUES (1, 2, {ts '2000-05-08 12:00:28'}) WHERE PUBLISHER_ID = 1;
UPDATE Publisher SET (activeRevision_PUBLISHER_REVISION_ID, activeValidator_USER_ID, validationDateTime) VALUES (2, 1, TIMESTAMP '2010-06-20 14:27:35') WHERE PUBLISHER_ID = 2;
UPDATE Publisher SET (activeRevision_PUBLISHER_REVISION_ID, activeValidator_USER_ID, validationDateTime) VALUES (4, 1, TIMESTAMP '2015-01-01 16:18:17') WHERE PUBLISHER_ID = 3;
UPDATE Publisher SET validatedRevision_PUBLISHER_REVISION_ID = 1, validator_USER_ID = 2, validationDateTime = {ts '2000-05-08 12:00:28'} WHERE PUBLISHER_ID = 1;
UPDATE Publisher SET validatedRevision_PUBLISHER_REVISION_ID = 2, validator_USER_ID = 1, validationDateTime = {ts '2010-06-20 14:27:35'} WHERE PUBLISHER_ID = 2;
UPDATE Publisher SET validatedRevision_PUBLISHER_REVISION_ID = 4, validator_USER_ID = 1, validationDateTime = {ts '2015-01-01 16:18:17'} WHERE PUBLISHER_ID = 3;
INSERT INTO UserRole VALUES (1, 'VISITEUR', TRUE);
INSERT INTO UserRole VALUES (2, 'RECRUE', TRUE);
......
......@@ -41,13 +41,6 @@
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/publisher/addPublisher.xhtml</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/publisher/listPublisherRevisions.xhtml</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/xyz/addCountry.xhtml</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
......
......@@ -3,52 +3,17 @@
"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:jsf="http://xmlns.jcp.org/jsf"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<body>
<h:form>
<ul>
<li>
<h:commandLink action="addBook">
<h:outputText value="Add book"/>
</h:commandLink>
<a jsf:outcome="publisher/publisherRevision">Ajouter un éditeur</a>
</li>
<li>
<h:commandLink action="listBooks">
<h:outputText value="List books"/>
</h:commandLink>
</li>
<li>
<h:commandLink action="addCountry">
<h:outputText value="Add country"/>
</h:commandLink>
</li>
<li>
<h:commandLink action="listCountries">
<h:outputText value="List countries"/>
</h:commandLink>
</li>
<li>
<h:commandLink action="addUser">
<h:outputText value="Add user"/>
</h:commandLink>
</li>
<li>
<h:commandLink action="listUsers">
<h:outputText value="List users"/>
</h:commandLink>
</li>
<li>
<h:link outcome="/publisherRevision">
<h:outputText value="Ajouter un éditeur"/>
</h:link>
</li>
<li>
<h:link outcome="/listPublisherRevisions">
<h:outputText value="Liste des versions des éditeurs"/>
</h:link>
<a jsf:outcome="publisher/listPublisherRevisions">Liste des versions des éditeurs</a>
</li>
</ul>
</h:form>
</body>
</html>
......