[Resolvido] JSF + Primefaces: Tab com conteúdo dinâmico

Pessoal,

Estou tendo dificuldade em inserir um conteúdo dinâmico em uma tab.
Já tentei utilizar um include passando a url do xhtml, mas não renderiza.
[code]<p:tabView value="#{tabViewController.tabList}"
activeIndex="#{tabViewController.activeIndex}" var=“tabItem”
dynamic=“true” closeable=“true”>

			<p:ajax event="tabClose" listener="#{tabViewController.onTabClose}"/>
			<p:ajax event="tabChange" listener="#{tabViewController.onTabChange}"/>
			
			<p:tab title="#{tabItem.name}" id="tab" closable="true">
						<p:panel><ui:include src="#{tabItem.url}"/></p:panel> 
							
			</p:tab>
		</p:tabView>[/code]

Segue o código do MB:

[code]@SessionScoped
@ManagedBean
public class TabViewController
{
private List tabList;
private int activeIndex = 0;

public TabViewController()
{
	tabList = new ArrayList<TabItem>();

	tabList.add(new TabItem("tab1", "teste.xhtml", 0));
	tabList.add(new TabItem("tab2", "teste.xhtml", 1));
}

public class TabItem
{
	private String name;
	private String url;
	private int tabIndex;

	public TabItem(String name, String url, int tabIndex)
	{
		this.setName(name);
		this.setUrl(url);
		this.setTabIndex(tabIndex);
	}

	//getters and setters...
	
}

}[/code]
teste.xhtml

[code]<h:head>

<title>teste</title>

</h:head>
<h:body style=“font-size: 10pt”>

<h:outputText value="conteúdo de teste.xhtml" />

</h:body>

[/code] Então... quando tento acessar o conteúdo do teste.xhtml não aparece nada.

na sua pagina que é inserida, deixe apenas o código: <h:outputText value=“conteúdo de teste.xhtml” /> e teste.

não funcionou… e engraçado que ele nem passa pelo método getUrl() do tabItem, somente pelo getName()

tenta retirar do <p:panel>.

Não deu certo.

Seus componentes estão dentro de outros componentes? tente coloca-los apenas dentro de um h:head e h:body.

O único problema que vejo em seu código é o ui:include. Ele é renderizado em um momento diferente dos componentes do primefaces, por isso não funciona. Você pode criar a tabView dinamicamente utilizando jstl, conforme abaixo:

<p:tabView>
            <c:forEach items="#{tabViewController.tabs}" var="t">
                <p:tab title="#{t.titulo}">
                    <ui:include src="#{t.url}"/>
                </p:tab>
            </c:forEach>
</p:tabView>

espero ter ajudado.

Obrigado benignoms

Resolveu parcialmente o meu problema, pois está mostrando o conteúdo dentro da tab, mas a questão agora é…
Como eu faço para atualizar a tabview quando eu insiro uma nova tab a minha lista no managedbean?

Bom dia a todos…
Você conseguiu resolver o problema…
Há algum tempo venho tentando fazer o mesmo, mas não consigo.
Eu queria um menu programável - dinâmico, que, quando eu clicasse em algum item do menu, fosse criada uma nova tab e o conteúdo dela fosse uma página específica, cujo endereço é um atributo da classe menu.
Valeu…

Consegui sim.

menu.xhtml

[code]<h:form>
<p:accordionPanel value="#{menuController.menus}" var=“menu”>
<p:tab title="#{menu.group}">


    <ui:repeat value="#{menu.subMenu}" var=“subMenu”>
    <p:commandLink ajax=“true” oncomplete=“updateTabView()”>
    <f:setPropertyActionListener target="#{tabViewController.label}"
    value="#{subMenu.label}" />
    <f:setPropertyActionListener target="#{tabViewController.url}"
    value="#{subMenu.url}" />
    <f:setPropertyActionListener target="#{tabViewController.tabID}"
    value="#{subMenu.tabID}" />
						<img id="subMenuIcon"
							src="#{request.contextPath}/img/icons/#{subMenu.iconImg}" />
						<h:outputText value="#{subMenu.label}" />

					</p:commandLink>
					<br />
				</ui:repeat>
			</ul>
			
			<p:remoteCommand name="updateTabView" update=":tabView"></p:remoteCommand>
		</p:tab>
	</p:accordionPanel>
	
</h:form>[/code]

tabView.xhtml

[code]<p:tabView id=“tabView”
activeIndex="#{tabViewController.activeIndex}"
style=“heigth:100%;”>

			<p:ajax event="tabClose" listener="#{tabViewController.onTabClose}" />
			<p:ajax event="tabChange"
				listener="#{tabViewController.onTabChange}" />

			<c:forEach items="#{tabViewController.tabList}" var="tabItem">
				<p:tab title="#{tabItem.title}" closable="#{tabItem.closeable}" id="#{tabItem.id}">
					<ui:include src="http://#{request.serverName}:#{request.serverPort}#{request.contextPath}/#{tabItem.url}" />
				</p:tab>
			</c:forEach>

		</p:tabView>[/code]

O segredo depois de inserido a nova tab a lista contida no tabViewController é fazer o update do componente tabView e isso você pode ver quando faço a chama do remoteCommand no menu.xhtml acima.

<p:remoteCommand name="updateTabView" update=":tabView"></p:remoteCommand>

Não coloquei os controllers porque isso pode ser facilmente compreendido.

Mews, valeu pela resposta…
Faz um tempão que eu estou tentando fazer isso… Já tinha até desistido…
Pra falar a verdade eu sou bem fraco em Java.
Vou tentar implementar.

Abração.

Mews…
Tô apanhando pra fazer o esquema das tabs…
Você poderia postar os componentes completos?
Valeu…
Abraços…

Vamos fazer ao contrário.
Você coloca o que você já tem e eu te ajudo.

Mews… mais uma vez obrigado pela resposta e paciência…
Olha só os códigos que tenho…
São bem simples, mas não tô dando conta.
index.xhtml:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!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"
      xmlns:p="http://primefaces.org/ui"
      xmlns:c="http://java.sun.com/jsp/jstl/core">
      
    <f:view contentType="text/html">
        <h:head>
            <f:facet name="first">
                <meta http-equiv="X-UA-Compatible" content="EmulateIE8" />
                <meta content='text/html; charset=UTF-8' http-equiv="Content-Type"/>
                <title>PrimeFaces - ShowCase</title>
            </f:facet>

            <link type="text/css" rel="stylesheet" href="#{request.contextPath}/resources/css/default.css" />
            <link type="text/css" rel="stylesheet" href="#{request.contextPath}/resources/css/syntaxhighlighter/syntaxhighlighter.css" />

            <style type="text/css">
                .ui-layout-north {
                    z-index:20 !important;
                    overflow:visible !important;;
                }

                .ui-layout-north .ui-layout-unit-content {
                    overflow:visible !important;
                }
            </style>
        </h:head>


        <h:body>

            <p:layout fullPage="true" >

                <p:layoutUnit id="top" position="north" size="50">
                </p:layoutUnit>

                <p:layoutUnit id="bottom" position="south" size="60">
                </p:layoutUnit>

                <p:layoutUnit id="left" position="west" size="300" resizable="true" closable="true" collapsible="true" header="Options" minSize="200">
					<h:form>
						<p:accordionPanel value="#{menuController.menus}" var="menu">
							<p:tab title="#{menu.group}">
								<ul>
									<ui:repeat value="#{menu.subMenu}" var="subMenu">
										<p:commandLink ajax="true" oncomplete="updateTabView()">
											<f:setPropertyActionListener target="#{tabViewController.label}"
												value="#{subMenu.label}" />
											<f:setPropertyActionListener target="#{tabViewController.url}"
												value="#{subMenu.url}" />
											<f:setPropertyActionListener target="#{tabViewController.tabID}"
												value="#{subMenu.tabID}" />
				
											<h:outputText value="#{subMenu.label}" />
				
										</p:commandLink>
										<br />
									</ui:repeat>
								</ul>
								
								<p:remoteCommand name="updateTabView" update=":tabView"></p:remoteCommand>
							</p:tab>
						</p:accordionPanel>
					</h:form>
                </p:layoutUnit>

                <p:layoutUnit id="right" position="east" size="250" header="Gallery" resizable="true" closable="true" collapsible="true" style="text-align:center">
                <h:form>
					 <p:themeSwitcher value="#{themeSwitcherBean.theme}" style="width:150px" effect="fade">
						<f:selectItem itemLabel="Choose Theme" itemValue="" />
						<f:selectItems value="#{themeSwitcherBean.themes}" />
						<p:ajax listener="#{themeSwitcherBean.saveTheme}" />
					 </p:themeSwitcher>
                </h:form>
                </p:layoutUnit>

                <p:layoutUnit id="center" position="center">


					<p:tabView id="tabView"	activeIndex="#{tabViewController.activeIndex}"	style="heigth:100%;">
						<p:ajax event="tabClose" listener="#{tabViewController.onTabClose}" />  
						<p:ajax event="tabChange" listener="#{tabViewController.onTabChange}" />

						<c:forEach items="#{tabViewController.tabList}" var="tabItem">  
							<p:tab title="#{tabItem.title}" id="#{tabItem.id}">  
								<ui:include src="http://#{request.serverName}:#{request.serverPort}#{request.contextPath}/#{tabItem.url}" />  
							</p:tab>  
						</c:forEach> 
					</p:tabView>

                </p:layoutUnit>

            </p:layout>

            <p:dialog header="Basic Dialog" widgetVar="dlg1" modal="true">
                <h:outputText value="Resistance to PrimeFaces is futile!" />
            </p:dialog>

        </h:body>

    </f:view>
</html>

TabViewController.java:

package br.com.sitic.sitic.sistema.controller;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

@SuppressWarnings("serial")
@ManagedBean(name="tabViewController")
@ViewScoped
public class TabViewController implements Serializable{
	private List<TabItem> tabList;
	private int activeIndex = 0;

	public TabViewController(){
		tabList = new ArrayList<TabItem>();

		tabList.add(new TabItem("tab1", "teste.xhtml", 0));
		tabList.add(new TabItem("tab2", "teste.xhtml", 1));
	}
	
	public List<TabItem> getTabList() {
		return tabList;
	}

	public void setTabList(List<TabItem> tabList) {
		this.tabList = tabList;
	}

	public int getActiveIndex() {
		return activeIndex;
	}

	public void setActiveIndex(int activeIndex) {
		this.activeIndex = activeIndex;
	}

	public class TabItem implements Serializable{
		private String title;
		private String id;
		private String name;
		private String url;
		private int tabIndex;
		private String label;

		public TabItem(String name, String url, int tabIndex)
		{
			this.setName(name);
			this.setUrl(url);
			this.setTabIndex(tabIndex);
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public String getUrl() {
			return url;
		}

		public void setUrl(String url) {
			this.url = url;
		}

		public int getTabIndex() {
			return tabIndex;
		}

		public void setTabIndex(int tabIndex) {
			this.tabIndex = tabIndex;
		}

		public String getTitle() {
			return title;
		}

		public void setTitle(String title) {
			this.title = title;
		}

		public String getId() {
			return id;
		}

		public void setId(String id) {
			this.id = id;
		}

		public String getLabel() {
			return label;
		}

		public void setLabel(String label) {
			this.label = label;
		}

		//getters and setters...
		
	}
}

No seu TabViewController você não tem os atributos que estão sendo utilizados no teu Menu.

<f:setPropertyActionListener target="#{tabViewController.label}" value="#{subMenu.label}" /> <f:setPropertyActionListener target="#{tabViewController.url}" value="#{subMenu.url}" /> <f:setPropertyActionListener target="#{tabViewController.tabID}" value="#{subMenu.tabID}" />
Então você pode fazer assim…
Como o clique no link do menu executa algumas tarefas utilizando ajax, você pode sincronizar os eventos.
de acordo como você escreveu o seu menu, o JSF vai setar os valores do label, url e tabID no seu tabViewController.
Significa que depois de ele ter inserido o tabID, você poderá chamar a função addTab() criando um novo objeto tabItem e inserindo ele na tabList.
Por fim, ou seja, no onComplete() do click ele executará o remoteCommand que atualizará a tabView.

Obs: Você precisa que os valores acima dos menus estejam setados.

#{subMenu.label}
#{subMenu.url}
#{subMenu.tabID}

Mews…
Mais uma vez peço tua ajuda.
Tô tentando sem sucesso resolver o problema.
A tela tá aparecendo, não dá erro… até o system.out.println que eu coloquei exibe a msg no tomcat.
Mas só exibe a msg de que entrou no
Posto agora todos os códigos que utilizo pra você ver se pode me ajudar.

Menu.java:

[code]package br.com.sitic.sitic.sistema.model;

import java.io.Serializable;
import java.util.List;

@SuppressWarnings(“serial”)
public class Menu implements Serializable{
private String group;
private String label;
private String url;
private int tabId;
private String iconImg;
private List subMenu;

public Menu(String group, String label, String url, int tabId, String iconImg, List<Menu> subMenu){
	this.group = group;
	this.label = label;
	this.url = url;
	this.tabId = tabId;
	this.iconImg = iconImg;
	this.subMenu = subMenu;
}

public String getGroup() {
	return group;
}
public void setGroup(String group) {
	this.group = group;
}
public String getLabel() {
	return label;
}
public void setLabel(String label) {
	this.label = label;
}
public String getUrl() {
	return url;
}
public void setUrl(String url) {
	this.url = url;
}
public int getTabId() {
	return tabId;
}
public void setTabId(int tabId) {
	this.tabId = tabId;
}
public String getIconImg() {
	return iconImg;
}
public void setIconImg(String iconImg) {
	this.iconImg = iconImg;
}

public List<Menu> getSubMenu() {
	return subMenu;
}

public void setSubMenu(List<Menu> subMenu) {
	this.subMenu = subMenu;
}

}
[/code]

MenuController.java:

[code]package br.com.sitic.sitic.sistema.controller;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

import br.com.sitic.sitic.sistema.model.Menu;

@SuppressWarnings(“serial”)
@ManagedBean(name=“menuController”)
@SessionScoped
public class MenuController implements Serializable{
private List menus;
private List subMenu;

public MenuController(){
	int tabId = 0;
	
	menus = new ArrayList<Menu>();
	subMenu = new ArrayList<Menu>();
	subMenu.add(new Menu ("", "Aplicação 1","teste.xhtml",tabId++,"iconImg Sistema-1",null));
	subMenu.add(new Menu ("", "Aplicação 2","teste.xhtml",tabId++,"iconImg Sistema-2",null));
	menus.add(new Menu ("Group Sistema", "Label Sistema","",0,"",subMenu));
}

public List<Menu> getMenus() {
	return menus;
}

public void setMenus(List<Menu> menus) {
	this.menus = menus;
}

}[/code]

TabViewController.java:

package br.com.sitic.sitic.sistema.controller;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@SuppressWarnings("serial")
@ManagedBean(name="tabViewController")
@SessionScoped
public class TabViewController implements Serializable{
	private String label;
	private String url;
	private int tabId;
	private List<TabItem> tabList;
	private int activeIndex = 0;

	public TabViewController(){
		tabList = new ArrayList<TabItem>();
		System.out.println("label: "+label+", url: "+url+"tabId: "+tabId);
		if(tabId>0){
			tabList.add(new TabItem(label, url, tabId));
		}
	}
	
	public String getLabel() {
		return label;
	}

	public void setLabel(String label) {
		this.label = label;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public int getTabId() {
		return tabId;
	}

	public void setTabId(int tabId) {
		this.tabId = tabId;
	}

	public List<TabItem> getTabList() {
		return tabList;
	}

	public void setTabList(List<TabItem> tabList) {
		this.tabList = tabList;
	}

	public int getActiveIndex() {
		return activeIndex;
	}

	public void setActiveIndex(int activeIndex) {
		this.activeIndex = activeIndex;
	}

	public class TabItem implements Serializable{
		private String name;
		private String url;
		private int tabIndex;

		public TabItem(String name, String url, int tabIndex)
		{
			this.setName(name);
			this.setUrl(url);
			this.setTabIndex(tabIndex);
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public String getUrl() {
			return url;
		}

		public void setUrl(String url) {
			this.url = url;
		}

		public int getTabIndex() {
			return tabIndex;
		}

		public void setTabIndex(int tabIndex) {
			this.tabIndex = tabIndex;
		}

	}
}

index.xhtml:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!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"
      xmlns:p="http://primefaces.org/ui"
      xmlns:c="http://java.sun.com/jsp/jstl/core">
      
    <f:view contentType="text/html">
        <h:head>
            <f:facet name="first">
                <meta http-equiv="X-UA-Compatible" content="EmulateIE8" />
                <meta content='text/html; charset=UTF-8' http-equiv="Content-Type"/>
                <title>PrimeFaces - ShowCase</title>
            </f:facet>

            <link type="text/css" rel="stylesheet" href="#{request.contextPath}/resources/css/default.css" />
            <link type="text/css" rel="stylesheet" href="#{request.contextPath}/resources/css/syntaxhighlighter/syntaxhighlighter.css" />

            <style type="text/css">
                .ui-layout-north {
                    z-index:20 !important;
                    overflow:visible !important;;
                }

                .ui-layout-north .ui-layout-unit-content {
                    overflow:visible !important;
                }
            </style>
        </h:head>


        <h:body>

            <p:layout fullPage="true" >

                <p:layoutUnit id="top" position="north" size="50">
                </p:layoutUnit>

                <p:layoutUnit id="bottom" position="south" size="60">
                </p:layoutUnit>

                <p:layoutUnit id="left" position="west" size="300" resizable="true" closable="true" collapsible="true" header="Options" minSize="200">
					<h:form>
						<p:accordionPanel value="#{menuController.menus}" var="menu">
							<p:tab title="#{menu.group}">
								<ul>
									<ui:repeat value="#{menu.subMenu}" var="subMenu">
										<p:commandLink ajax="true" oncomplete="updateTabView()">
											<f:setPropertyActionListener target="#{tabViewController.label}"
												value="#{subMenu.label}" />
											<f:setPropertyActionListener target="#{tabViewController.url}"
												value="#{subMenu.url}" />
											<f:setPropertyActionListener target="#{tabViewController.tabId}"
												value="#{subMenu.tabId}" />
				
											<h:outputText value="#{subMenu.label}" />
											<h:outputText value="#{subMenu.url}" />
											<h:outputText value="#{subMenu.tabId}" />
				
										</p:commandLink>
										<br />
									</ui:repeat>
								</ul>
								
								<p:remoteCommand name="updateTabView" update=":tabView"></p:remoteCommand>
							</p:tab>
						</p:accordionPanel>
					</h:form>
                </p:layoutUnit>

                <p:layoutUnit id="right" position="east" size="250" header="Gallery" resizable="true" closable="true" collapsible="true" style="text-align:center">
                <h:form>
					 <p:themeSwitcher value="#{themeSwitcherBean.theme}" style="width:150px" effect="fade">
						<f:selectItem itemLabel="Choose Theme" itemValue="" />
						<f:selectItems value="#{themeSwitcherBean.themes}" />
						<p:ajax listener="#{themeSwitcherBean.saveTheme}" />
					 </p:themeSwitcher>
                </h:form>
                </p:layoutUnit>

                <p:layoutUnit id="center" position="center">


					<p:tabView id="tabView"	activeIndex="#{tabViewController.activeIndex}"	style="heigth:100%;">
						<p:ajax event="tabClose" listener="#{tabViewController.onTabClose}" />  
						<p:ajax event="tabChange" listener="#{tabViewController.onTabChange}" />

						<c:forEach items="#{tabViewController.tabList}" var="tabItem">   
							<p:tab title="#{tabItem.name}" id="#{tabItem.tabIndex}">   
								<ui:include src="http://#{request.serverName}:#{request.serverPort}#{request.contextPath}/#{tabItem.url}" />   
							</p:tab>   
						</c:forEach>
					</p:tabView>

                </p:layoutUnit>

            </p:layout>

            <p:dialog header="Basic Dialog" widgetVar="dlg1" modal="true"> 
                <h:outputText value="Resistance to PrimeFaces is futile!" />
            </p:dialog>

        </h:body>

    </f:view>
</html>

teste.xhtml:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!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">
<body>
 Teste aqui.
</body>
</html>

Ooooops…
Fiquei preocupado com os códigos e esqueci de falar do problema.
Eu coloquei um system.out.println pra ver quais os valores que apareceriam a cada vez que fosse chamado o construtor do tabViewController.

Aparece a msg:
label: null, url: nulltabId: 0

Toda vez que a página é chamada pela primeira vez.
Só que como você pode ver, no index.xhtml eu coloquei:
<h:outputText value="#{subMenu.label}" />
<h:outputText value="#{subMenu.url}" />
<h:outputText value="#{subMenu.tabId}" />

O nome do botão aparecem todos os valores, só que, aparentemente, esses valores não são atualizados para os atributos da classe.
Depois não acontece mais nada.
Não aparece mais msg alguma quando clico nos items do menu, nem mesmo é aberta nova aba…
outra coisa que notei foi a falta dos métodos onTabClose e onTabChange no TabViewController… eu não sei o que colocar neles…
qualquer ajuda é bem vinda.

Abraços.

Com relação aos eventos da tab… esses não são necessários.
Eu criei apenas para saber qual tab está selecionada e para remover uma tab da lista quando o usuário fechar a tab.

faz as seguintes alterações:

TabViewController

Altera o teu construtor:

public TabViewController() { tabList = new ArrayList<TabItem>(); }
Cria o método addTab() e coloca dentro dele o seguinte código

this.tabList.add(new TabItem(this.label, this.url, tabIndex));

Quando o JSF chamar o método setTabId() dentro dele você pode chamar o addTab().
Não é a forma mais linda de se fazer, mas é uma forma de sincronizar os eventos para dar conta desse cenário.

Além disso, coloca breakpoint nos teus getters e setters para ver se estão executando corretamente.

Eu coloquei nos get e setters…
Estão funcionando corretamente.
Estava tentando adicionar os itens por meio de um actionEvent…
Olha só:
public void adicionarTabItem(ActionEvent actionEvent){
System.out.println(“adicionarTabItem…”);
System.out.println("label: “+label+”, url: "+url+"tabId: "+tabId);
tabList.add(new TabItem(label, url, tabId));
}
O resultado foi:
Quando eu clico em um botão/link, aparecem as mensagens:
adicionarTabItem…
label: menuxx, url: urlxxx: tabId: 1.

Mas a mensagem só aparece uma vez… posso clicar quantas vezes eu quizer, não acontece mais nada.
Só quando eu tento atualizar a página CTRL F5, aí dá um erro doido:

16/02/2012 16:18:47 org.apache.catalina.core.StandardWrapperValve invoke
GRAVE: Servlet.service() for servlet [Faces Servlet] in context with path [/sitic] threw exception [0] with root cause
java.lang.IllegalArgumentException: 0
	at javax.faces.component.UIComponentBase.validateId(UIComponentBase.java:542)
bla bla bla....

Acho que isso tá acontecendo porque a classe é SessionScoped, e eu deveria chaamr o ActionEvent em uma classe ViewScoped, correto?
Esse caminho que eu tô tentando seguir vai dar certo ou é melhor fazer como você tá falando?
Mais uma vez obrigado pela ajuda.

Você pode fazer dessa forma, porém os eventos são assíncronos e por isso que quando você manda adicionar a tab os valores estão null.
O outro problema é que você precisa colocar um id único para cada tab adicionada. Para isso adicione um novo atributo no TabItem e depois passe para o xhtml.