0
votes

I used to initialize certain properties of an entity object with pre-defined values as early as its instantiation in a @PostConstruct method of a jsf managed bean (or even the managed bean's constructor). I can no longer preserve this functionality when porting the project to Seam with the managed bean gone (wondering also how it would be in JSF 2.2 without managed beans).

The entity class:

@Entity
@Name("task") // this line in Seam version
public class Task implements Serializable {

    private Integer id;
    private String subject;
    private Date creationDate;
    private Date completionDate;
    private Category category;
    private User user;

    public Task() {
    }

    public Task(Date creationDate) {
        this.creationDate = creationDate;
        this.user = user;
    }

    // getters & setters, etc.
}

The JSF Managed Bean

public class TaskBean extends BaseBean {

    // Super class provides the logged in user object and a default category object

    private Task task = new Task(java.util.Calendar.getInstance().getTime(), this.user);

    @PostConstruct
    public void initTaskBean() {
        if (certainConditionMet) 
            task.setCategory(defaultCategory);
    }

    // Other managed bean business...
}

The JSF page

<h:form>
<h:panelGrid columns="2">
    Date: <h:outputText value="#{taskBean.task.creationDate}">
            <f:convertDateTime pattern="dd/MM/yyyy" />
           </h:outputText>
    User:  <h:outputText value="#{taskBean.task.user.name}" />
    Subject: <h:inputText value="#{taskBean.task.subject}" id="subjectField" />
    Category: <h:selectOneMenu value="#{taskBean.task.category}" id="catMenu">
                <f:selectItems value="#{taskBean.categories}" />
              </h:selectOneMenu>
    // remaining stuff
</h:panelGrid>
</h:form>

The Stateless Session Bean in Seam version also assuming the responsibility of the jsf managed bean

@Name("taskAction")
@Stateless
public class TaskAction implements TaskActionLocal {

    @PersistenceContext
    private EntityManager em;

    @In private FacesMessages facesMessages;
    @In User user;
    @In Category defaultCategory
    @Logger private Log log;

    @In
    // private Task task = new Task(java.util.Calendar.getInstance().getTime(), user)
    // the above didn't work so 
    private Task task; 

    @PostConstruct
    public void baslarken() {
        System.out.println("TaskAction PostConstructed");
        task = new task(java.util.Calendar.getInstance().getTime(), user);
        if (certainConditionMet) 
                task.setCategory(defaultCategory);

        // the above won't work either. Date and User always blank on the ui form
    }

    // other business methods, etc
}

Seam version of the form:

<h:form id="todo" styleClass="edit">
    <rich:panel>
        <f:facet name="header">Task To Do</f:facet>

        <s:decorate id="dateField" template="layout/edit.xhtml">
            <ui:define name="label">Date:</ui:define>
            <h:outputText value="#{task.creationDate}"/>
        </s:decorate>

        <s:decorate id="userField" template="layout/edit.xhtml">
            <ui:define name="label">User:</ui:define>
            <h:outputText value="#{task.user.name}"/>
        </s:decorate>

        <s:decorate id="subjectField" template="layout/edit.xhtml">
            <ui:define name="label">Başlık</ui:define>
            <h:inputText id="subject" required="true" value="#{task.subject}" >
            <a4j:support event="onblur" reRender="subjectField" bypassupdates="true" ajaxSingle="true" />
            </h:inputText>
        </s:decorate>

        <!-- other components, etc -->
    </rich:panel>
</h:form>

I need advice on how to make the task object to hold the date and logged in user data (and preferably a default category) pre-populated when instantiated.

2

2 Answers

1
votes

You have several possibilities to initialize an entity. There is the EntityHome class that you can extend for an entity. It's the default implementation of handling entities for an editor. It is also used if you use seam-gen to create your application.

This would look something like this:

@Name("queryHome")
@Scope(ScopeType.CONVERSATION)
public class QueryHome extends EntityHome<Query> {
    /*
     * (non-Javadoc)
     * @see org.jboss.seam.framework.Home#createInstance()
     */
    @Override
    public Query createInstance() {
        Query query = super.createInstance();
        query.setUser(loggedUser);
        query.setCreationDate(new Date());
        query.setLastExecutionDate(new Date());
        return query;
    }
}

And you will be calling queryHome.getInstance(). If the id property in entityHome is set it will try to load the entity with this id from the database, and if there is no id it will call createInstance(). This is how i use it normally.

You can also create a factory annotated method in a seam managed bean. There you can do whatever you like.

@Name("CreationFactory")
@Scope(ScopeType.STATELESS)
pulic class CreationFactory {

    @Factory("createNewTask")
    public Task createTask() {
        Task task = new Task();
        task.sometext = "sometext";
        return task;
    }
}

I normally do not access or create a bean directly but i use a manager component like the entityhome to do it. You can simplify the access with a factory, but this is explained in the Seam documentation.

Martin

1
votes

First im sorry but i cannot find a comment link on this answer?? ( so moderators feel free to move this post;) )

Extending the entityhome class as a session bean should be possible yes. But if its the right thing to do i'm not sure. I would more likely create a new session bean that serves my purpose more exact.

For the factory invocation. You will call this the same way from a jsf page as any other name. I.e. value="#{createNewTask.id}". Or you can inject it into another class. Take a look at the seam doc. Its really well written.