xhtml files in subdirectories
newlukai Oct 7, 2008 4:07 PMHi there,
I'm implementing an administration interface to manage several entities. For every database table I created two pages: the first on, say languages.xhtml displays all available languages in a datatable. The user can add, edit or delete a language. To add or edit a language another page should be displayed which shows the details of this language in a form. As soon as the user wants to edit a language, a conversation is started which ends if the user cancels or saves this language.
Nothing new here ;)
Now I tried to put those two files in a subdirectory since I want to separate the administration interface from the user interface. So I created a subdirectory admin and saved those two files there. Every JSF tag which references a file (like h:graphicImage and so on) now use such an URL: /path/file; it works. Then I read about the basePath and used it for my CSS.
Here are those two pages:
languages.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:s="http://jboss.com/products/seam/taglib" xmlns:a4j="http://richfaces.org/a4j" xmlns:rich="http://richfaces.org/rich" template="/template.xhtml"> <ui:define name="content"> <h:form id="languages"> <s:div styleClass="buttonBar"> <h:commandLink action="#{adminLanguage.add}" styleClass="button"> <h:graphicImage url="/gfx/icon_add.png" /> <h:outputText value="#{msgs.button_add}" /> </h:commandLink> </s:div> <rich:dataTable value="#{languages}" var="iterLanguage" id="table_languages" rows="20" styleClass="fullWidth" rowClasses="even, odd"> <rich:column sortBy="#{iterLanguage.token}"> <f:facet name="header"> <h:outputText value="#{msgs.label_language_token}" /> </f:facet> <h:outputText value="#{iterLanguage.token}" /> </rich:column> <rich:column sortBy="#{iterLanguage.isoToken}"> <f:facet name="header"> <h:outputText value="#{msgs.label_language_isoToken}" /> </f:facet> <h:outputText value="#{iterLanguage.iso_token}" /> </rich:column> <rich:column sortBy="#{iterLanguage.type}"> <f:facet name="header"> <h:outputText value="#{msgs.label_language_type}" /> </f:facet> <h:outputText value="#{iterLanguage.type}" /> </rich:column> <rich:column> <f:facet name="header"> <h:outputText value="#{msgs.header_actions}"/> </f:facet> <h:panelGroup> <h:commandLink action="#{adminLanguage.edit}" styleClass="button"> <h:graphicImage url="/gfx/icon_edit.png" /> <h:outputText value="#{msgs.button_edit}" /> </h:commandLink> <h:commandLink action="#{adminLanguage.delete}" styleClass="button"> <h:graphicImage url="/gfx/icon_delete.png" /> <h:outputText value="#{msgs.button_delete}" /> </h:commandLink> </h:panelGroup> </rich:column> </rich:dataTable> <rich:datascroller for="table_languages" /> </h:form> </ui:define> </ui:composition>
language.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:s="http://jboss.com/products/seam/taglib" xmlns:a4j="http://richfaces.org/a4j" xmlns:rich="http://richfaces.org/rich" template="/template.xhtml"> <ui:define name="content"> <h:form id="language"> <ui:include src="/includes/messages.xhtml" /> <h:panelGrid cellpadding="5" cellspacing="0" columns="2"> <h:outputText value="#{msgs.label_language_token}:" id="label_language_token" /> <s:decorate id="decorate_language_token" template="/includes/decorateField.xhtml"> <h:inputText value="#{language.token}" id="language_token"> <s:validate /> </h:inputText> </s:decorate> <h:outputText value="#{msgs.label_language_isoToken}:" id="label_language_isoToken" /> <s:decorate id="decorate_language_isoToken" template="/includes/decorateField.xhtml"> <h:inputText value="#{language.token}" id="language_isoToken"> <s:validate /> </h:inputText> </s:decorate> <h:outputText value="#{msgs.label_language_type}:" id="label_language_type" /> <s:decorate id="decorate_language_type" template="/includes/decorateField.xhtml"> <h:inputText value="#{language.type}" id="language_type"> <s:validate /> </h:inputText> </s:decorate> <h:outputText value="#{msgs.label_language_descr}:" id="label_language_descr" /> <h:inputTextarea value="#{language.descr}" rows="5" cols="50" id="language_descr" /> <h:commandLink action="#{adminLanguage.save}" styleClass="button"> <h:graphicImage url="/gfx/icon_save.png" /> <h:outputText value="#{msgs.button_save}" /> </h:commandLink> <h:commandLink action="cancel" immediate="true" styleClass="button"> <h:graphicImage url="/gfx/icon_cancel.png" /> <h:outputText value="#{msgs.button_cancel}" /> </h:commandLink> </h:panelGrid> </h:form> </ui:define> </ui:composition>
And the backing bean:
@Stateful @Name("adminLanguage") @Scope(ScopeType.SESSION) public class AdminLanguage implements IAdminAttribute, Serializable { private static final long serialVersionUID = 5816783546495530542L; @In private transient IAttributeService<Language> languageService; @In(required = false, scope = ScopeType.CONVERSATION) @Out(required = false, scope = ScopeType.CONVERSATION) private Language language; @DataModel private List<Language> languages; @DataModelSelection private Language selectedLanguage; @Factory("languages") public void getItems() { languages = languageService.select(); } @Begin(join = true) public String add() { language = new Language(); return "add"; } @Begin(join = true) public String edit() { language = selectedLanguage; return "edit"; } @End public String save() { try { if(languageService.select(language.getId()) == null) { languageService.insert(language); } else { languageService.update(language); } } catch (MissingPropertiesException e) { for(MissingProperty property : e.getMissingProperties()) { FacesUtil.addInfo(property.getControlID(), e.getResourceKey(), e.getResourceKey() + "_" + property.getControlID()); } return null; } catch (EntityAlreadyExistsException e) { return null; } catch (EntityDoesntExistException e) { return null; } getItems(); language = new Language(); return "saved"; } public String delete() { languageService.delete(selectedLanguage); languages.remove(selectedLanguage); selectedLanguage = null; return "deleted"; } @Remove @Destroy public void destroy() { } }
pages.xml
<page view-id="/admin/languages.xhtml"> <navigation> <rule if-outcome="add"> <redirect view-id="/admin/language.xhtml" /> </rule> <rule if-outcome="edit"> <redirect view-id="/admin/language.xhtml" /> </rule> </navigation> </page> <page view-id="/admin/language.xhtml"> <navigation> <rule if-outcome="cancel"> <end-conversation /> <redirect view-id="/admin/languages.xhtml" /> </rule> <rule if-outcome="saved"> <redirect view-id="/admin/languages.xhtml" /> </rule> </navigation> </page>
The problem now is that the conversation ends unexpectedly. The use case is as follows: The user clicks Add to add a new language. The language.xhtml shows with empty fields. The user enters a token (nothing else) and then clicks Save. Now the page should be redisplayed with some error messages and the already entered value.
The error messages are displayed correctly. But the fields are empty again, since the conversation ended.
And I don't know why it ended. As I told you before I have a several pairs of pages that are almost the same. And they work. The only difference is that they aren't stored in a subdirectory and that they refer to other database tables. But the structure is the same.
Thanks in advance
Newlukai