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" />