At line 17 added 1 line. |
* [3] Configure Spring for this Manager and Transactions |
At line 20 changed 1 line. |
In [Part I|CreateDAO], we created a Person object and PersonDao - so let's continue developing this entity. First, let's create a JUnit test for the PersonManager. Create PersonManagerTest in the test/web/**/service directory. We'll want to test the same basic methods (get, save, remove) that our DAO has. |
In [Part I|CreateDAO], we created a Person object and PersonDao - so let's continue developing this entity. First, let's create a JUnit test for the PersonManager. Create PersonManagerTest in the test/service/**/service directory. We'll want to test the same basic methods (get, save, remove) that our DAO has. |
At line 24 changed 1 line. |
This class should extend [BaseManagerTestCase|http://raibledesigns.com/downloads/appfuse/api/org/appfuse/webapp/service/BaseManagerTestCase.java.html], which already exists in the ''service'' package. The parent class (BaseManagerTestCase) serves the same functionality as the BaseDaoTestCase - to load a properties file that has the same name as your *Test.class. |
This class should extend [BaseManagerTestCase|http://raibledesigns.com/downloads/appfuse/api/org/appfuse/service/BaseManagerTestCase.java.html], which already exists in the ''service'' package. The parent class (BaseManagerTestCase) serves the same functionality as the BaseDaoTestCase - to load a properties file that has the same name as your *Test.class, as well as to initialize Spring's ApplicationContext. |
At line 28 changed 1 line. |
The code below is what we need for a basic JUnit test of our Managers. It created and destroys our PersonManager. The "conn" object is initialized (and obtains a connection) in the [BaseManagerTestCase|http://raibledesigns.com/downloads/appfuse/api/org/appfuse/webapp/service/BaseManagerTestCase.java.html] class. |
The code below is what we need for a basic JUnit test of our Managers. It created and destroys our PersonManager. The "ctx" object is initialized in the [BaseManagerTestCase|http://raibledesigns.com/downloads/appfuse/api/org/appfuse/service/BaseManagerTestCase.java.html] class. |
At line 32 changed 1 line. |
package org.appfuse.webapp.service; |
package org.appfuse.service; |
At line 40 added 1 line. |
|
At line 42 added 4 lines. |
//~ Static fields/initializers ============================================= |
|
private PersonForm personForm; |
|
At line 44 removed 1 line. |
private PersonForm personForm; |
At line 46 removed 1 line. |
//~ Constructors =========================================================== |
At line 48 removed 4 lines. |
public PersonManagerTest(String name) { |
super(name); |
} |
|
At line 55 changed 2 lines. |
super.setUp(); |
mgr = new PersonManagerImpl(conn); |
mgr = (PersonManager) ctx.getBean("personManager"); |
At line 60 removed 1 line. |
super.tearDown(); |
At line 81 changed 6 lines. |
if (log.isDebugEnabled()) { |
log.debug(personForm); |
} |
|
assertTrue(personForm != null); |
assertTrue(personForm.getFirstName() != null); |
assertTrue("person.firstName not null", |
personForm.getFirstName() != null); |
At line 91 changed 1 line. |
personForm.setFirstName("Joe"); |
String name = personForm.getFirstName(); |
personForm.setFirstName("test"); |
At line 93 removed 4 lines. |
if (log.isDebugEnabled()) { |
log.debug("saving person with updated firstName: " + personForm); |
} |
|
At line 98 changed 1 line. |
assertTrue(personForm.getFirstName().equals("Joe")); |
assertTrue("name updated", personForm.getFirstName().equals("test")); |
|
personForm.setFirstName(name); |
mgr.savePerson(personForm); |
At line 103 removed 3 lines. |
|
// call populate method in super class to populate test data |
// from a properties file matching this class name |
At line 109 changed 1 line. |
assertTrue(personForm.getLastName().equals("Raible")); |
assertTrue(personForm.getFirstName().equals("Abbie")); |
assertTrue(personForm.getId() != null); |
At line 112 changed 1 line. |
log.debug("removing person..."); |
log.debug("removing personForm, personId: " + |
personForm.getId()); |
At line 116 changed 1 line. |
|
|
At line 130 changed 1 line. |
This class won't compile at this point because we have not created our PersonManager nor the PersonManagerImpl. Unlike the DAO class, I'm not using a Factory pattern. Rather, I'm instantiating new Managers using: |
This class won't compile at this point because we have not created our PersonManager interface. |
At line 132 removed 14 lines. |
[{Java2HtmlPlugin |
|
Manager mgr = new ManagerImp(conn); |
}] |
|
If I followed recommended patterns a bit more, I'd do: |
|
[{Java2HtmlPlugin |
|
Manager mgr = ManagerFactory.getInstance(conn, PersonManager.class); |
}] |
|
I don't have any reason for ''not doing'' the factory pattern on Managers, I just simply haven't done it. I __am__ creating Interfaces for the Managers - in case I decide I need new ManagerImpls someday. Then it'd be easy to create a Factory and different implementations. Someday I hope to dig into <a href="http://www.springframework.org/">Spring</a> to see if it can be my Factory to determine Managers for clients (Tests and Actions). |
|
At line 149 removed 1 line. |
First off, create a PersonManager.java interface in the src/web/**/service directory and specify the basic CRUD methods for any implementation classes. ''I've eliminated the JavaDocs in the class below for display purposes.'' |
At line 129 added 2 lines. |
First off, create a PersonManager.java interface in the src/service/**/service directory and specify the basic CRUD methods for any implementation classes. ''I've eliminated the JavaDocs in the class below for display purposes.'' |
|
At line 155 changed 1 line. |
package org.appfuse.webapp.service; |
package org.appfuse.service; |
At line 168 changed 1 line. |
to convert POJOs → ActionForms and ActionForms → POJOs. To do this, create a new class in src/web/**/service and name it PersonManagerImpl.java. It should extend BaseManager and implement PersonManager. |
to convert POJOs → ActionForms and ActionForms → POJOs. To do this, create a new class in src/service/**/service and name it PersonManagerImpl.java. It should extend BaseManager and implement PersonManager. |
At line 170 changed 1 line. |
;:''The [BaseManager|http://raibledesigns.com/downloads/appfuse/api/org/appfuse/webapp/service/BaseManager.java.html] is for registering different Converters (i.e. [DateConverter|http://raibledesigns.com/downloads/appfuse/api/org/appfuse/common/util/DateConverter.java.html]) so that BeanUtils.copyProperties knows how to convert Strings → Objects. It currently does not have any convenience methods, but does provide a nice place to add them for all your managers.'' |
;:''The [BaseManager|http://raibledesigns.com/downloads/appfuse/api/org/appfuse/service/BaseManager.java.html] is for registering different Converters (i.e. [DateConverter|http://raibledesigns.com/downloads/appfuse/api/org/appfuse/common/util/DateConverter.java.html]) so that BeanUtils.copyProperties knows how to convert Strings → Objects. It also provides a {{convert(Object)}} method that converts POJOs -> Forms and vise-versa. If you have Lists on your POJOs (i.e. for parent-child relationships), you will need to manually convert those if you want to work with indexed properties (see UserManagerImpl.java and the conversion of Roles for an example). |
At line 174 changed 1 line. |
package org.appfuse.webapp.service; |
package org.appfuse.service; |
At line 176 removed 2 lines. |
import org.apache.commons.beanutils.BeanUtils; |
import org.apache.commons.lang.ObjectUtils; |
At line 181 changed 2 lines. |
import org.appfuse.persistence.DAOFactory; |
import org.appfuse.persistence.Person; |
import org.appfuse.model.Person; |
At line 184 removed 1 line. |
import org.appfuse.webapp.form.PersonForm; |
At line 186 removed 2 lines. |
public class PersonManagerImpl extends BaseManager implements PersonManager { |
//~ Instance fields ======================================================== |
At line 163 added 1 line. |
public class PersonManagerImpl extends BaseManager implements PersonManager { |
At line 191 removed 2 lines. |
private Person person; |
private PersonForm personForm; |
At line 194 changed 5 lines. |
//~ Constructors =========================================================== |
|
public PersonManagerImpl(Object conn) |
throws Exception { |
dao = (PersonDao) DAOFactory.getInstance(conn, PersonDao.class); |
public void setPersonDao(PersonDao dao) { |
this.dao = dao; |
At line 201 removed 2 lines. |
//~ Methods ================================================================ |
|
At line 204 changed 6 lines. |
person = dao.getPerson(Long.valueOf(id)); |
|
personForm = new PersonForm(); |
BeanUtils.copyProperties(personForm, person); |
|
return personForm; |
Person person = dao.getPerson(Long.valueOf(id)); |
|
return convert(person); |
At line 213 changed 20 lines. |
if (person == null) { |
person = new Person(); |
} |
personForm = (PersonForm) obj; |
|
// copy form properties to person |
try { |
BeanUtils.copyProperties(person, personForm); |
} catch (IllegalArgumentException i) { |
log.error("Exception occured copying properties", i); |
throw new ConversionException(); |
} |
|
// BeanUtils.copyProperties converts empty Strings to |
// Longs with a value of 0 to prevent a NPE. |
// Setting the defaultLong to null (in BaseManager) is another solution |
if (ObjectUtils.equals(person.getId(), new Long(0))) { |
person.setId(null); |
} |
|
Person person = (Person) convert(obj); |
At line 235 changed 2 lines. |
return getPerson(person.getId().toString()); |
|
return convert(person); |
At line 240 changed 10 lines. |
if (person == null) { |
person = new Person(); |
} |
personForm = (PersonForm) obj; |
if (log.isDebugEnabled()) { |
log.debug("removing person: " + |
personForm.getFirstName() + " " + |
personForm.getLastName()); |
} |
|
Person person = (Person) convert(obj); |
At line 255 changed 1 line. |
You should be able to compile everything now using "ant compile-web"... |
One thing to note is the {{setPersonDao}} method. This is used by Spring to bind the PersonDao to this Manager. This is configured in the applicationContext-service.xml file. We'll get to configuring that in Step 3[3]. |
You should be able to compile everything now using "ant compile-service"... |
At line 275 changed 1 line. |
Finally, we need to create the PersonManagerTest.properties file in test/web/**/service so that {{personForm = (PersonForm) populate(personForm);}} will work in our test. |
Finally, we need to create the PersonManagerTest.properties file in test/service/**/service so that {{personForm = (PersonForm) populate(personForm);}} will work in our test. |
At line 277 changed 6 lines. |
;:''Duplicating (and renaming) the PersonDaoTest.properties is the easy route. Alternatively, you could set the properties manually. Make sure and add an __id__ property.'' |
{{{ |
firstName=Bill |
lastName=Joy |
}}} |
!!Run the ManagerTest [#3] |
;:''Duplicating (and renaming) the PersonDaoTest.properties is the easy route. Alternatively, you could set the properties manually.'' |
At line 216 added 32 lines. |
{{{firstName=Bill |
lastName=Joy}}} |
|
Now we need to edit Spring's config file for our services layer so it will know about this new Manager. |
|
!!Configure Spring for this Manager and Transactions [#3] |
|
To notify Spring of this our PersonManager interface and it's implementation, open the src/service/**/service/applicationContext-service.xml file. In here, you will see an existing configuration for the UserManager. You should be able to copy that and change a few things to get the XML fragment below. Add the following to the bottom of this file. |
|
[{Java2HtmlPlugin |
|
<!-- Person Manager: Struts implementation --> |
<bean id="personManagerTarget" class="org.appfuse.service.PersonManagerImpl" singleton="false"> |
<property name="personDao"><ref local="personDAO"/></property> |
</bean> |
|
<!-- Transaction declarations for business services. To apply a generic transaction proxy to |
all managers, you might look into using the BeanNameAutoProxyCreator --> |
<bean id="personManager" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> |
<property name="transactionManager"><ref local="transactionManager"/></property> |
<property name="target"><ref local="personManagerTarget"/></property> |
<property name="transactionAttributes"> |
<props> |
<prop key="save*">PROPAGATION_REQUIRED</prop> |
<prop key="remove*">PROPAGATION_REQUIRED</prop> |
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop> |
</props> |
</property> |
</bean> |
}] |
!!Run the ManagerTest [#4] |
|