13.2. Home objects
A Home object provides persistence operations for a particular entity class. Suppose we have our
Person
class:
@Entity public class Person { @Id private Long id; private String firstName; private String lastName; private Country nationality; //getters and setters... }
We can define a
personHome
component either through configuration:
<framework:entity-home name="personHome" entity-class="eg.Person" />
Or through extension:
@Name("personHome") public class PersonHome extends EntityHome<Person> {}
A Home object provides operations like
persist()
, remove()
, update()
and getInstance()
. Before you can call remove()
or update()
, you must set the identifier of the object you are interested in, using the setId()
method.
For example, we can use a Home directly from a JSF page:
<h1>Create Person</h1> <h:form> <div> First name: <h:inputText value="#{personHome.instance.firstName}"/> </div> <div> Last name: <h:inputText value="#{personHome.instance.lastName}"/> </div> <div> <h:commandButton value="Create Person" action="#{personHome.persist}"/> </div> </h:form>
It is useful to be able to refer to
Person
as person
, so we will add that line to components.xml
(if we are using configuration):
<factory name="person" value="#{personHome.instance}"/> <framework:entity-home name="personHome" entity-class="eg.Person" />
Or, if we are using extension, we can add a
@Factory
method to PersonHome
:
@Name("personHome") public class PersonHome extends EntityHome<Person> { @Factory("person") public Person initPerson() { return getInstance(); } }
This change simplifies our JSF page to the following:
<h1>Create Person</h1> <h:form> <div> First name: <h:inputText value="#{person.firstName}"/> </div> <div> Last name: <h:inputText value="#{person.lastName}"/> </div> <div> <h:commandButton value="Create Person" action="#{personHome.persist}"/> </div> </h:form>
This is all the code required to create new
Person
entries. If we want to be able to display, update, and delete pre-existing Person
entries in the database, we need to be able to pass the entry identifier to the PersonHome
. An excellent method is through page parameters:
<pages> <page view-id="/editPerson.jsp"> <param name="personId" value="#{personHome.id}"/> </page> </pages>
Now we can add the extra operations to our JSF page:
<h1> <h:outputText rendered="#{!personHome.managed}" value="Create Person"/> <h:outputText rendered="#{personHome.managed}" value="Edit Person"/> </h1> <h:form> <div> First name: <h:inputText value="#{person.firstName}"/> </div> <div> Last name: <h:inputText value="#{person.lastName}"/> </div> <div> <h:commandButton value="Create Person" action="#{personHome.persist}" rendered="#{!personHome.managed}"/> <h:commandButton value="Update Person" action="#{personHome.update}" rendered="#{personHome.managed}"/> <h:commandButton value="Delete Person" action="#{personHome.remove}" rendered="#{personHome.managed}"/> </div> </h:form>
When we link to the page with no request parameters, the page will be displayed as a Create Person page. When we provide a value for the
personId
request parameter, it will be an Edit Person page.
If we need to create
Person
entries with their nationality initialized, we can do so easily. Via configuration:
<factory name="person" value="#{personHome.instance}"/> <framework:entity-home name="personHome" entity-class="eg.Person" new-instance="#{newPerson}"/> <component name="newPerson" class="eg.Person"> <property name="nationality">#{country}</property> </component>
Or via extension:
@Name("personHome") public class PersonHome extends EntityHome<Person> { @In Country country; @Factory("person") public Person initPerson() { return getInstance(); } protected Person createInstance() { return new Person(country); } }
The
Country
could be an object managed by another Home object, for example, CountryHome
.
To add more sophisticated operations (association management, etc.), we simply add methods to
PersonHome
.
@Name("personHome") public class PersonHome extends EntityHome<Person> { @In Country country; @Factory("person") public Person initPerson() { return getInstance(); } protected Person createInstance() { return new Person(country); } public void migrate() { getInstance().setCountry(country); update(); } }
The Home object raises an
org.jboss.seam.afterTransactionSuccess
event when a transaction (a call to persist()
, update()
or remove()
) succeeds. By observing this event, we can refresh our querues when the underlying entities change. If we only want to refresh certain queries when a particular entry is persisted, updated, or removed, we can observe the org.jboss.seam.afterTransactionSuccess.<name>
(where <name>
is the name of the entity).
The Home object automatically displays Faces messages when an operation succeeds. To customize these messages we can, again, use configuration:
<factory name="person" value="#{personHome.instance}"/> <framework:entity-home name="personHome" entity-class="eg.Person" new-instance="#{newPerson}"> <framework:created-message> New person #{person.firstName} #{person.lastName} created </framework:created-message> <framework:deleted-message> Person #{person.firstName} #{person.lastName} deleted </framework:deleted-message> <framework:updated-message> Person #{person.firstName} #{person.lastName} updated </framework:updated-message> </framework:entity-home> <component name="newPerson" class="eg.Person"> <property name="nationality">#{country}</property> </component>
Or extension:
@Name("personHome") public class PersonHome extends EntityHome<Person> { @In Country country; @Factory("person") public Person initPerson() { return getInstance(); } protected Person createInstance() { return new Person(country); } protected String getCreatedMessage() { return createValueExpression("New person #{person.firstName} #{person.lastName} created"); } protected String getUpdatedMessage() { return createValueExpression("Person #{person.firstName} #{person.lastName} updated"); } protected String getDeletedMessage() { return createValueExpression("Person #{person.firstName} #{person.lastName} deleted"); } }
The best way to specify messages is to put them in a resource bundle known to Seam — by default, the bundle named
messages
.
Person_created=New person #{person.firstName} #{person.lastName} created Person_deleted=Person #{person.firstName} #{person.lastName} deleted Person_updated=Person #{person.firstName} #{person.lastName} updated
This enables internationalization, and keeps your code and configuration clean of presentation concerns.