Spring Injected Models
nealhaggard Apr 23, 2008 5:55 PMSpring Injected Models and Seam
I'm trying to use a Spring-defined service and framework/model layer that I have created and jarred up from a separate project to be reused in the Web layer of my application. Using my service objects have worked flawlessly, I was able to retrieve objects from my service layer and show them in a table without an issue. Now I'm trying to use Seam to create a new account for a user on the web layer by injecting an 'Account' model object from my Spring definition of a JPA/Hibernate POJO.
The problem I'm seeing is that Seam appears to be injecting a fresh account into my RegisterBean with every request. How do I set up the RegisterBean with one Account object that'll stick around until I'm done registering the user? (Note that I'm using a4j's support to re-validate the Account object with every onblur, so it'll need to stick through that).
Am I going about this completely wrong? I'm new to Seam, but not JSF, so I have enough knowledge to be dangerous, but really am still grasping to understand the state/stateless nature of doing this with POJOs instead of EJBs. I really don't want to have to rewrite my Model objects as EJBs as the JPA/Hibernate POJO is working great in the rest of the app.
I'm including what I feel are the relevant code pieces to help you guys answer my question. If you need more info, please let me know and I'll post more of my config.
components.xml
<?xml version="1.0" encoding="UTF-8"?>
<components xmlns="http://jboss.com/products/seam/components"
xmlns:core="http://jboss.com/products/seam/core"
xmlns:persistence="http://jboss.com/products/seam/persistence"
xmlns:drools="http://jboss.com/products/seam/drools"
xmlns:bpm="http://jboss.com/products/seam/bpm"
xmlns:security="http://jboss.com/products/seam/security"
xmlns:mail="http://jboss.com/products/seam/mail"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:spring="http://jboss.com/products/seam/spring"
xsi:schemaLocation=
"http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.0.xsd
http://jboss.com/products/seam/persistence http://jboss.com/products/seam/persistence-2.0.xsd
http://jboss.com/products/seam/drools http://jboss.com/products/seam/drools-2.0.xsd
http://jboss.com/products/seam/bpm http://jboss.com/products/seam/bpm-2.0.xsd
http://jboss.com/products/seam/security http://jboss.com/products/seam/security-2.0.xsd
http://jboss.com/products/seam/mail http://jboss.com/products/seam/mail-2.0.xsd
http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.0.xsd
http://jboss.com/products/seam/spring
http://jboss.com/products/seam/spring-2.0.xsd">
<core:init debug="@debug@" jndi-pattern="@jndiPattern@"/>
<core:manager concurrent-request-timeout="500"
conversation-timeout="120000"
conversation-id-parameter="cid"/>
<persistence:managed-persistence-context name="entityManager"
auto-create="true"
entity-manager-factory="#{MyAppEntityManagerFactory}"/>
<persistence:entity-manager-factory name="MyAppEntityManagerFactory"
persistence-unit-name="MyApp"/>
<drools:rule-base name="securityRules">
<drools:rule-files><value>/security.drl</value></drools:rule-files>
</drools:rule-base>
<security:identity authenticate-method="#{authenticator.authenticate}"
security-rules="#{securityRules}"
remember-me="true"/>
<event type="org.jboss.seam.security.notLoggedIn">
<action execute="#{redirect.captureCurrentView}"/>
</event>
<event type="org.jboss.seam.security.loginSuccessful">
<action execute="#{redirect.returnToCapturedView}"/>
</event>
<spring:context-loader>
<spring:config-locations>
<value>classpath:coreResourceContext.xml</value>
<value>classpath:daoContext.xml</value>
<value>classpath:modelContext.xml</value>
</spring:config-locations>
</spring:context-loader>
</components>
menu.xhtml
<rich:toolBar
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:rich="http://richfaces.org/rich">
<rich:toolBarGroup>
<h:outputText value="#{projectName}:"/>
<s:link view="/home.xhtml" value="Home"/>
<s:link view="/accountList.xhtml" value="Accounts" rendered="#{identity.loggedIn}" />
</rich:toolBarGroup>
<!-- @newMenuItem@ -->
<rich:toolBarGroup location="right">
<h:outputText value="Welcome, #{identity.username}!" rendered="#{identity.loggedIn}"/>
<s:link view="/login.xhtml" value="Login" rendered="#{not identity.loggedIn}"/>
<s:link view="/register.xhtml" value="Register" rendered="#{not identity.loggedIn}" conversationScope="begin" />
<s:link view="/home.xhtml" action="#{identity.logout}" value="Logout" rendered="#{identity.loggedIn}"/>
</rich:toolBarGroup>
</rich:toolBar>
RegisterBean.java
@Name("registerAccount")
@Scope(ScopeType.CONVERSATION)
public class RegisterBean {
@In("#{accountService}")
private AccountService accountService;
@In("#{account}")
@Out
private Account account;
@In
private FacesMessages facesMessages;
private boolean registered = false;
/**
* Do the work of creating an account.
*
* @return
*/
@End
public void register() {
LogicMessages messages = new LogicMessages();
try {
messages = accountService.create(account);
registered = true;
} catch (LogicException e) {
messages.addAll(e.getMessages());
}
WebUtil.addLogicMessages(messages, facesMessages);
}
/**
* @return the registered
*/
public boolean isRegistered() {
return registered;
}
}
register.xhtml
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:rich="http://richfaces.org/rich"
xmlns:a4j="http://richfaces.org/a4j"
template="layout/template.xhtml">
<ui:define name="body">
<h:form id="registerForm">
<h:messages globalOnly="true" />
<rich:panel>
<f:facet name="header">Register a new Account</f:facet>
<fieldset>
<s:decorate id="nameDecoration" template="layout/edit.xhtml">
<ui:define name="label">Name:</ui:define>
<h:inputText value="#{account.name}" required="true">
<a4j:support event="onblur" reRender="nameDecoration" />
</h:inputText>
</s:decorate>
<s:decorate id="emailDecoration" template="../layout/edit.xhtml">
<ui:define name="label">Email:</ui:define>
<h:inputText value="#{account.email}" required="true">
<a4j:support event="onblur" reRender="emailDecoration" />
</h:inputText>
</s:decorate>
<s:decorate id="securityQuestionDecoration" template="layout/edit.xhtml">
<ui:define name="label">SecurityQuestion:</ui:define>
<h:inputText value="#{account.securityQuestion}" required="true">
<a4j:support event="onblur" reRender="securityQuestionDecoration" />
</h:inputText>
</s:decorate>
<s:decorate id="securityAnswerDecoration" template="layout/edit.xhtml">
<ui:define name="label">Security Answer:</ui:define>
<h:inputText value="#{account.securityAnswer}" required="true">
<a4j:support event="onblur" reRender="securityAnswerDecoration" />
</h:inputText>
</s:decorate>
</fieldset>
</rich:panel>
<div class="actionButtons">
<h:commandButton value="Register!" action="#{registerAccount.register}" />
</div>
</h:form>
</ui:define>
</ui:composition>
daoContext.xml (relevant bit)
<bean id="accountDao" class="myapp.AccountJpaDaoImpl"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <bean id="accountService" class="myapp.AccountServiceImpl"> <constructor-arg> <ref bean="accountDao" /> </constructor-arg> </bean>
modelContext.xml (relevant bit)
<bean id="account" class="myapp.AccountImpl" scope="prototype" />