This question already has answers here:
h:commandButton/h:commandLink does not work on first click, works only on second click
(2 answers)
have to press command button twice
(5 answers)
Closed 7 years ago.
I have a bunch of html files on my server that get loaded into my JSF view when a menu button is clicked.
Many of those files have an action button in them, like so:
<?xml version="1.0" encoding="utf-8"?>
<div xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns="http://www.w3.org/1999/xhtml" id="d10e780" class="content">
<h:form id="publicationForm">
<h:panelGrid columns="2" width="45%">
<h:commandButton id="addToCart" value="Add to publishing Cart" actionListener="#{cartController.addToCart('d10e780.html')}">
<f:ajax execute="#form" render="#none"/>
</h:commandButton>
<h:commandButton id="viewCart" value="View publishing cart" action="#{cartController.viewCart()}"/>
</h:panelGrid>
</h:form>
<div id="d10e780" class="content">
<ul class="level_two">
<li class="level_two">SomeStuff</li>
</ul>
</div>
</div>
when the button is clicked, the name of the file is added to that shopping cart for subsequent publication.
The backing beans look like this:
package controllers;
import java.io.IOException;
import java.io.Serializable;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import org.xml.sax.SAXException;
import utils.PDFCreator;
#Named
#SessionScoped
public class Publication implements Serializable {
private static final long serialVersionUID = -2404153211000142338L;
private List<String> documents = new ArrayList<>();
private Map<Long, Boolean> selected = new HashMap<Long, Boolean>();
public Publication() {
}
public Map<Long, Boolean> getSelected() {
return selected;
}
public void setSelected(Map<Long, Boolean> selected) {
this.selected = selected;
}
public List<String> getDocuments() {
return documents;
}
public void setDocuments(List<String> documents) {
this.documents = documents;
}
public void addDocument(String dokumentId) {
if (!documents.contains(dokumentId)) {
documents.add(dokumentId);
}
}
public void publishPDF() {
List<String> checkedItems = new ArrayList<>();
for (String doc : documents) {
if (selected.get(doc)) {
checkedItems.add(doc);
System.out.println("BEING PUBLISHED " + doc);
}
}
selected.clear();
for (String item : checkedItems) {
try {
PDFCreator.makePDF(Paths.get(item));
} catch (SAXException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
and
package controllers;
import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;
import views.Pages;
#SessionScoped
#Named
public class CartController implements Serializable {
#Inject
private Publication publication;
private static final long serialVersionUID = 7768738867325966926L;
public CartController() {
}
public void addToCart(String dokumentId) {
System.out.println("CARTCONTROLLER: ADDTOCART: " + dokumentId);
if (getPublication() == null) {
publication = new Publication();
getPublication().addDocument(dokumentId);
} else {
getPublication().addDocument(dokumentId);
}
}
public String viewCart() {
return Pages.PUBLICATION + "?faces-redirect=true";
}
public void editItem(String title) {
}
public void updateCart(String title) {
}
public Publication getPublication() {
return publication;
}
public void setPublication(Publication publication) {
this.publication = publication;
}
}
Now here's the problem: I have to click the button twice for the file name to be added to the list. Why is that? I'd like, of course, to just click the button once and have it work.
Thanks for help and tips!!
Related
I'm trying to understand how to program composite components, and have followed the great example by balusc, and others, but I'm missing something.
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:cc="http://java.sun.com/jsf/composite">
<cc:interface componentType="simpleComponent">
<cc:attribute name="value" required="true" type="example.LanguageDefinition"/>
<cc:attribute name="possibilities" default="de_DE" type="java.lang.String"/>
</cc:interface>
<cc:implementation>
<p:selectOneMenu binding="#{cc.inputComponent}" converter="omnifaces.SelectItemsConverter" var="l"
value="#{cc.attrs.value}">
<p:ajax update="#form"/>
<f:selectItems value="#{cc.languages}" var="l" itemLabel="#{l.label}"
itemValue="#{l}" />
<p:column>#{l.label}</p:column>
<p:column>
<p:graphicImage name="#{l.imgPath}" />
</p:column>
</p:selectOneMenu>
</cc:implementation>
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.faces.component.FacesComponent;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIInput;
import javax.faces.component.UINamingContainer;
import javax.faces.context.FacesContext;
import example.LanguageDefinition;
#FacesComponent("simpleComponent")
public class SimpleComponent extends UIInput implements NamingContainer {
private UIInput inputComponent;
public UIInput getInputComponent() {
return inputComponent;
}
public void setInputComponent(UIInput inputComponent) {
this.inputComponent = inputComponent;
}
#Override
public Object getSubmittedValue() {
return inputComponent.getSubmittedValue();
}
#Override
protected Object getConvertedValue(FacesContext context, Object newSubmittedValue) {
return (String) newSubmittedValue;
}
#Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
#Override
public void encodeBegin(FacesContext context) throws IOException {
String possibilities = getAttributeValue("possibilities", "en_US");
// In theory, build based on incoming possibilities, now hard code
List<LanguageDefinition> languages = new ArrayList<LanguageDefinition>();
languages.add(new LanguageDefinition("pt_PT",
"images/flags/PT.gif", "Português (Portugal)"));
languages.add(new LanguageDefinition("cs_CZ",
"images/flags/CZ.gif", "Czech (Czech Republic)"));
getStateHelper().put("languages", languages);
super.encodeBegin(context);
}
#SuppressWarnings("unchecked")
public List<LanguageDefinition> getLanguages() {
return (List<LanguageDefinition>) getStateHelper().get("languages");
}
/**
* Return specified attribute value or otherwise the specified default if it's null.
*/
#SuppressWarnings("unchecked")
private <T> T getAttributeValue(String key, T defaultValue) {
T value = (T) getAttributes().get(key);
return (value != null) ? value : defaultValue;
}
}
This isn't working calling like this:
<ex:simpleComponent value="#{compBean.selected}"/>
Everything renders fine, but the submitted value is never passed back to my "compBean". However, if I set the selectItems "languages" in any other way other than doing it in encodeBegin it works... as a member variable with getters and setters, or using this code:
<c:set target="#{cc}" property="possibilities" value="#{cc.attrs.possibilities}"/>
In combination with this much simpler class:
import java.util.ArrayList;
import java.util.List;
import javax.faces.component.FacesComponent;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIInput;
import javax.faces.component.UINamingContainer;
import example.LanguageDefinition;
#FacesComponent("simpleComponent")
public class SimpleComponent extends UIInput implements NamingContainer {
#Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
public void setPossibilities(String possibilities) {
if (getStateHelper().get("possibilities") == null) {
List<LanguageDefinition> languages = new ArrayList<LanguageDefinition>();
languages.add(new LanguageDefinition("pt_PT",
"images/flags/PT.gif", "Português (Portugal)"));
languages.add(new LanguageDefinition("cs_CZ",
"images/flags/CZ.gif", "Czech (Czech Republic)"));
getStateHelper().put("languages", languages);
getStateHelper().put("possibilities", possibilities);
}
}
public String getPossibilities() {
return (String) getStateHelper().get("possibilities");
}
#SuppressWarnings("unchecked")
public List<LanguageDefinition> getLanguages() {
return (List<LanguageDefinition>) getStateHelper().get("languages");
}
}
But, it doesn't seem right to do it this way (wasn't the way balusc did it), so I'm just trying to understand. Which way is better? Assuming the first, why is mine not working?
Thanks!
So... the reason this wasn't working was because I forgot to implement Serializable on my custom drop down list value object "example.LanguageDefinition".
Hopefully the next person won't have to look for this needle in the haystack as long as I did :)
i' m developing my first jsf2 richfaces application , and now i am faced with the following problem :
i have the following menù
<rich:panelMenu >
<rich:panelMenuGroup >
<rich:panelMenuItem label="Users" name="Users " />
<rich:panelMenuItem label="Orders" name="Orders" />
</rich:panelMenuGroup>
</rich:panelMenu>
I want that when click on the panelMenuItem is created a new tab and within of this new tab must insert a table that contains all users of the my application
i saw a few example of this type
<rich:tabPanel switchType="client" id="tabPanel">
<c:forEach items="#{handlerTab.tabsName}" var="tabName">
<rich:tab name = ... >
</rich:tab>
</c:foreach>
but don't know as insert a table in my new tab
how can i do?
tanks for your reply, but i don't want declare all tabs in the view , i want add and remove tab dynamically , now i have managed to do this
<rich:panelMenu >
<rich:panelMenuGroup >
<rich:panelMenuItem label="Users" name="Users" action="#{tabsBean.createTabs()}" render="tabs" />
<rich:panelMenuItem label="Orders" name="Orders" action="#{tabsBean.createTabs()}" render="tabs" />
</rich:panelMenuGroup>
<h:panelGrid id="tabs" binding="#{tabsBean.panelGrid}"/>
then i have a bean that manage the tabs
#ManagedBean
#SessionScoped
public class TabsBean {
private HtmlPanelGrid panelGrid;
private Integer numOfTabs;
#PostConstruct
public void init(){numOfTabs=1;}
public Integer getNumOfTabs() {
return numOfTabs;
}
public void setNumOfTabs(Integer numOfTabs) {
this.numOfTabs = numOfTabs;
}
public TabsBean() {
}
public HtmlPanelGrid getPanelGrid() {
return panelGrid;
}
public void setPanelGrid(HtmlPanelGrid panelGrid) {
this.panelGrid = panelGrid;
}
public void createTabs (){
FacesContext context = FacesContext.getCurrentInstance();
Application application = context.getApplication();
UITabPanel tabPanel = (UITabPanel)application.createComponent(UITabPanel.COMPONENT_TYPE);
tabPanel.setSwitchType(SwitchType.ajax);
for (int i=0; i<numOfTabs; i++){
UITab tab = new UITab();
tab = (UITab)application.createComponent(UITab.COMPONENT_TYPE);
tab.setName("User Count "+i);
tabPanel.getChildren().add(tab);
}
numOfTabs++;
panelGrid.getChildren().clear();
panelGrid.getChildren().add(tabPanel);
}
}
now my problem is that i must add of components a this tabs (datatable that contains all user , form for insert a user and other)
how can i do?
If you want the menu to open tabs with specific content it's better if you pre-create the tab and hide it, showing it (rendering) on request. To create the Users do the following:
Create a User class (if you don't have one)
public class User {
private String name;
private String country;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
Create a UserTab managed bean
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class UserTab implements Serializable {
private List<User> users;
private boolean rendered;
public UserTab() {
//Initialize list
users = new ArrayList();
//Initialize rendered attribute
rendered = false;
//Replace this for your User data retrieving method
createDummyUsers();
}
private void createDummyUsers() {
User user = new User();
user.setName("John Doe");
user.setCountry("USA");
users.add(user);
user = new User();
user.setName("Bill Doe");
user.setCountry("Canada");
users.add(user);
user = new User();
user.setName("Winston Doe");
user.setCountry("England");
users.add(user);
}
public void showTab() {
rendered = true;
}
public void hideTab() {
rendered = false;
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
public boolean isRendered() {
return rendered;
}
public void setRendered(boolean rendered) {
this.rendered = rendered;
}
}
Create a tab handler:
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class TabHandler implements Serializable {
private String activeTab;
public TabHandler() {
activeTab = "none";
}
public String getActiveTab() {
return activeTab;
}
public void setActiveTab(String activeTab) {
this.activeTab = activeTab;
}
}
Create the view
<h:body>
<h:form>
<rich:panelMenu >
<rich:panelMenuGroup >
<rich:panelMenuItem label="Users" name="Users"
actionListener="#{userTab.showTab()}">
<f:ajax event="select"
execute="#this"
render="tabPanel"
listener="#{tabHandler.setActiveTab('usersTab')}"/>
</rich:panelMenuItem>
<rich:panelMenuItem label="Orders" name="Orders" />
</rich:panelMenuGroup>
</rich:panelMenu>
<rich:tabPanel id="tabPanel"
switchType="client"
activeItem="#{tabHandler.activeTab}">
<rich:tab id="mainTab">
</rich:tab>
<rich:tab id="usersTab"
rendered="#{userTab.rendered}">
<f:facet name="header">
<h:outputLabel value="Users"/>
<h:commandLink value=" X" actionListener="#{userTab.hideTab()}"/>
</f:facet>
<rich:dataTable value="#{userTab.users}"
var="user">
<rich:column>
#{user.name}
</rich:column>
<rich:column>
#{user.country}
</rich:column>
</rich:dataTable>
</rich:tab>
</rich:tabPanel>
</h:form>
</h:body>
Do the same steps and add the required tags for the Order class.
See:
RichFaces dynamic TabPanel
c:forEach is not an option if you want to add the tabs by click.
What you want is to add components dynamically:
How to dynamically add JSF components
Dynamically added input field in ui:repeat is not processed during form submit
How to Dynamically adding fields in JSF?
I want to use the arquillian warp test framework for a JSF project I am developing. I understand that I need to use the CDI annotations instead of the JSF ones to get this to work. I am using #ViewScoped beans so I have included seam-faces in my project to deal with this (i am running on JBoss 7). I have modified my beans to use #Named and where I was using #PostConstruct I have put this into the constructor which all seems to be okay.
When I access a view with a selectOneMenu it never has any list items. Here is the code form the view and the bean.
View:
<h:selectOneMenu value="#{ngoBean.ngo.country}" >
<f:selectItems value="#{ngoBean.countryValues}" />
</h:selectOneMenu>
Bean:
import com.a.Facade;
import com.a.CountryEnum;
import com.a.GoverningBody;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.bean.ViewScoped;
import javax.faces.model.SelectItem;
import javax.inject.Named;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* Created with IntelliJ IDEA.
*/
#Named("ngoBean")
#ViewScoped
public class NgoBean implements Serializable {
private GoverningBody ngo = new GoverningBody();
private List<GoverningBody> ngoList;
private boolean edit;
private List<SelectItem> countryValues;
#EJB(beanName = "NgoFacadeImpl")
private Facade<GoverningBody> ngoController;
public NgoBean(){
}
#PostConstruct
public void init(){
//TODO this is a bad way of loading db data i should change it
ngoList = ngoController.findAll();
countryValues = initCountryValues();
}
public void add(){
ngoList.add(ngoController.save(ngo));
//reset the variable
ngo = new GoverningBody();
}
public void edit(GoverningBody item) {
this.ngo = item;
edit = true;
}
public void save() {
ngo = ngoController.update(ngo);
edit = false;
}
public void delete(GoverningBody item) {
ngoController.delete(item);
ngoList.remove(item);
}
public List<GoverningBody> getNgoList() {
return ngoList;
}
public GoverningBody getNgo() {
return ngo;
}
public boolean isEdit() {
return edit;
}
public List<SelectItem> getCountryValues() {
return countryValues;
}
public void setCountryValues(List<SelectItem> countryValues) {
this.countryValues = countryValues;
}
public List<SelectItem> initCountryValues() {
List<SelectItem> items = new ArrayList<>(CountryEnum.values().length);
int i = 0;
for(CountryEnum g: CountryEnum.values()) {
items.add(new SelectItem(g, g.getName()));
}
System.out.println("items = " + items);
return items;
}
}
I tried annotating the method with #Factory("countryValues") but this didn't seem to help.
This problem was unrelated to the symptom. The root cause of the problem was an incorrectly located beans.xml this should have be in the WEB-INF directory of the war not the META-INF directory of the ear.
I also changed the seam-faces dependency to use apache CODI, this is not necessary but this uses #ViewAccessScoped instead of #ViewScoped the different name is less ambiguous I think.
i am new to the icefaces components, want to use ice:selectInputText component same as in showcase [ice:selectInputText showcase][1] but the default css as it is shown in showcase doesnot functions same for me. i get dropdown list when something entered but the values shown as transparent rows and nothing highlited when move mouse on any item.
Can anyone guide where can be the problem:
here's my code:test.xhtml
<html 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:ice="http://www.icesoft.com/icefaces/component">
<h:head></h:head>
<h:body>
<h:form>
<h:panelGroup>
<h:outputLabel value="Enter your name(autocomplete) :"></h:outputLabel>
<ice:selectInputText id="heloo"
value="#{helloBean.selectedItem}"
rows="10" width="152" valueChangeListener="#{helloBean.ValueChangeL}" actionListener="#{helloBean.ActionL}">
<f:selectItems value="#{helloBean.itemList}"></f:selectItems>
</ice:selectInputText>
</h:panelGroup>
</h:form>
</h:body>
</html>
Managed bean class:
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.SessionScoped;
import javax.faces.event.ActionEvent;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;
import com.icesoft.faces.component.selectinputtext.SelectInputText;
#ManagedBean( name= "helloBean")
#SessionScoped
public class HelloBean {
private String selectedItem;
private Integer seelectedId;
private List<SelectItem> itemList=new ArrayList<SelectItem>();
public String getSelectedItem() {
return selectedItem;
}
public void setSelectedItem(String selectedItem) {
this.selectedItem = selectedItem;
}
public Integer getSeelectedId() {
return seelectedId;
}
public void setSeelectedId(Integer seelectedId) {
this.seelectedId = seelectedId;
}
public List<SelectItem> getItemList() {
return itemList;
}
public void setItemList(List<SelectItem> itemList) {
this.itemList = itemList;
}
public void ValueChangeL(ValueChangeEvent event)
{
String query=(String) event.getNewValue();
System.out.println("query is "+query);
SelectItem item1=new SelectItem();
SelectItem item2=new SelectItem();
SelectItem item3=new SelectItem();
item1.setLabel("abc");
item1.setValue(1);
item2.setLabel("bbc");
item2.setValue(2);
item3.setLabel("aaa");
item3.setValue(3);
itemList.add(item1);
itemList.add(item2);
itemList.add(item3);
}
public void ActionL(ActionEvent event)
{
System.out.println("HELLO IN LISTENER of SELECTINPUTTEXT"+event.getSource().toString());
System.out.println("HELLO IN LISTENER of PHASEID IS"+event.getPhaseId());
if ( event != null && event.getSource() instanceof SelectInputText )
{
SelectInputText comp_ = (SelectInputText) event.getSource();
SelectItem selectItem_ = comp_.getSelectedItem();//critical line
System.out.println("selected id"+selectItem_.getValue());
seelectedId=(Integer)selectItem_.getValue();
}
}
public String submitFunc()
{
System.out.println("checking selected item: "+ selectedItem );
System.out.println("checking selected id: "+ seelectedId );
return "success";
}
}
There is more to the showcase than that is shown on the page. There are some stylesheets that are included on that page.
If you want to have the same kind of styling. Refer to their code base here and include those as well.
I'm using JBoss6.1.Final, JSF 2.0 (Mojarra), Weld CDI, MyFaces CODI 1.0.5 (for view-access-scoped)
I'm using something like the Gateway Pattern from Real World Java EE Patterns Rethinking Best Practices (unfortunately I don't have it with me, so I may have screwed something up here). Basically, the application allows a user to go into "edit mode" and edit a List of people (create, edit, remove) maintained in a #ViewAccessScoped backing bean with an extended persistence context and then click a "save" command link that flushes all their changes to the database. At first I was having a problem with ViewExpiredExceptions (if the browser was idle past the session-timeout period and then further requests are performed), but I added some jQuery to make a get request to a servlet that keeps the session alive (called 10 seconds before session-timeout). This seems to be working but now I have another problem, the backing bean is also a SFSB and after some idle time, it is being removed resulting in the following error message being logged (and all ajax rendered data disappears) when I attempt to perform more edits ...
13:06:22,063 SEVERE [javax.enterprise.resource.webcontainer.jsf.context] javax.el.ELException: /index.xhtml #27,81 rendered="#{!conversationBean.editMode}": javax.ejb.NoSuchEJBException: Could not find stateful bean: 43h1h2f-9c7qkb-h34t0f34-1-h34teo9p-de
Any ideas on how I could prevent SFSB removal or at least handle it more gracefully?
Here's my backing bean:
package com.ray.named;
import java.io.Serializable;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.ejb.EJBTransactionRolledbackException;
import javax.ejb.Stateful;
import javax.ejb.TransactionAttribute;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import org.apache.myfaces.extensions.cdi.core.api.scope.conversation.ViewAccessScoped;
import com.ray.model.Person;
#Named
#Stateful
#ViewAccessScoped
#TransactionAttribute(javax.ejb.TransactionAttributeType.NEVER)
public class ConversationBean implements Serializable {
private static final long serialVersionUID = 1L;
//properties
private List<Person> people;
private String name;
private Boolean editMode;
#PersistenceContext(type=PersistenceContextType.EXTENDED)
private EntityManager em;
#PostConstruct
public void init() {
people = em.createNamedQuery("Person.findAll", Person.class).getResultList();
setEditMode(false);
}
//event listeners
public void beginEdits() {
setEditMode(true);
}
public void addPerson() {
Person p = new Person(name);
em.persist(p);
people.add(p);
name = null;
}
public void removePerson(Person p) {
people.remove(people.indexOf(p));
em.remove(p);
}
//this method flushes the persistence context to the database
#TransactionAttribute(javax.ejb.TransactionAttributeType.REQUIRES_NEW)
public void saveEdits() {
setEditMode(false);
}
//getters/setters
public List<Person> getPeople() {
return people;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean getEditMode() {
return editMode;
}
public void setEditMode(Boolean editMode) {
this.editMode = editMode;
}
}
Here's the Person entity bean:
package com.ray.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Version;
#Entity
#NamedQueries({
#NamedQuery(name="Person.findAll",
query="SELECT p FROM Person p")
})
public class Person {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
private String name;
#Version
private int version;
public Person() { }
public Person(String name) {
setName(name);
}
public boolean equals(Object o) {
if (!(o instanceof Person)) {
return false;
}
return id == ((Person)o).id;
}
//getters/setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
}
Here's the view:
<?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://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
$(document).ready(function() {
setInterval(function() {
$.get("#{request.contextPath}/poll");
}, #{(session.maxInactiveInterval - 10) * 1000});
});
</script>
<title>Conversation Test</title>
</h:head>
<h:body>
<h:form>
<h:commandLink value="Begin Edits" rendered="#{!conversationBean.editMode}">
<f:ajax render="#form" listener="#{conversationBean.beginEdits}"/>
</h:commandLink>
<h:commandLink value="Save" rendered="#{conversationBean.editMode}">
<f:ajax render="#form" listener="#{conversationBean.saveEdits}"/>
</h:commandLink>
<h:dataTable id="peopleTable" value="#{conversationBean.people}" var="person">
<h:column>
<f:facet name="header">Name</f:facet>
<h:panelGroup>
<h:inputText value="#{person.name}" disabled="#{!conversationBean.editMode}">
<f:ajax/>
</h:inputText>
<h:commandLink value="X" disabled="#{!conversationBean.editMode}">
<f:ajax render="#form" listener="#{conversationBean.removePerson(person)}"/>
</h:commandLink>
</h:panelGroup>
</h:column>
</h:dataTable>
<h:panelGrid columns="2">
<h:outputLabel for="name">Name:</h:outputLabel>
<h:inputText id="name" value="#{conversationBean.name}" disabled="#{!conversationBean.editMode}"/>
</h:panelGrid>
<h:commandButton value="Add" disabled="#{!conversationBean.editMode}">
<f:ajax execute="#form" render="#form" listener="#{conversationBean.addPerson}"/>
</h:commandButton>
</h:form>
</h:body>
</html>
Here's a servlet used to keep the session alive (called by jQuery ajax get request 10 seconds before session expires):
package com.ray.web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class PollServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void init() throws ServletException {
}
public String getServletInfo() {
return null;
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
request.getSession(); //Keep session alive
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
}
public void destroy() {
}
}
Any ideas on how I could prevent SFSB removal or at least handle it
more gracefully?
To investigate further I would recommend to take a look at the EJB lifecycle hooks for passivation and add some debug output there.
Should that be the source of the problem you will be able to configure / deactivate passivation - but scalability might come up as an issue.
Honestly, this scenario seems quite uncommon to me. In general I would expect requests / conversations / sessions to be working more or less in the default boundaries - should you find yourself writing code that circumvents this can it be that you are better off with a RESTful / stateless approach...?
Please update the question with further information if available.
I suppose you have already solved your problem. Otherwise, this JBoss wiki page should be helpful (also for future readers...).
https://community.jboss.org/wiki/Ejb3DisableSfsbPassivation
Cheers,
Luigi