| 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] |
|