views:

859

answers:

1

I have not been able to find a solution to this problem and my post to the Seam forum has gone unanswered. I am hope someone here can help.

I am a noob working with Seam, so I am sure I am just doing something stupid. Any help anyone can give me would be greatly appreciated... I have wasted hours and gotten nowhere. I used the jboss tools to generate a seam project in eclipse. The tool took pre-created JPA entities and created a basic webapp. My first step was to add a registration page so that I can create some users and login using database authentication (I set this up, but will test it once the registration page works). I used the seam-booking example to guide me (basically integrating the form stuff plus additional fields into the view of the seam-gen app). When I test the registration page, I get NullPointerExceptions for all of the injected fields. I have looked through the entire seam-booking example, scoured the web looking at examples, and quickly read through some sections of a book and I do not see where there is any additional configuration information needed. What in the world am I doing wrong? Please help!!!

I am using JBoss Server (community edition) 5.1.0GA and Seam 2.2.0GA.

If you need any more information than what I am posting, please let me know. Thanks to all ahead of time for your help!!

Stateful EJB:

@Stateful
@Scope(EVENT)
@Name("register")
public class RegisterAction implements Register {
    @In
    private User user;

    @PersistenceContext
    private EntityManager entityManager;

    @In 
    private FacesMessages facesMessages;

    private String verify = null;

    private boolean registered = false;

    public void registerUser() {
        if (user.getPassword().equals(verify)) {
            List existing = entityManager
                    .createQuery(
                            "select u.userName from User u where u.userName=#{user.userName}")
                    .getResultList();
            if (existing.size() == 0) {
                entityManager.persist(user);
                facesMessages
                        .add("Successfully registered as #{user.userName}");
                registered = true;
            } else {
                facesMessages.addToControl("userName",
                        "Username #{user.userName} already exists");
            }
        } else {
            facesMessages.addToControl("verify", "Re-enter your password");
            verify = null;
        }
    }

    public void invalid() {
        facesMessages.add("Please try again");
    }

    public boolean isRegistered() {
        return registered;
    }

    public String getVerify() {
        return verify;
    }

    public void setVerify(String verify) {
        this.verify = verify;
    }

    @Remove
    @Destroy
    public void destroy() {
    }
}

EJB local interface:

@Local
public interface Register
{
   public void registerUser();
   public void invalid();
   public String getVerify();
   public void setVerify(String verify);
   public boolean isRegistered();
   public void destroy();
}

XHTML of registratin page:

<ui:define name="body">
    <rich:panel>
        <f:facet name="header">Register</f:facet>
        <h:form id="registration">
            <fieldset><s:decorate id="firstNameDecorate"
                template="layout/edit.xhtml">
                <ui:define name="label">First Name:</ui:define>
                <h:inputText id="firstName" value="#{user.firstName}"
                    required="true">
                    <a:support id="onblur" event="onblur" reRender="firstNameDecorate" />
                </h:inputText>
            </s:decorate> <s:decorate id="lastNameDecorate" template="layout/edit.xhtml">
                <ui:define name="label">Last Name:</ui:define>
                <h:inputText id="lastName" value="#{user.lastName}" required="true">
                    <a:support id="onblur" event="onblur" reRender="lastNameDecorate" />
                </h:inputText>
            </s:decorate> <s:decorate id="emailDecorate" template="layout/edit.xhtml">
                <ui:define name="label">Email:</ui:define>
                <h:inputText id="emailAddress" value="#{user.emailAddress}"
                    required="true">
                    <a:support id="onblur" event="onblur" reRender="emailDecorate" />
                </h:inputText>
            </s:decorate> <s:decorate id="usernameDecorate" template="layout/edit.xhtml">
                <ui:define name="label">Username:</ui:define>
                <h:inputText id="username" value="#{user.userName}" required="true">
                    <a:support id="onblur" event="onblur" reRender="usernameDecorate" />
                </h:inputText>
            </s:decorate> <s:decorate id="passwordDecorate" template="layout/edit.xhtml">
                <ui:define name="label">Password:</ui:define>
                <h:inputSecret id="password" value="#{user.password}"
                    required="true" />
            </s:decorate> <s:decorate id="verifyDecorate" template="layout/edit.xhtml">
                <ui:define name="label">Verify Password:</ui:define>
                <h:inputSecret id="verify" value="#{register.verify}"
                    required="true" />
            </s:decorate>

            <div class="buttonBox"><h:commandButton id="register"
                value="Register" action="#{register.registerUser}" /> &#160; <s:button
                id="cancel" value="Cancel" view="/index.xhtml" /></div>
        </fieldset>
        </h:form>
    </rich:panel>
    </ui:define>
</ui:composition>

Template XHTML (Registration page uses this):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
<f:view xmlns="http://www.w3.org/1999/xhtml"
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:a="http://richfaces.org/a4j"
xmlns:s="http://jboss.com/products/seam/taglib"
contentType="text/html">
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  <title>MyApp</title>
  <link rel="shortcut icon" href="#{request.contextPath}/favicon.ico"/>
  <a:loadStyle src="resource:///stylesheet/theme.xcss"/>
  <a:loadStyle src="/stylesheet/theme.css"/>
  <ui:insert name="head"/>
</head>
<body>
  <ui:include src="menu.xhtml">
     <ui:param name="projectName" value="MyApp"/>
  </ui:include>
  <div class="body">
     <h:messages id="messages" globalOnly="true" styleClass="message"
        errorClass="errormsg" infoClass="infomsg" warnClass="warnmsg"
        rendered="#{showGlobalMessages != 'false'}"/>
     <ui:insert name="body"/>
  </div>
  <div class="footer">
     <p>Powered by <a href="http://seamframework.org"&gt;Seam&lt;/a&gt; #{org.jboss.seam.version} and <a href="http://www.jboss.org/jbossrichfaces"&gt;RichFaces&lt;/a&gt;. Generated by seam-gen.</p>
     <s:fragment rendered="#{init.debug}">
     <a:log hotkey="D"/>
     <p style="margin-top: -0.5em;">
        Conversation: id = #{conversation.id}, #{conversation.longRunning ? 'long running' : 'temporary'}#{conversation.nested ? ', nested, parent id = '.concat(conversation.parentId) : ''}
        #{' - '}
        Ajax4jsf Log (Ctrl+Shift+D)
        #{' - '}
        <s:link id="debugConsole" view="/debug.xhtml" value="Debug console" target="debugConsole"/>
        #{' - '}
        <s:link id="resetSession" view="/home.xhtml" action="#{org.jboss.seam.web.session.invalidate}" propagation="none" value="Terminate session"/>
     </p>
     </s:fragment>
  </div>
 </body>
</html>
</f:view>

Seam Components.xml file:

<?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:web="http://jboss.com/products/seam/web"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation=
            "http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.2.xsd
             http://jboss.com/products/seam/persistence http://jboss.com/products/seam/persistence-2.2.xsd
             http://jboss.com/products/seam/drools http://jboss.com/products/seam/drools-2.2.xsd
             http://jboss.com/products/seam/bpm http://jboss.com/products/seam/bpm-2.2.xsd
             http://jboss.com/products/seam/security http://jboss.com/products/seam/security-2.2.xsd
             http://jboss.com/products/seam/mail http://jboss.com/products/seam/mail-2.2.xsd
             http://jboss.com/products/seam/web http://jboss.com/products/seam/web-2.2.xsd
             http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.2.xsd"&gt;

 <core:init debug="true" jndi-pattern="@jndiPattern@"/>

 <core:manager concurrent-request-timeout="500"
             conversation-timeout="120000"
             conversation-id-parameter="cid"
             parent-conversation-id-parameter="pid"/>

 <!-- Make sure this URL pattern is the same as that used by the Faces Servlet -->
 <web:hot-deploy-filter url-pattern="*.seam"/>

 <persistence:managed-persistence-context name="entityManager" auto-create="true"
                  persistence-unit-jndi-name="java:/MyAppEntityManagerFactory"/>

 <drools:rule-base name="securityRules">
  <drools:rule-files>
     <value>/security.drl</value>
  </drools:rule-files>
 </drools:rule-base>

 <security:rule-based-permission-resolver security-rules="#{securityRules}"/>

<security:identity-manager identity-store="#{jpaIdentityStore}" />

<security:jpa-identity-store
    entity-manager="#{entityManager}" user-class="my.app.path.dao.profiles.User"
    role-class="my.app.path.dao.profiles.Role" />

 <event type="org.jboss.seam.security.notLoggedIn">
  <action execute="#{redirect.captureCurrentView}"/>
 </event>
 <event type="org.jboss.seam.security.loginSuccessful">
  <action execute="#{redirect.returnToCapturedView}"/>
 </event>

 <mail:mail-session host="localhost" port="25"/>
</components>
+4  A: 

A quick answer as I'm on the rush:

To address the Seam question first, is "User" a Seam component that will be auto-created or is there a factory method to create one? Annotating a field with @In is just one half of what's required, you still need the other end which supplies the value.

In the bigger picture:

  • presuming User is an entity, having it as a Seam component is not a good practice (way too much overhead caused by Seam).
  • your stateful bean is scoped as an EVENT. This is unlikely to be your desire, the EVENT scope in Seam is the same as a request for a servlet.

See if you can get a copy of "Seam in Action", it explains the fundamentals very well.

wishihadabettername
User is a JPA entity and has the Seam name annotation (i can't remember off the top of my head if it is a scoped entity). I did try a factory and create=true, but that didn't help. I thought that User is instantiated and populated from the registration page data. I have tried SESSION and CONVERSATION scope for the bean, neither worked. I have EVENT b/c that is what they used in the booking example included with the seam download. My code really doesn't look any different than the example, which works... so, I am really at a loss. I will definitely take a look at Seam In Action.
PaulP1975
First, realize that @Injected objects are injected before any methods are called on that component. So in this case ask *which* user would be instantiated in this case? I guess you expect an empty instance. To be so, you'd need a method annotated @Factory("user") which creates a new User().
wishihadabettername
Check section 4.7.1 of that book for an excellent explanation of how a component is instantiated (or not) or, a little bit less clear, http://docs.jboss.org/seam/2.2.0.GA/reference/en-US/html/concepts.html#d0e4003
wishihadabettername
i will take a look at the reference docs (don't have the book yet). thanks for the pointers!
PaulP1975
One other thing... we have been focusing on user, which is problematic and may have issues here. But, what about facesMessages. I thought that this was created by the container and injected for me when annotated with the @In. This is not one of my own objects and thought it was supposed to be essentially a freebie. Also, prior to posting for help, I had tried a plethora of things... one of those is the @Factory annotation on a method to create the user. It confuses me greatly how this code is a replica of the booking example, but doesn't work here. Doesn't this suggest a config issue?
PaulP1975
Something is fishy there. Indeed, facesMessages is predefined as an auto-create component in Seam's components.xml. I'm starting to suspect that Seam is not initialized at runtime. Do you see the messages from it in the JBoss log?
wishihadabettername
yes, i see all the messages and it looks like everything is loading properly. there is a message stating that it is installing the bean with dependencies and demands and supplies. interestingly, it shows no dependencies. I will post the log for this as a post rather than a comment.
PaulP1975
Guess I can't do that. here is the log, hopefully it will be readable:installing bean: jboss.j2ee:ear=DealDataWeb-ear.ear,jar=DealDataWeb-ejb.jar,name=RegisterAction,service=EJB3 with dependencies: and demands: jboss.ejb:service=EJBTimerService persistence.unit:unitName=DealDataWeb-ear.ear/DealDataWeb-ejb.jar#DealDataWeb and supplies: jndi:DealDataWeb-ear/RegisterAction/remote jndi:DealDataWeb-ear/RegisterAction/local Class:net.myproject.web.session.Register jndi:DealDataWeb-ear/RegisterAction/local-myproject.web.session.Register
PaulP1975
Those are messages about the EJB container installing the EJBs. I was talking about messages about *Seam* being initialized. Do you have a seam.properties in your jar? Quoting from the docs: Usually, Seam components are installed when the deployment scanner discovers a class with a @Name annotation sitting in an archive with a seam.properties file or a META-INF/components.xml file. I suspect you don't have that and, as such, the Seam nature of your component is not initialized (and, as such, it doesn't even get to be a Seam component, just an EJB).
wishihadabettername
I have an empty seam.properties file (same with the booking example). I do have a components.xml file, however. Is this the log entry you are looking for: "Component: user, scope: SESSION, type: ENTITY_BEAN, class: net.myapp.dao.profiles.User"? Thanks so much for the help with this issue. I am going to attempt a complete rebuild doing small pieces at a time to see if I introduced a problem by accident. It is clear that whatever is wrong is not at all obvious.
PaulP1975
wishihadabettername... the rebuild fixed the facesMessages, but not the user. this is good, b/c it is probably now just some misunderstanding on my part. i am stepping back and reading seam in action. i accepted your answer not b/c it fixed all the problems, but put me on the right track. thanks so much for the suggestions, information, and all of your assistance!
PaulP1975
i was wrong... the rebuild fixed nothing. i am still having the same problem... i have read a good portion of the seam in action book and i am still clueless... i have done everything right and by their example, yet it still doesn't work. i really don't get it. could it be a deployment issue? eclipse jboss as plugin deploys to the default/tmp directory... maybe that could be the source of my issue?
PaulP1975