From c9c8c4e085015b14ca6c3db077bac05e36859907 Mon Sep 17 00:00:00 2001 From: Mic <misvy@vmware.com> Date: Thu, 17 Jan 2013 15:27:27 +0800 Subject: [PATCH] moved the ClinicRepository into some separate repos There is still some polish up to be done. --- .../samples/petclinic/Clinic.java | 82 ----- .../samples/petclinic/Owner.java | 7 - .../petclinic/aspects/UsageLogAspect.java | 2 +- .../petclinic/jdbc/JdbcClinicImpl.java | 344 ------------------ .../petclinic/repository/OwnerRepository.java | 47 +++ .../petclinic/repository/PetRepository.java | 51 +++ .../petclinic/repository/VetRepository.java | 27 ++ .../petclinic/repository/VisitRepository.java | 30 ++ .../jdbc/JdbcClinicImplMBean.java | 6 +- .../jdbc/JdbcOwnerRepositoryImpl.java | 173 +++++++++ .../{ => repository}/jdbc/JdbcPet.java | 4 +- .../jdbc/JdbcPetRepositoryImpl.java | 160 ++++++++ .../repository/jdbc/JdbcPetRowMapper.java | 23 ++ .../jdbc/JdbcVetRepositoryImpl.java | 118 ++++++ .../jdbc/JdbcVisitRepositoryImpl.java | 131 +++++++ .../{ => repository}/jdbc/package-info.java | 2 +- .../{ => repository}/jpa/JpaClinicImpl.java | 8 +- .../jpa/JpaOwnerRepositoryImpl.java | 57 +++ .../jpa/SpringDataClinic.java | 6 +- .../jpa/SpringDataOwnerRepository.java | 13 + .../{ => repository}/jpa/package-info.java | 2 +- .../petclinic/service/ClinicService.java | 39 ++ .../petclinic/service/ClinicServiceImpl.java | 71 ++++ .../web/ClinicBindingInitializer.java | 6 +- .../petclinic/web/ClinicController.java | 99 ----- .../petclinic/web/OwnerController.java | 30 +- .../samples/petclinic/web/PetController.java | 24 +- .../samples/petclinic/web/PetTypeEditor.java | 10 +- .../samples/petclinic/web/VetController.java | 54 +++ .../petclinic/web/VisitController.java | 30 +- .../samples/petclinic/web/VisitsAtomView.java | 2 +- .../spring/applicationContext-dao.xml | 18 +- src/main/webapp/WEB-INF/petclinic-servlet.xml | 4 +- .../AbstractOwnerRepositoryTests.java | 147 ++++++++ ...s.java => AbstractPetRepositoryTests.java} | 122 ++----- .../petclinic/AbstractVetRepositoryTests.java | 107 ++++++ .../AbstractVisitRepositoryTests.java | 111 ++++++ .../aspects/UsageLogAspectTests.java | 15 +- .../jdbc/JdbcOwnerRepositoryImplTests.java | 29 ++ ...s.java => JdbcPetRepositoryImplTests.java} | 5 +- .../jdbc/JdbcVetRepositoryImplTests.java | 29 ++ .../jdbc/JdbcVisitRepositoryImplTests.java | 29 ++ ....java => JpaOwnerRepositoryImplTests.java} | 29 +- .../jpa/JpaPetRepositoryImplTests.java | 29 ++ .../jpa/JpaVetRepositoryImplTests.java | 29 ++ .../jpa/JpaVisitRepositoryImplTests.java | 29 ++ ...va => SpringDataOwnerRepositoryTests.java} | 4 +- 47 files changed, 1666 insertions(+), 728 deletions(-) delete mode 100644 src/main/java/org/springframework/samples/petclinic/Clinic.java delete mode 100644 src/main/java/org/springframework/samples/petclinic/jdbc/JdbcClinicImpl.java create mode 100644 src/main/java/org/springframework/samples/petclinic/repository/OwnerRepository.java create mode 100644 src/main/java/org/springframework/samples/petclinic/repository/PetRepository.java create mode 100644 src/main/java/org/springframework/samples/petclinic/repository/VetRepository.java create mode 100644 src/main/java/org/springframework/samples/petclinic/repository/VisitRepository.java rename src/main/java/org/springframework/samples/petclinic/{ => repository}/jdbc/JdbcClinicImplMBean.java (59%) create mode 100644 src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcOwnerRepositoryImpl.java rename src/main/java/org/springframework/samples/petclinic/{ => repository}/jdbc/JdbcPet.java (78%) create mode 100644 src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPetRepositoryImpl.java create mode 100644 src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPetRowMapper.java create mode 100644 src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcVetRepositoryImpl.java create mode 100644 src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcVisitRepositoryImpl.java rename src/main/java/org/springframework/samples/petclinic/{ => repository}/jdbc/package-info.java (62%) rename src/main/java/org/springframework/samples/petclinic/{ => repository}/jpa/JpaClinicImpl.java (89%) create mode 100644 src/main/java/org/springframework/samples/petclinic/repository/jpa/JpaOwnerRepositoryImpl.java rename src/main/java/org/springframework/samples/petclinic/{ => repository}/jpa/SpringDataClinic.java (83%) create mode 100644 src/main/java/org/springframework/samples/petclinic/repository/jpa/SpringDataOwnerRepository.java rename src/main/java/org/springframework/samples/petclinic/{ => repository}/jpa/package-info.java (62%) create mode 100644 src/main/java/org/springframework/samples/petclinic/service/ClinicService.java create mode 100644 src/main/java/org/springframework/samples/petclinic/service/ClinicServiceImpl.java delete mode 100644 src/main/java/org/springframework/samples/petclinic/web/ClinicController.java create mode 100644 src/main/java/org/springframework/samples/petclinic/web/VetController.java create mode 100644 src/test/java/org/springframework/samples/petclinic/AbstractOwnerRepositoryTests.java rename src/test/java/org/springframework/samples/petclinic/{AbstractClinicTests.java => AbstractPetRepositoryTests.java} (60%) create mode 100644 src/test/java/org/springframework/samples/petclinic/AbstractVetRepositoryTests.java create mode 100644 src/test/java/org/springframework/samples/petclinic/AbstractVisitRepositoryTests.java create mode 100644 src/test/java/org/springframework/samples/petclinic/jdbc/JdbcOwnerRepositoryImplTests.java rename src/test/java/org/springframework/samples/petclinic/jdbc/{JdbcClinicImplTests.java => JdbcPetRepositoryImplTests.java} (74%) create mode 100644 src/test/java/org/springframework/samples/petclinic/jdbc/JdbcVetRepositoryImplTests.java create mode 100644 src/test/java/org/springframework/samples/petclinic/jdbc/JdbcVisitRepositoryImplTests.java rename src/test/java/org/springframework/samples/petclinic/jpa/{JpaClinicImplTests.java => JpaOwnerRepositoryImplTests.java} (57%) create mode 100644 src/test/java/org/springframework/samples/petclinic/jpa/JpaPetRepositoryImplTests.java create mode 100644 src/test/java/org/springframework/samples/petclinic/jpa/JpaVetRepositoryImplTests.java create mode 100644 src/test/java/org/springframework/samples/petclinic/jpa/JpaVisitRepositoryImplTests.java rename src/test/java/org/springframework/samples/petclinic/jpa/{SpringDataClinicTests.java => SpringDataOwnerRepositoryTests.java} (75%) diff --git a/src/main/java/org/springframework/samples/petclinic/Clinic.java b/src/main/java/org/springframework/samples/petclinic/Clinic.java deleted file mode 100644 index 9eca087..0000000 --- a/src/main/java/org/springframework/samples/petclinic/Clinic.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.springframework.samples.petclinic; - -import java.util.Collection; - -import org.springframework.dao.DataAccessException; - -/** - * The high-level PetClinic business interface. - * - * <p>This is basically a data access object. - * PetClinic doesn't have a dedicated business facade. - * - * @author Ken Krebs - * @author Juergen Hoeller - * @author Sam Brannen - */ -public interface Clinic { - - /** - * Retrieve all <code>Vet</code>s from the data store. - * @return a <code>Collection</code> of <code>Vet</code>s - */ - Collection<Vet> getVets() throws DataAccessException; - - /** - * Retrieve all <code>PetType</code>s from the data store. - * @return a <code>Collection</code> of <code>PetType</code>s - */ - Collection<PetType> getPetTypes() throws DataAccessException; - - /** - * Retrieve <code>Owner</code>s from the data store by last name, - * returning all owners whose last name <i>starts</i> with the given name. - * @param lastName Value to search for - * @return a <code>Collection</code> of matching <code>Owner</code>s - * (or an empty <code>Collection</code> if none found) - */ - Collection<Owner> findOwners(String lastName) throws DataAccessException; - - /** - * Retrieve an <code>Owner</code> from the data store by id. - * @param id the id to search for - * @return the <code>Owner</code> if found - * @throws org.springframework.dao.DataRetrievalFailureException if not found - */ - Owner findOwner(int id) throws DataAccessException; - - /** - * Retrieve a <code>Pet</code> from the data store by id. - * @param id the id to search for - * @return the <code>Pet</code> if found - * @throws org.springframework.dao.DataRetrievalFailureException if not found - */ - Pet findPet(int id) throws DataAccessException; - - /** - * Save an <code>Owner</code> to the data store, either inserting or updating it. - * @param owner the <code>Owner</code> to save - * @see BaseEntity#isNew - */ - void storeOwner(Owner owner) throws DataAccessException; - - /** - * Save a <code>Pet</code> to the data store, either inserting or updating it. - * @param pet the <code>Pet</code> to save - * @see BaseEntity#isNew - */ - void storePet(Pet pet) throws DataAccessException; - - /** - * Save a <code>Visit</code> to the data store, either inserting or updating it. - * @param visit the <code>Visit</code> to save - * @see BaseEntity#isNew - */ - void storeVisit(Visit visit) throws DataAccessException; - - /** - * Deletes a <code>Pet</code> from the data store. - */ - void deletePet(int id) throws DataAccessException; - -} diff --git a/src/main/java/org/springframework/samples/petclinic/Owner.java b/src/main/java/org/springframework/samples/petclinic/Owner.java index 65e3df8..cb24f26 100644 --- a/src/main/java/org/springframework/samples/petclinic/Owner.java +++ b/src/main/java/org/springframework/samples/petclinic/Owner.java @@ -126,19 +126,12 @@ public class Owner extends Person { return new ToStringCreator(this) .append("id", this.getId()) - .append("new", this.isNew()) - .append("lastName", this.getLastName()) - .append("firstName", this.getFirstName()) - .append("address", this.address) - .append("city", this.city) - .append("telephone", this.telephone) - .toString(); } } diff --git a/src/main/java/org/springframework/samples/petclinic/aspects/UsageLogAspect.java b/src/main/java/org/springframework/samples/petclinic/aspects/UsageLogAspect.java index e326abf..b7fde37 100644 --- a/src/main/java/org/springframework/samples/petclinic/aspects/UsageLogAspect.java +++ b/src/main/java/org/springframework/samples/petclinic/aspects/UsageLogAspect.java @@ -9,7 +9,7 @@ import org.aspectj.lang.annotation.Before; /** * Sample AspectJ annotation-style aspect that saves - * every owner name requested to the clinic. + * every owner name requested to the petRepository. * * @author Rod Johnson * @author Juergen Hoeller diff --git a/src/main/java/org/springframework/samples/petclinic/jdbc/JdbcClinicImpl.java b/src/main/java/org/springframework/samples/petclinic/jdbc/JdbcClinicImpl.java deleted file mode 100644 index ecd8cb1..0000000 --- a/src/main/java/org/springframework/samples/petclinic/jdbc/JdbcClinicImpl.java +++ /dev/null @@ -1,344 +0,0 @@ -package org.springframework.samples.petclinic.jdbc; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import javax.sql.DataSource; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DataAccessException; -import org.springframework.dao.EmptyResultDataAccessException; -import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; -import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; -import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; -import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper; -import org.springframework.jdbc.core.simple.ParameterizedRowMapper; -import org.springframework.jdbc.core.simple.SimpleJdbcInsert; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jmx.export.annotation.ManagedOperation; -import org.springframework.jmx.export.annotation.ManagedResource; -import org.springframework.orm.ObjectRetrievalFailureException; -import org.springframework.samples.petclinic.Clinic; -import org.springframework.samples.petclinic.Owner; -import org.springframework.samples.petclinic.Pet; -import org.springframework.samples.petclinic.PetType; -import org.springframework.samples.petclinic.Specialty; -import org.springframework.samples.petclinic.Vet; -import org.springframework.samples.petclinic.Visit; -import org.springframework.samples.petclinic.util.EntityUtils; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** - * A simple JDBC-based implementation of the {@link Clinic} interface. - * - * <p>This class uses Java 5 language features and the {@link SimpleJdbcTemplate} - * plus {@link SimpleJdbcInsert}. It also takes advantage of classes like - * {@link BeanPropertySqlParameterSource} and - * {@link ParameterizedBeanPropertyRowMapper} which provide automatic mapping - * between JavaBean properties and JDBC parameters or query results. - * - * <p>JdbcClinicImpl is a rewrite of the AbstractJdbcClinic which was the base - * class for JDBC implementations of the Clinic interface for Spring 2.0. - * - * @author Ken Krebs - * @author Juergen Hoeller - * @author Rob Harrop - * @author Sam Brannen - * @author Thomas Risberg - * @author Mark Fisher - */ -@Service -@ManagedResource("petclinic:type=Clinic") -public class JdbcClinicImpl implements Clinic, JdbcClinicImplMBean { - - private final Logger logger = LoggerFactory.getLogger(getClass()); - - private JdbcTemplate jdbcTemplate; - private NamedParameterJdbcTemplate namedParameterJdbcTemplate; - - private SimpleJdbcInsert insertOwner; - private SimpleJdbcInsert insertPet; - private SimpleJdbcInsert insertVisit; - - private final List<Vet> vets = new ArrayList<Vet>(); - - - @Autowired - public void init(DataSource dataSource) { - this.jdbcTemplate = new JdbcTemplate(dataSource); - this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); - - this.insertOwner = new SimpleJdbcInsert(dataSource) - .withTableName("owners") - .usingGeneratedKeyColumns("id"); - this.insertPet = new SimpleJdbcInsert(dataSource) - .withTableName("pets") - .usingGeneratedKeyColumns("id"); - this.insertVisit = new SimpleJdbcInsert(dataSource) - .withTableName("visits") - .usingGeneratedKeyColumns("id"); - } - - - /** - * Refresh the cache of Vets that the Clinic is holding. - * @see org.springframework.samples.petclinic.Clinic#getVets() - */ - @ManagedOperation - @Transactional(readOnly = true) - public void refreshVetsCache() throws DataAccessException { - synchronized (this.vets) { - this.logger.info("Refreshing vets cache"); - - // Retrieve the list of all vets. - this.vets.clear(); - this.vets.addAll(this.jdbcTemplate.query( - "SELECT id, first_name, last_name FROM vets ORDER BY last_name,first_name", - ParameterizedBeanPropertyRowMapper.newInstance(Vet.class))); - - // Retrieve the list of all possible specialties. - final List<Specialty> specialties = this.jdbcTemplate.query( - "SELECT id, name FROM specialties", - ParameterizedBeanPropertyRowMapper.newInstance(Specialty.class)); - - // Build each vet's list of specialties. - for (Vet vet : this.vets) { - final List<Integer> vetSpecialtiesIds = this.jdbcTemplate.query( - "SELECT specialty_id FROM vet_specialties WHERE vet_id=?", - new ParameterizedRowMapper<Integer>() { - public Integer mapRow(ResultSet rs, int row) throws SQLException { - return Integer.valueOf(rs.getInt(1)); - }}, - vet.getId().intValue()); - for (int specialtyId : vetSpecialtiesIds) { - Specialty specialty = EntityUtils.getById(specialties, Specialty.class, specialtyId); - vet.addSpecialty(specialty); - } - } - } - } - - - // START of Clinic implementation section ******************************* - - @Transactional(readOnly = true) - public Collection<Vet> getVets() throws DataAccessException { - synchronized (this.vets) { - if (this.vets.isEmpty()) { - refreshVetsCache(); - } - return this.vets; - } - } - - @Transactional(readOnly = true) - public Collection<PetType> getPetTypes() throws DataAccessException { - return this.jdbcTemplate.query( - "SELECT id, name FROM types ORDER BY name", - ParameterizedBeanPropertyRowMapper.newInstance(PetType.class)); - } - - /** - * Loads {@link Owner Owners} from the data store by last name, returning - * all owners whose last name <i>starts</i> with the given name; also loads - * the {@link Pet Pets} and {@link Visit Visits} for the corresponding - * owners, if not already loaded. - */ - @Transactional(readOnly = true) - public Collection<Owner> findOwners(String lastName) throws DataAccessException { - List<Owner> owners = this.jdbcTemplate.query( - "SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE last_name like ?", - ParameterizedBeanPropertyRowMapper.newInstance(Owner.class), - lastName + "%"); - loadOwnersPetsAndVisits(owners); - return owners; - } - - /** - * Loads the {@link Owner} with the supplied <code>id</code>; also loads - * the {@link Pet Pets} and {@link Visit Visits} for the corresponding - * owner, if not already loaded. - */ - @Transactional(readOnly = true) - public Owner findOwner(int id) throws DataAccessException { - Owner owner; - try { - owner = this.jdbcTemplate.queryForObject( - "SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE id=?", - ParameterizedBeanPropertyRowMapper.newInstance(Owner.class), - id); - } - catch (EmptyResultDataAccessException ex) { - throw new ObjectRetrievalFailureException(Owner.class, new Integer(id)); - } - loadPetsAndVisits(owner); - return owner; - } - - @Transactional(readOnly = true) - public Pet findPet(int id) throws DataAccessException { - JdbcPet pet; - try { - pet = this.jdbcTemplate.queryForObject( - "SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE id=?", - new JdbcPetRowMapper(), - id); - } - catch (EmptyResultDataAccessException ex) { - throw new ObjectRetrievalFailureException(Pet.class, new Integer(id)); - } - Owner owner = findOwner(pet.getOwnerId()); - owner.addPet(pet); - pet.setType(EntityUtils.getById(getPetTypes(), PetType.class, pet.getTypeId())); - loadVisits(pet); - return pet; - } - - @Transactional - public void storeOwner(Owner owner) throws DataAccessException { - if (owner.isNew()) { - Number newKey = this.insertOwner.executeAndReturnKey( - new BeanPropertySqlParameterSource(owner)); - owner.setId(newKey.intValue()); - } - else { - this.namedParameterJdbcTemplate.update( - "UPDATE owners SET first_name=:firstName, last_name=:lastName, address=:address, " + - "city=:city, telephone=:telephone WHERE id=:id", - new BeanPropertySqlParameterSource(owner)); - } - } - - @Transactional - public void storePet(Pet pet) throws DataAccessException { - if (pet.isNew()) { - Number newKey = this.insertPet.executeAndReturnKey( - createPetParameterSource(pet)); - pet.setId(newKey.intValue()); - } - else { - this.namedParameterJdbcTemplate.update( - "UPDATE pets SET name=:name, birth_date=:birth_date, type_id=:type_id, " + - "owner_id=:owner_id WHERE id=:id", - createPetParameterSource(pet)); - } - } - - @Transactional - public void storeVisit(Visit visit) throws DataAccessException { - if (visit.isNew()) { - Number newKey = this.insertVisit.executeAndReturnKey( - createVisitParameterSource(visit)); - visit.setId(newKey.intValue()); - } - else { - throw new UnsupportedOperationException("Visit update not supported"); - } - } - - public void deletePet(int id) throws DataAccessException { - this.jdbcTemplate.update("DELETE FROM pets WHERE id=?", id); - } - - // END of Clinic implementation section ************************************ - - - /** - * Creates a {@link MapSqlParameterSource} based on data values from the - * supplied {@link Pet} instance. - */ - private MapSqlParameterSource createPetParameterSource(Pet pet) { - return new MapSqlParameterSource() - .addValue("id", pet.getId()) - .addValue("name", pet.getName()) - .addValue("birth_date", pet.getBirthDate()) - .addValue("type_id", pet.getType().getId()) - .addValue("owner_id", pet.getOwner().getId()); - } - - /** - * Creates a {@link MapSqlParameterSource} based on data values from the - * supplied {@link Visit} instance. - */ - private MapSqlParameterSource createVisitParameterSource(Visit visit) { - return new MapSqlParameterSource() - .addValue("id", visit.getId()) - .addValue("visit_date", visit.getDate()) - .addValue("description", visit.getDescription()) - .addValue("pet_id", visit.getPet().getId()); - } - - /** - * Loads the {@link Visit} data for the supplied {@link Pet}. - */ - private void loadVisits(JdbcPet pet) { - final List<Visit> visits = this.jdbcTemplate.query( - "SELECT id, visit_date, description FROM visits WHERE pet_id=?", - new ParameterizedRowMapper<Visit>() { - public Visit mapRow(ResultSet rs, int row) throws SQLException { - Visit visit = new Visit(); - visit.setId(rs.getInt("id")); - visit.setDate(rs.getTimestamp("visit_date")); - visit.setDescription(rs.getString("description")); - return visit; - } - }, - pet.getId().intValue()); - for (Visit visit : visits) { - pet.addVisit(visit); - } - } - - /** - * Loads the {@link Pet} and {@link Visit} data for the supplied - * {@link Owner}. - */ - private void loadPetsAndVisits(final Owner owner) { - final List<JdbcPet> pets = this.jdbcTemplate.query( - "SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE owner_id=?", - new JdbcPetRowMapper(), - owner.getId().intValue()); - for (JdbcPet pet : pets) { - owner.addPet(pet); - pet.setType(EntityUtils.getById(getPetTypes(), PetType.class, pet.getTypeId())); - loadVisits(pet); - } - } - - /** - * Loads the {@link Pet} and {@link Visit} data for the supplied - * {@link List} of {@link Owner Owners}. - * - * @param owners the list of owners for whom the pet and visit data should be loaded - * @see #loadPetsAndVisits(Owner) - */ - private void loadOwnersPetsAndVisits(List<Owner> owners) { - for (Owner owner : owners) { - loadPetsAndVisits(owner); - } - } - - /** - * {@link ParameterizedRowMapper} implementation mapping data from a - * {@link ResultSet} to the corresponding properties of the {@link JdbcPet} class. - */ - private class JdbcPetRowMapper implements ParameterizedRowMapper<JdbcPet> { - - public JdbcPet mapRow(ResultSet rs, int rownum) throws SQLException { - JdbcPet pet = new JdbcPet(); - pet.setId(rs.getInt("id")); - pet.setName(rs.getString("name")); - pet.setBirthDate(rs.getDate("birth_date")); - pet.setTypeId(rs.getInt("type_id")); - pet.setOwnerId(rs.getInt("owner_id")); - return pet; - } - } - -} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/OwnerRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/OwnerRepository.java new file mode 100644 index 0000000..4a24d54 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/OwnerRepository.java @@ -0,0 +1,47 @@ +package org.springframework.samples.petclinic.repository; + +import java.util.Collection; + +import org.springframework.dao.DataAccessException; +import org.springframework.samples.petclinic.BaseEntity; +import org.springframework.samples.petclinic.Owner; + +/** + * The high-level PetClinic business interface. + * + * <p>This is basically a data access object. + * PetClinic doesn't have a dedicated business facade. + * + * @author Ken Krebs + * @author Juergen Hoeller + * @author Sam Brannen + */ +public interface OwnerRepository { + + /** + * Retrieve <code>Owner</code>s from the data store by last name, + * returning all owners whose last name <i>starts</i> with the given name. + * @param lastName Value to search for + * @return a <code>Collection</code> of matching <code>Owner</code>s + * (or an empty <code>Collection</code> if none found) + */ + Collection<Owner> findByLastName(String lastName) throws DataAccessException; + + /** + * Retrieve an <code>Owner</code> from the data store by id. + * @param id the id to search for + * @return the <code>Owner</code> if found + * @throws org.springframework.dao.DataRetrievalFailureException if not found + */ + Owner findById(int id) throws DataAccessException; + + + /** + * Save an <code>Owner</code> to the data store, either inserting or updating it. + * @param owner the <code>Owner</code> to save + * @see BaseEntity#isNew + */ + void save(Owner owner) throws DataAccessException; + + +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/PetRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/PetRepository.java new file mode 100644 index 0000000..119e0e3 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/PetRepository.java @@ -0,0 +1,51 @@ +package org.springframework.samples.petclinic.repository; + +import java.util.Collection; + +import org.springframework.dao.DataAccessException; +import org.springframework.samples.petclinic.BaseEntity; +import org.springframework.samples.petclinic.Owner; +import org.springframework.samples.petclinic.Pet; +import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.Vet; +import org.springframework.samples.petclinic.Visit; + +/** + * The high-level PetClinic business interface. + * + * <p>This is basically a data access object. + * PetClinic doesn't have a dedicated business facade. + * + * @author Ken Krebs + * @author Juergen Hoeller + * @author Sam Brannen + */ +public interface PetRepository { + + /** + * Retrieve all <code>PetType</code>s from the data store. + * @return a <code>Collection</code> of <code>PetType</code>s + */ + Collection<PetType> getPetTypes() throws DataAccessException; + + /** + * Retrieve a <code>Pet</code> from the data store by id. + * @param id the id to search for + * @return the <code>Pet</code> if found + * @throws org.springframework.dao.DataRetrievalFailureException if not found + */ + Pet findById(int id) throws DataAccessException; + + /** + * Save a <code>Pet</code> to the data store, either inserting or updating it. + * @param pet the <code>Pet</code> to save + * @see BaseEntity#isNew + */ + void storePet(Pet pet) throws DataAccessException; + + /** + * Deletes a <code>Pet</code> from the data store. + */ + void deletePet(int id) throws DataAccessException; + +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/VetRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/VetRepository.java new file mode 100644 index 0000000..a306860 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/VetRepository.java @@ -0,0 +1,27 @@ +package org.springframework.samples.petclinic.repository; + +import java.util.Collection; + +import org.springframework.dao.DataAccessException; +import org.springframework.samples.petclinic.Vet; + +/** + * The high-level PetClinic business interface. + * + * <p>This is basically a data access object. + * PetClinic doesn't have a dedicated business facade. + * + * @author Ken Krebs + * @author Juergen Hoeller + * @author Sam Brannen + */ +public interface VetRepository { + + /** + * Retrieve all <code>Vet</code>s from the data store. + * @return a <code>Collection</code> of <code>Vet</code>s + */ + Collection<Vet> getVets() throws DataAccessException; + + +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/VisitRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/VisitRepository.java new file mode 100644 index 0000000..2af5ac7 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/VisitRepository.java @@ -0,0 +1,30 @@ +package org.springframework.samples.petclinic.repository; + +import java.util.List; + +import org.springframework.dao.DataAccessException; +import org.springframework.samples.petclinic.BaseEntity; +import org.springframework.samples.petclinic.Visit; + +/** + * The high-level PetClinic business interface. + * + * <p>This is basically a data access object. + * PetClinic doesn't have a dedicated business facade. + * + * @author Ken Krebs + * @author Juergen Hoeller + * @author Sam Brannen + */ +public interface VisitRepository { + + /** + * Save a <code>Visit</code> to the data store, either inserting or updating it. + * @param visit the <code>Visit</code> to save + * @see BaseEntity#isNew + */ + void storeVisit(Visit visit) throws DataAccessException; + + List<Visit> findByPetId(Integer petId); + +} diff --git a/src/main/java/org/springframework/samples/petclinic/jdbc/JdbcClinicImplMBean.java b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcClinicImplMBean.java similarity index 59% rename from src/main/java/org/springframework/samples/petclinic/jdbc/JdbcClinicImplMBean.java rename to src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcClinicImplMBean.java index 6eaa97c..b324036 100644 --- a/src/main/java/org/springframework/samples/petclinic/jdbc/JdbcClinicImplMBean.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcClinicImplMBean.java @@ -1,4 +1,4 @@ -package org.springframework.samples.petclinic.jdbc; +package org.springframework.samples.petclinic.repository.jdbc; /** * Interface that defines a cache refresh operation. @@ -11,8 +11,8 @@ package org.springframework.samples.petclinic.jdbc; public interface JdbcClinicImplMBean { /** - * Refresh the cache of Vets that the Clinic is holding. - * @see org.springframework.samples.petclinic.Clinic#getVets() + * Refresh the cache of Vets that the ClinicService is holding. + * @see org.springframework.samples.petclinic.service.ClinicService#getVets() * @see JdbcClinicImpl#refreshVetsCache() */ void refreshVetsCache(); diff --git a/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcOwnerRepositoryImpl.java b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcOwnerRepositoryImpl.java new file mode 100644 index 0000000..eef9dfd --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcOwnerRepositoryImpl.java @@ -0,0 +1,173 @@ +package org.springframework.samples.petclinic.repository.jdbc; + +import java.util.Collection; +import java.util.List; + +import javax.sql.DataSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.orm.ObjectRetrievalFailureException; +import org.springframework.samples.petclinic.Owner; +import org.springframework.samples.petclinic.Pet; +import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.Visit; +import org.springframework.samples.petclinic.repository.OwnerRepository; +import org.springframework.samples.petclinic.repository.PetRepository; +import org.springframework.samples.petclinic.repository.VisitRepository; +import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.samples.petclinic.util.EntityUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * A simple JDBC-based implementation of the {@link ClinicService} interface. + * + * <p>This class uses Java 5 language features and the {@link SimpleJdbcTemplate} + * plus {@link SimpleJdbcInsert}. It also takes advantage of classes like + * {@link BeanPropertySqlParameterSource} and + * {@link ParameterizedBeanPropertyRowMapper} which provide automatic mapping + * between JavaBean properties and JDBC parameters or query results. + * + * <p>JdbcClinicImpl is a rewrite of the AbstractJdbcClinic which was the base + * class for JDBC implementations of the ClinicService interface for Spring 2.0. + * + * @author Ken Krebs + * @author Juergen Hoeller + * @author Rob Harrop + * @author Sam Brannen + * @author Thomas Risberg + * @author Mark Fisher + */ +@Service +public class JdbcOwnerRepositoryImpl implements OwnerRepository { + + @Autowired + private PetRepository petRepository; + + @Autowired + private VisitRepository visitRepository; + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Autowired + private NamedParameterJdbcTemplate namedParameterJdbcTemplate; + + private SimpleJdbcInsert insertOwner; + + @Autowired + public void init(DataSource dataSource) { + + this.insertOwner = new SimpleJdbcInsert(dataSource) + .withTableName("owners") + .usingGeneratedKeyColumns("id"); + } + + + + + /** + * Loads {@link Owner Owners} from the data store by last name, returning + * all owners whose last name <i>starts</i> with the given name; also loads + * the {@link Pet Pets} and {@link Visit Visits} for the corresponding + * owners, if not already loaded. + */ + @Transactional(readOnly = true) + public Collection<Owner> findByLastName(String lastName) throws DataAccessException { + List<Owner> owners = this.jdbcTemplate.query( + "SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE last_name like ?", + ParameterizedBeanPropertyRowMapper.newInstance(Owner.class), + lastName + "%"); + loadOwnersPetsAndVisits(owners); + return owners; + } + + /** + * Loads the {@link Owner} with the supplied <code>id</code>; also loads + * the {@link Pet Pets} and {@link Visit Visits} for the corresponding + * owner, if not already loaded. + */ + @Transactional(readOnly = true) + public Owner findById(int id) throws DataAccessException { + Owner owner; + try { + owner = this.jdbcTemplate.queryForObject( + "SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE id=?", + ParameterizedBeanPropertyRowMapper.newInstance(Owner.class), + id); + } + catch (EmptyResultDataAccessException ex) { + throw new ObjectRetrievalFailureException(Owner.class, new Integer(id)); + } + loadPetsAndVisits(owner); + return owner; + } + + public void loadPetsAndVisits(final Owner owner) { + final List<JdbcPet> pets = this.jdbcTemplate.query( + "SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE owner_id=?", + new JdbcPetRowMapper(), + owner.getId().intValue()); + for (JdbcPet pet : pets) { + owner.addPet(pet); + pet.setType(EntityUtils.getById(getPetTypes(), PetType.class, pet.getTypeId())); + List<Visit> visits = this.visitRepository.findByPetId(pet.getId()); + for (Visit visit : visits) { + pet.addVisit(visit); + } + } + } + + + + @Transactional + public void save(Owner owner) throws DataAccessException { + if (owner.isNew()) { + Number newKey = this.insertOwner.executeAndReturnKey( + new BeanPropertySqlParameterSource(owner)); + owner.setId(newKey.intValue()); + } + else { + this.namedParameterJdbcTemplate.update( + "UPDATE owners SET first_name=:firstName, last_name=:lastName, address=:address, " + + "city=:city, telephone=:telephone WHERE id=:id", + new BeanPropertySqlParameterSource(owner)); + } + } + + + + + + @Transactional(readOnly = true) + public Collection<PetType> getPetTypes() throws DataAccessException { + return this.jdbcTemplate.query( + "SELECT id, name FROM types ORDER BY name", + ParameterizedBeanPropertyRowMapper.newInstance(PetType.class)); + } + + /** + * Loads the {@link Pet} and {@link Visit} data for the supplied + * {@link List} of {@link Owner Owners}. + * + * @param owners the list of owners for whom the pet and visit data should be loaded + * @see #loadPetsAndVisits(Owner) + */ + private void loadOwnersPetsAndVisits(List<Owner> owners) { + for (Owner owner : owners) { + loadPetsAndVisits(owner); + } + } + + +} diff --git a/src/main/java/org/springframework/samples/petclinic/jdbc/JdbcPet.java b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPet.java similarity index 78% rename from src/main/java/org/springframework/samples/petclinic/jdbc/JdbcPet.java rename to src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPet.java index aa0bf18..4a9ccf3 100644 --- a/src/main/java/org/springframework/samples/petclinic/jdbc/JdbcPet.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPet.java @@ -1,10 +1,10 @@ -package org.springframework.samples.petclinic.jdbc; +package org.springframework.samples.petclinic.repository.jdbc; import org.springframework.samples.petclinic.Pet; /** * Subclass of Pet that carries temporary id properties which - * are only relevant for a JDBC implmentation of the Clinic. + * are only relevant for a JDBC implmentation of the ClinicService. * * @author Juergen Hoeller * @see JdbcClinicImpl diff --git a/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPetRepositoryImpl.java b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPetRepositoryImpl.java new file mode 100644 index 0000000..6efff5f --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPetRepositoryImpl.java @@ -0,0 +1,160 @@ +package org.springframework.samples.petclinic.repository.jdbc; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.sql.DataSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper; +import org.springframework.jdbc.core.simple.ParameterizedRowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jmx.export.annotation.ManagedOperation; +import org.springframework.jmx.export.annotation.ManagedResource; +import org.springframework.orm.ObjectRetrievalFailureException; +import org.springframework.samples.petclinic.Owner; +import org.springframework.samples.petclinic.Pet; +import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.Specialty; +import org.springframework.samples.petclinic.Vet; +import org.springframework.samples.petclinic.Visit; +import org.springframework.samples.petclinic.repository.OwnerRepository; +import org.springframework.samples.petclinic.repository.PetRepository; +import org.springframework.samples.petclinic.repository.VisitRepository; +import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.samples.petclinic.util.EntityUtils; +import org.springframework.stereotype.Repository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * A simple JDBC-based implementation of the {@link ClinicService} interface. + * + * <p>This class uses Java 5 language features and the {@link SimpleJdbcTemplate} + * plus {@link SimpleJdbcInsert}. It also takes advantage of classes like + * {@link BeanPropertySqlParameterSource} and + * {@link ParameterizedBeanPropertyRowMapper} which provide automatic mapping + * between JavaBean properties and JDBC parameters or query results. + * + * <p>JdbcClinicImpl is a rewrite of the AbstractJdbcClinic which was the base + * class for JDBC implementations of the ClinicService interface for Spring 2.0. + * + * @author Ken Krebs + * @author Juergen Hoeller + * @author Rob Harrop + * @author Sam Brannen + * @author Thomas Risberg + * @author Mark Fisher + */ +@Repository +public class JdbcPetRepositoryImpl implements PetRepository { + + private JdbcTemplate jdbcTemplate; + private NamedParameterJdbcTemplate namedParameterJdbcTemplate; + + private SimpleJdbcInsert insertPet; + + @Autowired + private OwnerRepository ownerRepository; + + @Autowired + private VisitRepository visitRepository; + + private final List<Vet> vets = new ArrayList<Vet>(); + + + @Autowired + public void init(DataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); + + this.insertPet = new SimpleJdbcInsert(dataSource) + .withTableName("pets") + .usingGeneratedKeyColumns("id"); + } + + @Transactional(readOnly = true) + public Collection<PetType> getPetTypes() throws DataAccessException { + return this.jdbcTemplate.query( + "SELECT id, name FROM types ORDER BY name", + ParameterizedBeanPropertyRowMapper.newInstance(PetType.class)); + } + + @Transactional(readOnly = true) + public Pet findById(int id) throws DataAccessException { + JdbcPet pet; + try { + pet = this.jdbcTemplate.queryForObject( + "SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE id=?", + new JdbcPetRowMapper(), + id); + } + catch (EmptyResultDataAccessException ex) { + throw new ObjectRetrievalFailureException(Pet.class, new Integer(id)); + } + Owner owner = this.ownerRepository.findById(pet.getOwnerId()); + owner.addPet(pet); + pet.setType(EntityUtils.getById(getPetTypes(), PetType.class, pet.getTypeId())); + + List<Visit> visits = this.visitRepository.findByPetId(pet.getId()); + for (Visit visit : visits) { + pet.addVisit(visit); + } + return pet; + } + + @Transactional + public void storePet(Pet pet) throws DataAccessException { + if (pet.isNew()) { + Number newKey = this.insertPet.executeAndReturnKey( + createPetParameterSource(pet)); + pet.setId(newKey.intValue()); + } + else { + this.namedParameterJdbcTemplate.update( + "UPDATE pets SET name=:name, birth_date=:birth_date, type_id=:type_id, " + + "owner_id=:owner_id WHERE id=:id", + createPetParameterSource(pet)); + } + } + + /** + * Creates a {@link MapSqlParameterSource} based on data values from the + * supplied {@link Pet} instance. + */ + private MapSqlParameterSource createPetParameterSource(Pet pet) { + return new MapSqlParameterSource() + .addValue("id", pet.getId()) + .addValue("name", pet.getName()) + .addValue("birth_date", pet.getBirthDate()) + .addValue("type_id", pet.getType().getId()) + .addValue("owner_id", pet.getOwner().getId()); + } + + @Override + public void deletePet(int id) throws DataAccessException { + // TODO Auto-generated method stub + + } + + + /** + * Loads the {@link Pet} and {@link Visit} data for the supplied + * {@link Owner}. + */ + + + + +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPetRowMapper.java b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPetRowMapper.java new file mode 100644 index 0000000..575f460 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPetRowMapper.java @@ -0,0 +1,23 @@ +package org.springframework.samples.petclinic.repository.jdbc; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.springframework.jdbc.core.simple.ParameterizedRowMapper; + +/** + * {@link ParameterizedRowMapper} implementation mapping data from a + * {@link ResultSet} to the corresponding properties of the {@link JdbcPet} class. + */ +class JdbcPetRowMapper implements ParameterizedRowMapper<JdbcPet> { + + public JdbcPet mapRow(ResultSet rs, int rownum) throws SQLException { + JdbcPet pet = new JdbcPet(); + pet.setId(rs.getInt("id")); + pet.setName(rs.getString("name")); + pet.setBirthDate(rs.getDate("birth_date")); + pet.setTypeId(rs.getInt("type_id")); + pet.setOwnerId(rs.getInt("owner_id")); + return pet; + } +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcVetRepositoryImpl.java b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcVetRepositoryImpl.java new file mode 100644 index 0000000..88b8c03 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcVetRepositoryImpl.java @@ -0,0 +1,118 @@ +package org.springframework.samples.petclinic.repository.jdbc; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.sql.DataSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper; +import org.springframework.jdbc.core.simple.ParameterizedRowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jmx.export.annotation.ManagedOperation; +import org.springframework.jmx.export.annotation.ManagedResource; +import org.springframework.orm.ObjectRetrievalFailureException; +import org.springframework.samples.petclinic.Owner; +import org.springframework.samples.petclinic.Pet; +import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.Specialty; +import org.springframework.samples.petclinic.Vet; +import org.springframework.samples.petclinic.Visit; +import org.springframework.samples.petclinic.repository.VetRepository; +import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.samples.petclinic.util.EntityUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * A simple JDBC-based implementation of the {@link ClinicService} interface. + * + * <p>This class uses Java 5 language features and the {@link SimpleJdbcTemplate} + * plus {@link SimpleJdbcInsert}. It also takes advantage of classes like + * {@link BeanPropertySqlParameterSource} and + * {@link ParameterizedBeanPropertyRowMapper} which provide automatic mapping + * between JavaBean properties and JDBC parameters or query results. + * + * <p>JdbcClinicImpl is a rewrite of the AbstractJdbcClinic which was the base + * class for JDBC implementations of the ClinicService interface for Spring 2.0. + * + * @author Ken Krebs + * @author Juergen Hoeller + * @author Rob Harrop + * @author Sam Brannen + * @author Thomas Risberg + * @author Mark Fisher + */ +@Service +public class JdbcVetRepositoryImpl implements VetRepository { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private JdbcTemplate jdbcTemplate; + + private final List<Vet> vets = new ArrayList<Vet>(); + + + + /** + * Refresh the cache of Vets that the ClinicService is holding. + * @see org.springframework.samples.petclinic.service.ClinicService#getVets() + */ + @ManagedOperation + @Transactional(readOnly = true) + public void refreshVetsCache() throws DataAccessException { + synchronized (this.vets) { + this.logger.info("Refreshing vets cache"); + + // Retrieve the list of all vets. + this.vets.clear(); + this.vets.addAll(this.jdbcTemplate.query( + "SELECT id, first_name, last_name FROM vets ORDER BY last_name,first_name", + ParameterizedBeanPropertyRowMapper.newInstance(Vet.class))); + + // Retrieve the list of all possible specialties. + final List<Specialty> specialties = this.jdbcTemplate.query( + "SELECT id, name FROM specialties", + ParameterizedBeanPropertyRowMapper.newInstance(Specialty.class)); + + // Build each vet's list of specialties. + for (Vet vet : this.vets) { + final List<Integer> vetSpecialtiesIds = this.jdbcTemplate.query( + "SELECT specialty_id FROM vet_specialties WHERE vet_id=?", + new ParameterizedRowMapper<Integer>() { + public Integer mapRow(ResultSet rs, int row) throws SQLException { + return Integer.valueOf(rs.getInt(1)); + }}, + vet.getId().intValue()); + for (int specialtyId : vetSpecialtiesIds) { + Specialty specialty = EntityUtils.getById(specialties, Specialty.class, specialtyId); + vet.addSpecialty(specialty); + } + } + } + } + + @Transactional(readOnly = true) + public Collection<Vet> getVets() throws DataAccessException { + synchronized (this.vets) { + if (this.vets.isEmpty()) { + refreshVetsCache(); + } + return this.vets; + } + } + + +} diff --git a/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcVisitRepositoryImpl.java b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcVisitRepositoryImpl.java new file mode 100644 index 0000000..f1cc60b --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcVisitRepositoryImpl.java @@ -0,0 +1,131 @@ +package org.springframework.samples.petclinic.repository.jdbc; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +import javax.sql.DataSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper; +import org.springframework.jdbc.core.simple.ParameterizedRowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.samples.petclinic.Pet; +import org.springframework.samples.petclinic.Visit; +import org.springframework.samples.petclinic.repository.VisitRepository; +import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * A simple JDBC-based implementation of the {@link ClinicService} interface. + * + * <p>This class uses Java 5 language features and the {@link SimpleJdbcTemplate} + * plus {@link SimpleJdbcInsert}. It also takes advantage of classes like + * {@link BeanPropertySqlParameterSource} and + * {@link ParameterizedBeanPropertyRowMapper} which provide automatic mapping + * between JavaBean properties and JDBC parameters or query results. + * + * <p>JdbcClinicImpl is a rewrite of the AbstractJdbcClinic which was the base + * class for JDBC implementations of the ClinicService interface for Spring 2.0. + * + * @author Ken Krebs + * @author Juergen Hoeller + * @author Rob Harrop + * @author Sam Brannen + * @author Thomas Risberg + * @author Mark Fisher + */ +@Service +public class JdbcVisitRepositoryImpl implements VisitRepository { + + private JdbcTemplate jdbcTemplate; + + private SimpleJdbcInsert insertVisit; + + @Autowired + public void init(DataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + + this.insertVisit = new SimpleJdbcInsert(dataSource) + .withTableName("visits") + .usingGeneratedKeyColumns("id"); + } + + + @Transactional + public void storeVisit(Visit visit) throws DataAccessException { + if (visit.isNew()) { + Number newKey = this.insertVisit.executeAndReturnKey( + createVisitParameterSource(visit)); + visit.setId(newKey.intValue()); + } + else { + throw new UnsupportedOperationException("Visit update not supported"); + } + } + + public void deletePet(int id) throws DataAccessException { + this.jdbcTemplate.update("DELETE FROM pets WHERE id=?", id); + } + + // END of ClinicService implementation section ************************************ + + + /** + * Creates a {@link MapSqlParameterSource} based on data values from the + * supplied {@link Visit} instance. + */ + private MapSqlParameterSource createVisitParameterSource(Visit visit) { + return new MapSqlParameterSource() + .addValue("id", visit.getId()) + .addValue("visit_date", visit.getDate()) + .addValue("description", visit.getDescription()) + .addValue("pet_id", visit.getPet().getId()); + } + + + + @Override + public List<Visit> findByPetId(Integer petId) { + final List<Visit> visits = this.jdbcTemplate.query( + "SELECT id, visit_date, description FROM visits WHERE pet_id=?", + new ParameterizedRowMapper<Visit>() { + public Visit mapRow(ResultSet rs, int row) throws SQLException { + Visit visit = new Visit(); + visit.setId(rs.getInt("id")); + visit.setDate(rs.getTimestamp("visit_date")); + visit.setDescription(rs.getString("description")); + return visit; + } + }, + petId); + return visits; + } + + + + /** + * {@link ParameterizedRowMapper} implementation mapping data from a + * {@link ResultSet} to the corresponding properties of the {@link JdbcPet} class. + */ + private class JdbcPetRowMapper implements ParameterizedRowMapper<JdbcPet> { + + public JdbcPet mapRow(ResultSet rs, int rownum) throws SQLException { + JdbcPet pet = new JdbcPet(); + pet.setId(rs.getInt("id")); + pet.setName(rs.getString("name")); + pet.setBirthDate(rs.getDate("birth_date")); + pet.setTypeId(rs.getInt("type_id")); + pet.setOwnerId(rs.getInt("owner_id")); + return pet; + } + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/jdbc/package-info.java b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/package-info.java similarity index 62% rename from src/main/java/org/springframework/samples/petclinic/jdbc/package-info.java rename to src/main/java/org/springframework/samples/petclinic/repository/jdbc/package-info.java index 6ec278b..edd0bf8 100644 --- a/src/main/java/org/springframework/samples/petclinic/jdbc/package-info.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/jdbc/package-info.java @@ -5,5 +5,5 @@ * of PetClinic's persistence layer. * */ -package org.springframework.samples.petclinic.jdbc; +package org.springframework.samples.petclinic.repository.jdbc; diff --git a/src/main/java/org/springframework/samples/petclinic/jpa/JpaClinicImpl.java b/src/main/java/org/springframework/samples/petclinic/repository/jpa/JpaClinicImpl.java similarity index 89% rename from src/main/java/org/springframework/samples/petclinic/jpa/JpaClinicImpl.java rename to src/main/java/org/springframework/samples/petclinic/repository/jpa/JpaClinicImpl.java index 4d19897..361fd4b 100644 --- a/src/main/java/org/springframework/samples/petclinic/jpa/JpaClinicImpl.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/jpa/JpaClinicImpl.java @@ -1,4 +1,4 @@ -package org.springframework.samples.petclinic.jpa; +package org.springframework.samples.petclinic.repository.jpa; import java.util.Collection; @@ -6,18 +6,18 @@ import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; -import org.springframework.samples.petclinic.Clinic; import org.springframework.samples.petclinic.Owner; import org.springframework.samples.petclinic.Pet; import org.springframework.samples.petclinic.PetType; import org.springframework.samples.petclinic.Vet; import org.springframework.samples.petclinic.Visit; +import org.springframework.samples.petclinic.service.ClinicService; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import org.springframework.dao.DataAccessException; /** - * JPA implementation of the Clinic interface using EntityManager. + * JPA implementation of the ClinicService interface using EntityManager. * * <p>The mappings are defined in "orm.xml" located in the META-INF directory. * @@ -29,7 +29,7 @@ import org.springframework.dao.DataAccessException; */ @Repository @Transactional -public class JpaClinicImpl implements Clinic { +public class JpaClinicImpl implements ClinicService { @PersistenceContext private EntityManager em; diff --git a/src/main/java/org/springframework/samples/petclinic/repository/jpa/JpaOwnerRepositoryImpl.java b/src/main/java/org/springframework/samples/petclinic/repository/jpa/JpaOwnerRepositoryImpl.java new file mode 100644 index 0000000..73ee82a --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/jpa/JpaOwnerRepositoryImpl.java @@ -0,0 +1,57 @@ +package org.springframework.samples.petclinic.repository.jpa; + +import java.util.Collection; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.Query; + +import org.springframework.dao.DataAccessException; +import org.springframework.samples.petclinic.Owner; +import org.springframework.samples.petclinic.Pet; +import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.Vet; +import org.springframework.samples.petclinic.Visit; +import org.springframework.samples.petclinic.repository.OwnerRepository; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +/** + * JPA implementation of the ClinicService interface using EntityManager. + * + * <p>The mappings are defined in "orm.xml" located in the META-INF directory. + * + * @author Mike Keith + * @author Rod Johnson + * @author Sam Brannen + * @author Michael Isvy + * @since 22.4.2006 + */ +@Repository +@Transactional +public class JpaOwnerRepositoryImpl implements OwnerRepository { + + @PersistenceContext + private EntityManager em; + + + @Transactional(readOnly = true) + @SuppressWarnings("unchecked") + public Collection<Owner> findByLastName(String lastName) { + Query query = this.em.createQuery("SELECT owner FROM Owner owner WHERE owner.lastName LIKE :lastName"); + query.setParameter("lastName", lastName + "%"); + return query.getResultList(); + } + + @Transactional(readOnly = true) + public Owner findById(int id) { + return this.em.find(Owner.class, id); + } + + + public void save(Owner owner) { + this.em.merge(owner); + + } + +} diff --git a/src/main/java/org/springframework/samples/petclinic/jpa/SpringDataClinic.java b/src/main/java/org/springframework/samples/petclinic/repository/jpa/SpringDataClinic.java similarity index 83% rename from src/main/java/org/springframework/samples/petclinic/jpa/SpringDataClinic.java rename to src/main/java/org/springframework/samples/petclinic/repository/jpa/SpringDataClinic.java index f21a576..cf1af4b 100644 --- a/src/main/java/org/springframework/samples/petclinic/jpa/SpringDataClinic.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/jpa/SpringDataClinic.java @@ -1,22 +1,22 @@ -package org.springframework.samples.petclinic.jpa; +package org.springframework.samples.petclinic.repository.jpa; import java.util.Collection; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.Repository; -import org.springframework.samples.petclinic.Clinic; import org.springframework.samples.petclinic.Owner; import org.springframework.samples.petclinic.Pet; import org.springframework.samples.petclinic.PetType; import org.springframework.samples.petclinic.Vet; import org.springframework.samples.petclinic.Visit; +import org.springframework.samples.petclinic.service.ClinicService; /** * * @author Michael Isvy * @since 15.1.2013 */ -public interface SpringDataClinic extends Clinic, Repository { +public interface SpringDataClinic extends ClinicService, Repository { diff --git a/src/main/java/org/springframework/samples/petclinic/repository/jpa/SpringDataOwnerRepository.java b/src/main/java/org/springframework/samples/petclinic/repository/jpa/SpringDataOwnerRepository.java new file mode 100644 index 0000000..f32b34c --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/repository/jpa/SpringDataOwnerRepository.java @@ -0,0 +1,13 @@ +package org.springframework.samples.petclinic.repository.jpa; + +import org.springframework.data.repository.Repository; +import org.springframework.samples.petclinic.Owner; +import org.springframework.samples.petclinic.repository.OwnerRepository; + +/** + * + * @author Michael Isvy + * @since 15.1.2013 + */ +public interface SpringDataOwnerRepository extends OwnerRepository, Repository<Owner, Integer> { +} diff --git a/src/main/java/org/springframework/samples/petclinic/jpa/package-info.java b/src/main/java/org/springframework/samples/petclinic/repository/jpa/package-info.java similarity index 62% rename from src/main/java/org/springframework/samples/petclinic/jpa/package-info.java rename to src/main/java/org/springframework/samples/petclinic/repository/jpa/package-info.java index 8093784..13c8552 100644 --- a/src/main/java/org/springframework/samples/petclinic/jpa/package-info.java +++ b/src/main/java/org/springframework/samples/petclinic/repository/jpa/package-info.java @@ -5,5 +5,5 @@ * of PetClinic's persistence layer. * */ -package org.springframework.samples.petclinic.jpa; +package org.springframework.samples.petclinic.repository.jpa; diff --git a/src/main/java/org/springframework/samples/petclinic/service/ClinicService.java b/src/main/java/org/springframework/samples/petclinic/service/ClinicService.java new file mode 100644 index 0000000..24a9329 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/service/ClinicService.java @@ -0,0 +1,39 @@ +package org.springframework.samples.petclinic.service; + +import java.util.Collection; + +import org.springframework.dao.DataAccessException; +import org.springframework.samples.petclinic.Owner; +import org.springframework.samples.petclinic.Pet; +import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.Vet; +import org.springframework.samples.petclinic.Visit; + + +/** + * The high-level PetClinic business interface. + * + * <p>This is basically a data access object. + * PetClinic doesn't have a dedicated business facade. + * + * @author Ken Krebs + * @author Juergen Hoeller + * @author Sam Brannen + */ +public interface ClinicService { + + public Collection<PetType> getPetTypes() throws DataAccessException; + + public Owner findOwnerById(int id) throws DataAccessException; + + public Pet findPetById(int id) throws DataAccessException; + + public void storePet(Pet pet) throws DataAccessException; + + public void deletePet(int id) throws DataAccessException; + + public void storeVisit(Visit visit) throws DataAccessException; + + public Collection<Vet> getVets() throws DataAccessException; + +} diff --git a/src/main/java/org/springframework/samples/petclinic/service/ClinicServiceImpl.java b/src/main/java/org/springframework/samples/petclinic/service/ClinicServiceImpl.java new file mode 100644 index 0000000..b4e51e7 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/service/ClinicServiceImpl.java @@ -0,0 +1,71 @@ +package org.springframework.samples.petclinic.service; + +import java.util.Collection; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.samples.petclinic.Owner; +import org.springframework.samples.petclinic.Pet; +import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.Vet; +import org.springframework.samples.petclinic.Visit; +import org.springframework.samples.petclinic.repository.OwnerRepository; +import org.springframework.samples.petclinic.repository.PetRepository; +import org.springframework.samples.petclinic.repository.VetRepository; +import org.springframework.samples.petclinic.repository.VisitRepository; +import org.springframework.stereotype.Service; + +@Service +public class ClinicServiceImpl implements ClinicService { + + @Autowired + private PetRepository petRepository; + + @Autowired + private VetRepository vetRepository; + + @Autowired + private OwnerRepository ownerRepository; + + @Autowired + private VisitRepository visitRepository; + + public Collection<PetType> getPetTypes() throws DataAccessException { + return petRepository.getPetTypes(); + } + + public Owner findOwnerById(int id) throws DataAccessException { + return ownerRepository.findById(id); + } + + public void storeVisit(Visit visit) throws DataAccessException { + visitRepository.storeVisit(visit); + } + + public Pet findPetById(int id) throws DataAccessException { + return petRepository.findById(id); + } + + public void storePet(Pet pet) throws DataAccessException { + petRepository.storePet(pet); + } + + public void deletePet(int id) throws DataAccessException { + petRepository.deletePet(id); + } + + public Collection<Vet> getVets() throws DataAccessException { + return vetRepository.getVets(); + } + + + + + + + + + + + +} diff --git a/src/main/java/org/springframework/samples/petclinic/web/ClinicBindingInitializer.java b/src/main/java/org/springframework/samples/petclinic/web/ClinicBindingInitializer.java index 2d2a8bd..4421ce0 100644 --- a/src/main/java/org/springframework/samples/petclinic/web/ClinicBindingInitializer.java +++ b/src/main/java/org/springframework/samples/petclinic/web/ClinicBindingInitializer.java @@ -6,8 +6,8 @@ import java.util.Date; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.propertyeditors.CustomDateEditor; import org.springframework.beans.propertyeditors.StringTrimmerEditor; -import org.springframework.samples.petclinic.Clinic; import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.service.ClinicService; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.support.WebBindingInitializer; import org.springframework.web.context.request.WebRequest; @@ -24,14 +24,14 @@ import org.springframework.web.context.request.WebRequest; public class ClinicBindingInitializer implements WebBindingInitializer { @Autowired - private Clinic clinic; + private ClinicService clinicService; public void initBinder(WebDataBinder binder, WebRequest request) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); dateFormat.setLenient(false); binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); binder.registerCustomEditor(String.class, new StringTrimmerEditor(false)); - binder.registerCustomEditor(PetType.class, new PetTypeEditor(this.clinic)); + binder.registerCustomEditor(PetType.class, new PetTypeEditor(this.clinicService)); } } diff --git a/src/main/java/org/springframework/samples/petclinic/web/ClinicController.java b/src/main/java/org/springframework/samples/petclinic/web/ClinicController.java deleted file mode 100644 index 8d5ea2d..0000000 --- a/src/main/java/org/springframework/samples/petclinic/web/ClinicController.java +++ /dev/null @@ -1,99 +0,0 @@ - -package org.springframework.samples.petclinic.web; - -import java.text.SimpleDateFormat; -import java.util.Date; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.propertyeditors.CustomDateEditor; -import org.springframework.beans.propertyeditors.StringTrimmerEditor; -import org.springframework.samples.petclinic.Clinic; -import org.springframework.samples.petclinic.PetType; -import org.springframework.samples.petclinic.Vets; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.WebDataBinder; -import org.springframework.web.bind.annotation.InitBinder; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.servlet.ModelAndView; - -/** - * Annotation-driven <em>MultiActionController</em> that handles all non-form - * URL's. - * - * @author Juergen Hoeller - * @author Mark Fisher - * @author Ken Krebs - * @author Arjen Poutsma - */ -@Controller -public class ClinicController { - - private final Clinic clinic; - - - @Autowired - public ClinicController(Clinic clinic) { - this.clinic = clinic; - } - - /** - * Custom handler for the welcome view. - * <p> - * Note that this handler relies on the RequestToViewNameTranslator to - * determine the logical view name based on the request URL: "/welcome.do" - * -> "welcome". - */ - @RequestMapping("/") - public String welcomeHandler() { - return "welcome"; - } - - /** - * Custom handler for displaying vets. - * - * <p>Note that this handler returns a plain {@link ModelMap} object instead of - * a ModelAndView, thus leveraging convention-based model attribute names. - * It relies on the RequestToViewNameTranslator to determine the logical - * view name based on the request URL: "/vets.do" -> "vets". - * - * @return a ModelMap with the model attributes for the view - */ - @RequestMapping("/vets") - public String showVetList(Model model) { - Vets vets = new Vets(); - vets.getVetList().addAll(this.clinic.getVets()); - model.addAttribute("vets", vets); - return "vetsList"; - } - - /** - * Custom handler for displaying an owner. - * - * @param ownerId the ID of the owner to display - * @return a ModelMap with the model attributes for the view - */ - @RequestMapping("/owners/{ownerId}") - public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) { - ModelAndView mav = new ModelAndView("owners/ownerDetails"); - mav.addObject(this.clinic.findOwner(ownerId)); - return mav; - } - - /** - * Custom handler for displaying an list of visits. - * - * @param petId the ID of the pet whose visits to display - * @return a ModelMap with the model attributes for the view - */ - @RequestMapping(value="/owners/*/pets/{petId}/visits", method=RequestMethod.GET) - public ModelAndView visitsHandler(@PathVariable int petId) { - ModelAndView mav = new ModelAndView("visits"); - mav.addObject("visits", this.clinic.findPet(petId).getVisits()); - return mav; - } - -} diff --git a/src/main/java/org/springframework/samples/petclinic/web/OwnerController.java b/src/main/java/org/springframework/samples/petclinic/web/OwnerController.java index 7b9fb49..a7f760a 100644 --- a/src/main/java/org/springframework/samples/petclinic/web/OwnerController.java +++ b/src/main/java/org/springframework/samples/petclinic/web/OwnerController.java @@ -6,8 +6,8 @@ import java.util.Collection; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.samples.petclinic.Clinic; import org.springframework.samples.petclinic.Owner; +import org.springframework.samples.petclinic.repository.OwnerRepository; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; @@ -18,6 +18,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.bind.support.SessionStatus; +import org.springframework.web.servlet.ModelAndView; /** * JavaBean form controller that is used to handle <code>Owner</code>s . @@ -31,12 +32,12 @@ import org.springframework.web.bind.support.SessionStatus; @SessionAttributes(types = Owner.class) public class OwnerController { - private final Clinic clinic; + private final OwnerRepository ownerRepository; @Autowired - public OwnerController(Clinic clinic) { - this.clinic = clinic; + public OwnerController(OwnerRepository ownerRepository) { + this.ownerRepository = ownerRepository; } @InitBinder @@ -57,7 +58,7 @@ public class OwnerController { return "owners/createOrUpdateOwnerForm"; } else { - this.clinic.storeOwner(owner); + this.ownerRepository.save(owner); status.setComplete(); return "redirect:/owners/" + owner.getId(); } @@ -78,7 +79,7 @@ public class OwnerController { } // find owners by last name - Collection<Owner> results = this.clinic.findOwners(owner.getLastName()); + Collection<Owner> results = this.ownerRepository.findByLastName(owner.getLastName()); if (results.size() < 1) { // no owners found result.rejectValue("lastName", "notFound", "not found"); @@ -98,7 +99,7 @@ public class OwnerController { @RequestMapping(value="/owners/{ownerId}/edit", method = RequestMethod.GET) public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) { - Owner owner = this.clinic.findOwner(ownerId); + Owner owner = this.ownerRepository.findById(ownerId); model.addAttribute(owner); return "owners/createOrUpdateOwnerForm"; } @@ -109,10 +110,23 @@ public class OwnerController { return "owners/createOrUpdateOwnerForm"; } else { - this.clinic.storeOwner(owner); + this.ownerRepository.save(owner); status.setComplete(); return "redirect:/owners/" + owner.getId(); } } + + /** + * Custom handler for displaying an owner. + * + * @param ownerId the ID of the owner to display + * @return a ModelMap with the model attributes for the view + */ + @RequestMapping("/owners/{ownerId}") + public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) { + ModelAndView mav = new ModelAndView("owners/ownerDetails"); + mav.addObject(this.ownerRepository.findById(ownerId)); + return mav; + } } diff --git a/src/main/java/org/springframework/samples/petclinic/web/PetController.java b/src/main/java/org/springframework/samples/petclinic/web/PetController.java index 55e4e93..b440a79 100644 --- a/src/main/java/org/springframework/samples/petclinic/web/PetController.java +++ b/src/main/java/org/springframework/samples/petclinic/web/PetController.java @@ -4,10 +4,10 @@ package org.springframework.samples.petclinic.web; import java.util.Collection; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.samples.petclinic.Clinic; import org.springframework.samples.petclinic.Owner; import org.springframework.samples.petclinic.Pet; import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.service.ClinicService; import org.springframework.samples.petclinic.validation.PetValidator; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -33,17 +33,17 @@ import org.springframework.web.bind.support.SessionStatus; @SessionAttributes("pet") public class PetController { - private final Clinic clinic; - + private final ClinicService clinicService; + @Autowired - public PetController(Clinic clinic) { - this.clinic = clinic; + public PetController(ClinicService clinicService) { + this.clinicService = clinicService; } @ModelAttribute("types") public Collection<PetType> populatePetTypes() { - return this.clinic.getPetTypes(); + return this.clinicService.getPetTypes(); } @InitBinder @@ -53,7 +53,7 @@ public class PetController { @RequestMapping(value="/owners/{ownerId}/pets/new", method = RequestMethod.GET) public String initCreationForm(@PathVariable("ownerId") int ownerId, Model model) { - Owner owner = this.clinic.findOwner(ownerId); + Owner owner = this.clinicService.findOwnerById(ownerId); Pet pet = new Pet(); owner.addPet(pet); model.addAttribute("pet", pet); @@ -67,7 +67,7 @@ public class PetController { return "pets/createOrUpdatePetForm"; } else { - this.clinic.storePet(pet); + this.clinicService.storePet(pet); status.setComplete(); return "redirect:/owners/" + pet.getOwner().getId(); } @@ -75,7 +75,7 @@ public class PetController { @RequestMapping(value="/owners/*/pets/{petId}/edit", method = RequestMethod.GET) public String initUpdateForm(@PathVariable("petId") int petId, Model model) { - Pet pet = this.clinic.findPet(petId); + Pet pet = this.clinicService.findPetById(petId); model.addAttribute("pet", pet); return "pets/createOrUpdatePetForm"; } @@ -88,7 +88,7 @@ public class PetController { return "pets/createOrUpdatePetForm"; } else { - this.clinic.storePet(pet); + this.clinicService.storePet(pet); status.setComplete(); return "redirect:/owners/" + pet.getOwner().getId(); } @@ -96,8 +96,8 @@ public class PetController { @RequestMapping(value="/owners/*/pets/{petId}/edit", method = RequestMethod.DELETE) public String deletePet(@PathVariable("petId") int petId) { - Pet pet = this.clinic.findPet(petId); - this.clinic.deletePet(petId); + Pet pet = this.clinicService.findPetById(petId); + this.clinicService.deletePet(petId); return "redirect:/owners/" + pet.getOwner().getId(); } diff --git a/src/main/java/org/springframework/samples/petclinic/web/PetTypeEditor.java b/src/main/java/org/springframework/samples/petclinic/web/PetTypeEditor.java index 812b648..1be37c9 100644 --- a/src/main/java/org/springframework/samples/petclinic/web/PetTypeEditor.java +++ b/src/main/java/org/springframework/samples/petclinic/web/PetTypeEditor.java @@ -2,8 +2,8 @@ package org.springframework.samples.petclinic.web; import java.beans.PropertyEditorSupport; -import org.springframework.samples.petclinic.Clinic; import org.springframework.samples.petclinic.PetType; +import org.springframework.samples.petclinic.service.ClinicService; /** * @author Mark Fisher @@ -11,16 +11,16 @@ import org.springframework.samples.petclinic.PetType; */ public class PetTypeEditor extends PropertyEditorSupport { - private final Clinic clinic; + private final ClinicService clinicService; - public PetTypeEditor(Clinic clinic) { - this.clinic = clinic; + public PetTypeEditor(ClinicService clinicService) { + this.clinicService = clinicService; } @Override public void setAsText(String text) throws IllegalArgumentException { - for (PetType type : this.clinic.getPetTypes()) { + for (PetType type : this.clinicService.getPetTypes()) { if (type.getName().equals(text)) { setValue(type); } diff --git a/src/main/java/org/springframework/samples/petclinic/web/VetController.java b/src/main/java/org/springframework/samples/petclinic/web/VetController.java new file mode 100644 index 0000000..5bcdfa2 --- /dev/null +++ b/src/main/java/org/springframework/samples/petclinic/web/VetController.java @@ -0,0 +1,54 @@ + +package org.springframework.samples.petclinic.web; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.samples.petclinic.Vets; +import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * Annotation-driven <em>MultiActionController</em> that handles all non-form + * URL's. + * + * @author Juergen Hoeller + * @author Mark Fisher + * @author Ken Krebs + * @author Arjen Poutsma + */ +@Controller +public class VetController { + + private final ClinicService clinicService; + + + @Autowired + public VetController(ClinicService clinicService) { + this.clinicService = clinicService; + } + + /** + * Custom handler for displaying vets. + * + * <p>Note that this handler returns a plain {@link ModelMap} object instead of + * a ModelAndView, thus leveraging convention-based model attribute names. + * It relies on the RequestToViewNameTranslator to determine the logical + * view name based on the request URL: "/vets.do" -> "vets". + * + * @return a ModelMap with the model attributes for the view + */ + @RequestMapping("/vets") + public String showVetList(Model model) { + Vets vets = new Vets(); + vets.getVetList().addAll(this.clinicService.getVets()); + model.addAttribute("vets", vets); + return "vetsList"; + } + + + + + +} diff --git a/src/main/java/org/springframework/samples/petclinic/web/VisitController.java b/src/main/java/org/springframework/samples/petclinic/web/VisitController.java index 0f38743..f093c04 100644 --- a/src/main/java/org/springframework/samples/petclinic/web/VisitController.java +++ b/src/main/java/org/springframework/samples/petclinic/web/VisitController.java @@ -4,9 +4,9 @@ package org.springframework.samples.petclinic.web; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.samples.petclinic.Clinic; import org.springframework.samples.petclinic.Pet; import org.springframework.samples.petclinic.Visit; +import org.springframework.samples.petclinic.service.ClinicService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; @@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.bind.support.SessionStatus; +import org.springframework.web.servlet.ModelAndView; /** * JavaBean form controller that is used to add a new <code>Visit</code> to the @@ -30,12 +31,12 @@ import org.springframework.web.bind.support.SessionStatus; @SessionAttributes("visit") public class VisitController { - private final Clinic clinic; + private final ClinicService clinicService; @Autowired - public VisitController(Clinic clinic) { - this.clinic = clinic; + public VisitController(ClinicService clinicService) { + this.clinicService = clinicService; } @InitBinder @@ -44,8 +45,8 @@ public class VisitController { } @RequestMapping(value="/owners/*/pets/{petId}/visits/new", method = RequestMethod.GET) - public String setupForm(@PathVariable("petId") int petId, Model model) { - Pet pet = this.clinic.findPet(petId); + public String initNewVisitForm(@PathVariable("petId") int petId, Model model) { + Pet pet = this.clinicService.findPetById(petId); Visit visit = new Visit(); pet.addVisit(visit); model.addAttribute("visit", visit); @@ -53,15 +54,28 @@ public class VisitController { } @RequestMapping(value="/owners/*/pets/{petId}/visits/new", method = RequestMethod.POST) - public String processSubmit(@Valid Visit visit, BindingResult result, SessionStatus status) { + public String processNewVisitForm(@Valid Visit visit, BindingResult result, SessionStatus status) { if (result.hasErrors()) { return "pets/createOrUpdateVisitForm"; } else { - this.clinic.storeVisit(visit); + this.clinicService.storeVisit(visit); status.setComplete(); return "redirect:/owners/" + visit.getPet().getOwner().getId(); } } + + /** + * Custom handler for displaying an list of visits. + * + * @param petId the ID of the pet whose visits to display + * @return a ModelMap with the model attributes for the view + */ + @RequestMapping(value="/owners/*/pets/{petId}/visits", method=RequestMethod.GET) + public ModelAndView showVisits(@PathVariable int petId) { + ModelAndView mav = new ModelAndView("visits"); + mav.addObject("visits", this.clinicService.findPetById(petId).getVisits()); + return mav; + } } diff --git a/src/main/java/org/springframework/samples/petclinic/web/VisitsAtomView.java b/src/main/java/org/springframework/samples/petclinic/web/VisitsAtomView.java index e9da832..f5f69e0 100644 --- a/src/main/java/org/springframework/samples/petclinic/web/VisitsAtomView.java +++ b/src/main/java/org/springframework/samples/petclinic/web/VisitsAtomView.java @@ -41,7 +41,7 @@ public class VisitsAtomView extends AbstractAtomFeedView { @Override protected void buildFeedMetadata(Map<String, Object> model, Feed feed, HttpServletRequest request) { feed.setId("tag:springsource.com"); - feed.setTitle("Pet Clinic Visits"); + feed.setTitle("Pet ClinicService Visits"); @SuppressWarnings("unchecked") List<Visit> visits = (List<Visit>) model.get("visits"); for (Visit visit : visits) { diff --git a/src/main/resources/spring/applicationContext-dao.xml b/src/main/resources/spring/applicationContext-dao.xml index 1ce9718..69f23d9 100644 --- a/src/main/resources/spring/applicationContext-dao.xml +++ b/src/main/resources/spring/applicationContext-dao.xml @@ -96,10 +96,16 @@ <!-- Transaction manager for a single JDBC DataSource (alternative to JTA) --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource"/> - - - <!-- PetClinic's central data access object using Spring's SimpleJdbcTemplate --> - <bean id="clinic" class="org.springframework.samples.petclinic.jdbc.JdbcClinicImpl"/> + + <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> + <constructor-arg ref="dataSource" /> + </bean> + + <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"> + <constructor-arg ref="dataSource" /> + </bean> + + <context:component-scan base-package="org.springframework.samples.petclinic.repository.jdbc"/> </beans> @@ -109,12 +115,12 @@ EntityManager will be auto-injected due to @PersistenceContext. PersistenceExceptions will be auto-translated due to @Repository. --> - <bean id="clinic" class="org.springframework.samples.petclinic.jpa.JpaClinicImpl"/> + <context:component-scan base-package="org.springframework.samples.petclinic.repository.jpa"/> </beans> <beans profile="spring-data-jpa"> - <jpa:repositories base-package="org.springframework.samples.petclinic.jpa"/> + <jpa:repositories base-package="org.springframework.samples.petclinic.repository.jpa"/> </beans> </beans> \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/petclinic-servlet.xml b/src/main/webapp/WEB-INF/petclinic-servlet.xml index d203e4a..c619a4f 100644 --- a/src/main/webapp/WEB-INF/petclinic-servlet.xml +++ b/src/main/webapp/WEB-INF/petclinic-servlet.xml @@ -13,7 +13,7 @@ <!-- - The controllers are autodetected POJOs labeled with the @Controller annotation. --> - <context:component-scan base-package="org.springframework.samples.petclinic.web"/> + <context:component-scan base-package="org.springframework.samples.petclinic.web, org.springframework.samples.petclinic.service"/> <mvc:annotation-driven /> @@ -25,6 +25,8 @@ <!-- uses WebJars so Javascript and CSS libs can be declared as Maven dependencies (we're using it for Bootstrap) --> <mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/"/> + <mvc:view-controller path="/" view-name="welcome"/> + <!-- - This view resolver delegates to the InternalResourceViewResolver and BeanNameViewResolver, diff --git a/src/test/java/org/springframework/samples/petclinic/AbstractOwnerRepositoryTests.java b/src/test/java/org/springframework/samples/petclinic/AbstractOwnerRepositoryTests.java new file mode 100644 index 0000000..9a516fc --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/AbstractOwnerRepositoryTests.java @@ -0,0 +1,147 @@ +package org.springframework.samples.petclinic; + +import java.util.Collection; +import java.util.Date; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.samples.petclinic.repository.OwnerRepository; +import org.springframework.samples.petclinic.util.EntityUtils; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests; +import org.springframework.transaction.annotation.Transactional; + +/** + * <p> + * Base class for {@link OwnerRepository} integration tests. + * </p> + * <p> + * "AbstractClinicTests-context.xml" declares a common + * {@link javax.sql.DataSource DataSource}. Subclasses should specify + * additional context locations which declare a + * {@link org.springframework.transaction.PlatformTransactionManager PlatformTransactionManager} + * and a concrete implementation of {@link OwnerRepository}. + * </p> + * <p> + * This class extends {@link AbstractTransactionalJUnit4SpringContextTests}, + * one of the valuable testing support classes provided by the + * <em>Spring TestContext Framework</em> found in the + * <code>org.springframework.test.context</code> package. The + * annotation-driven configuration used here represents best practice for + * integration tests with Spring. Note, however, that + * AbstractTransactionalJUnit4SpringContextTests serves only as a convenience + * for extension. For example, if you do not wish for your test classes to be + * tied to a Spring-specific class hierarchy, you may configure your tests with + * annotations such as {@link ContextConfiguration @ContextConfiguration}, + * {@link org.springframework.test.context.TestExecutionListeners @TestExecutionListeners}, + * {@link org.springframework.transaction.annotation.Transactional @Transactional}, + * etc. + * </p> + * <p> + * AbstractClinicTests and its subclasses benefit from the following services + * provided by the Spring TestContext Framework: + * </p> + * <ul> + * <li><strong>Spring IoC container caching</strong> which spares us + * unnecessary set up time between test execution.</li> + * <li><strong>Dependency Injection</strong> of test fixture instances, + * meaning that we don't need to perform application context lookups. See the + * use of {@link Autowired @Autowired} on the <code>ownerRepository</code> instance + * variable, which uses autowiring <em>by type</em>. As an alternative, we + * could annotate <code>ownerRepository</code> with + * {@link javax.annotation.Resource @Resource} to achieve dependency injection + * <em>by name</em>. + * <em>(see: {@link ContextConfiguration @ContextConfiguration}, + * {@link org.springframework.test.context.support.DependencyInjectionTestExecutionListener DependencyInjectionTestExecutionListener})</em></li> + * <li><strong>Transaction management</strong>, meaning each test method is + * executed in its own transaction, which is automatically rolled back by + * default. Thus, even if tests insert or otherwise change database state, there + * is no need for a teardown or cleanup script. + * <em>(see: {@link org.springframework.test.context.transaction.TransactionConfiguration @TransactionConfiguration}, + * {@link org.springframework.transaction.annotation.Transactional @Transactional}, + * {@link org.springframework.test.context.transaction.TransactionalTestExecutionListener TransactionalTestExecutionListener})</em></li> + * <li><strong>Useful inherited protected fields</strong>, such as a + * {@link org.springframework.jdbc.core.simple.SimpleJdbcTemplate SimpleJdbcTemplate} + * that can be used to verify database state after test operations or to verify + * the results of queries performed by application code. An + * {@link org.springframework.context.ApplicationContext ApplicationContext} is + * also inherited and can be used for explicit bean lookup if necessary. + * <em>(see: {@link org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests AbstractJUnit4SpringContextTests}, + * {@link AbstractTransactionalJUnit4SpringContextTests})</em></li> + * </ul> + * <p> + * The Spring TestContext Framework and related unit and integration testing + * support classes are shipped in <code>spring-test.jar</code>. + * </p> + * + * @author Ken Krebs + * @author Rod Johnson + * @author Juergen Hoeller + * @author Sam Brannen + */ +public abstract class AbstractOwnerRepositoryTests { + + @Autowired + protected OwnerRepository ownerRepository; + + + + + @Test + public void findOwners() { + Collection<Owner> owners = this.ownerRepository.findByLastName("Davis"); + assertEquals(2, owners.size()); + owners = this.ownerRepository.findByLastName("Daviss"); + assertEquals(0, owners.size()); + } + + @Test @Transactional + public void findOwner() { + Owner o1 = this.ownerRepository.findById(1); + assertTrue(o1.getLastName().startsWith("Franklin")); + Owner o10 = this.ownerRepository.findById(10); + assertEquals("Carlos", o10.getFirstName()); + + // XXX: Add programmatic support for ending transactions with the + // TestContext Framework. + + // Check lazy loading, by ending the transaction: + // endTransaction(); + + // Now Owners are "disconnected" from the data store. + // We might need to touch this collection if we switched to lazy loading + // in mapping files, but this test would pick this up. + o1.getPets(); + } + + @Test + public void insertOwner() { + Collection<Owner> owners = this.ownerRepository.findByLastName("Schultz"); + int found = owners.size(); + Owner owner = new Owner(); + owner.setFirstName("Sam"); + owner.setLastName("Schultz"); + owner.setAddress("4, Evans Street"); + owner.setCity("Wollongong"); + owner.setTelephone("4444444444"); + this.ownerRepository.save(owner); + owners = this.ownerRepository.findByLastName("Schultz"); + assertEquals("Verifying number of owners after inserting a new one.", found + 1, owners.size()); + } + + @Test + public void updateOwner() throws Exception { + Owner o1 = this.ownerRepository.findById(1); + String old = o1.getLastName(); + o1.setLastName(old + "X"); + this.ownerRepository.save(o1); + o1 = this.ownerRepository.findById(1); + assertEquals(old + "X", o1.getLastName()); + } + + + +} diff --git a/src/test/java/org/springframework/samples/petclinic/AbstractClinicTests.java b/src/test/java/org/springframework/samples/petclinic/AbstractPetRepositoryTests.java similarity index 60% rename from src/test/java/org/springframework/samples/petclinic/AbstractClinicTests.java rename to src/test/java/org/springframework/samples/petclinic/AbstractPetRepositoryTests.java index a9246d4..8db0a5f 100644 --- a/src/test/java/org/springframework/samples/petclinic/AbstractClinicTests.java +++ b/src/test/java/org/springframework/samples/petclinic/AbstractPetRepositoryTests.java @@ -8,6 +8,9 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.samples.petclinic.repository.OwnerRepository; +import org.springframework.samples.petclinic.repository.PetRepository; +import org.springframework.samples.petclinic.service.ClinicService; import org.springframework.samples.petclinic.util.EntityUtils; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests; @@ -15,14 +18,14 @@ import org.springframework.transaction.annotation.Transactional; /** * <p> - * Base class for {@link Clinic} integration tests. + * Base class for {@link ClinicService} integration tests. * </p> * <p> * "AbstractClinicTests-context.xml" declares a common * {@link javax.sql.DataSource DataSource}. Subclasses should specify * additional context locations which declare a * {@link org.springframework.transaction.PlatformTransactionManager PlatformTransactionManager} - * and a concrete implementation of {@link Clinic}. + * and a concrete implementation of {@link ClinicService}. * </p> * <p> * This class extends {@link AbstractTransactionalJUnit4SpringContextTests}, @@ -48,9 +51,9 @@ import org.springframework.transaction.annotation.Transactional; * unnecessary set up time between test execution.</li> * <li><strong>Dependency Injection</strong> of test fixture instances, * meaning that we don't need to perform application context lookups. See the - * use of {@link Autowired @Autowired} on the <code>clinic</code> instance + * use of {@link Autowired @Autowired} on the <code>petRepository</code> instance * variable, which uses autowiring <em>by type</em>. As an alternative, we - * could annotate <code>clinic</code> with + * could annotate <code>petRepository</code> with * {@link javax.annotation.Resource @Resource} to achieve dependency injection * <em>by name</em>. * <em>(see: {@link ContextConfiguration @ContextConfiguration}, @@ -81,30 +84,18 @@ import org.springframework.transaction.annotation.Transactional; * @author Juergen Hoeller * @author Sam Brannen */ -public abstract class AbstractClinicTests { +public abstract class AbstractPetRepositoryTests { @Autowired - protected Clinic clinic; - + protected PetRepository petRepository; + + @Autowired + protected OwnerRepository ownerRepository; - @Test @Transactional - public void getVets() { - Collection<Vet> vets = this.clinic.getVets(); - - Vet v1 = EntityUtils.getById(vets, Vet.class, 2); - assertEquals("Leary", v1.getLastName()); - assertEquals(1, v1.getNrOfSpecialties()); - assertEquals("radiology", (v1.getSpecialties().get(0)).getName()); - Vet v2 = EntityUtils.getById(vets, Vet.class, 3); - assertEquals("Douglas", v2.getLastName()); - assertEquals(2, v2.getNrOfSpecialties()); - assertEquals("dentistry", (v2.getSpecialties().get(0)).getName()); - assertEquals("surgery", (v2.getSpecialties().get(1)).getName()); - } @Test public void getPetTypes() { - Collection<PetType> petTypes = this.clinic.getPetTypes(); + Collection<PetType> petTypes = this.petRepository.getPetTypes(); PetType t1 = EntityUtils.getById(petTypes, PetType.class, 1); assertEquals("cat", t1.getName()); @@ -112,63 +103,14 @@ public abstract class AbstractClinicTests { assertEquals("snake", t4.getName()); } - @Test - public void findOwners() { - Collection<Owner> owners = this.clinic.findOwners("Davis"); - assertEquals(2, owners.size()); - owners = this.clinic.findOwners("Daviss"); - assertEquals(0, owners.size()); - } - - @Test @Transactional - public void findOwner() { - Owner o1 = this.clinic.findOwner(1); - assertTrue(o1.getLastName().startsWith("Franklin")); - Owner o10 = this.clinic.findOwner(10); - assertEquals("Carlos", o10.getFirstName()); - - // XXX: Add programmatic support for ending transactions with the - // TestContext Framework. - - // Check lazy loading, by ending the transaction: - // endTransaction(); - - // Now Owners are "disconnected" from the data store. - // We might need to touch this collection if we switched to lazy loading - // in mapping files, but this test would pick this up. - o1.getPets(); - } - - @Test - public void insertOwner() { - Collection<Owner> owners = this.clinic.findOwners("Schultz"); - int found = owners.size(); - Owner owner = new Owner(); - owner.setLastName("Schultz"); - this.clinic.storeOwner(owner); - // assertTrue(!owner.isNew()); -- NOT TRUE FOR TOPLINK (before commit) - owners = this.clinic.findOwners("Schultz"); - assertEquals("Verifying number of owners after inserting a new one.", found + 1, owners.size()); - } - - @Test - public void updateOwner() throws Exception { - Owner o1 = this.clinic.findOwner(1); - String old = o1.getLastName(); - o1.setLastName(old + "X"); - this.clinic.storeOwner(o1); - o1 = this.clinic.findOwner(1); - assertEquals(old + "X", o1.getLastName()); - } - @Test public void findPet() { - Collection<PetType> types = this.clinic.getPetTypes(); - Pet p7 = this.clinic.findPet(7); + Collection<PetType> types = this.petRepository.getPetTypes(); + Pet p7 = this.petRepository.findById(7); assertTrue(p7.getName().startsWith("Samantha")); assertEquals(EntityUtils.getById(types, PetType.class, 1).getId(), p7.getType().getId()); assertEquals("Jean", p7.getOwner().getFirstName()); - Pet p6 = this.clinic.findPet(6); + Pet p6 = this.petRepository.findById(6); assertEquals("George", p6.getName()); assertEquals(EntityUtils.getById(types, PetType.class, 4).getId(), p6.getType().getId()); assertEquals("Peter", p6.getOwner().getFirstName()); @@ -176,46 +118,30 @@ public abstract class AbstractClinicTests { @Test @Transactional public void insertPet() { - Owner o6 = this.clinic.findOwner(6); + Owner o6 = this.ownerRepository.findById(6); int found = o6.getPets().size(); Pet pet = new Pet(); pet.setName("bowser"); - Collection<PetType> types = this.clinic.getPetTypes(); + Collection<PetType> types = this.petRepository.getPetTypes(); pet.setType(EntityUtils.getById(types, PetType.class, 2)); pet.setBirthDate(new Date()); o6.addPet(pet); assertEquals(found + 1, o6.getPets().size()); // both storePet and storeOwner are necessary to cover all ORM tools - this.clinic.storePet(pet); - this.clinic.storeOwner(o6); - // assertTrue(!pet.isNew()); -- NOT TRUE FOR TOPLINK (before commit) - o6 = this.clinic.findOwner(6); + this.petRepository.storePet(pet); + this.ownerRepository.save(o6); + o6 = this.ownerRepository.findById(6); assertEquals(found + 1, o6.getPets().size()); } @Test public void updatePet() throws Exception { - Pet p7 = this.clinic.findPet(7); + Pet p7 = this.petRepository.findById(7); String old = p7.getName(); p7.setName(old + "X"); - this.clinic.storePet(p7); - p7 = this.clinic.findPet(7); + this.petRepository.storePet(p7); + p7 = this.petRepository.findById(7); assertEquals(old + "X", p7.getName()); } - @Test @Transactional - public void insertVisit() { - Pet p7 = this.clinic.findPet(7); - int found = p7.getVisits().size(); - Visit visit = new Visit(); - p7.addVisit(visit); - visit.setDescription("test"); - // both storeVisit and storePet are necessary to cover all ORM tools - this.clinic.storeVisit(visit); - this.clinic.storePet(p7); - // assertTrue(!visit.isNew()); -- NOT TRUE FOR TOPLINK (before commit) - p7 = this.clinic.findPet(7); - assertEquals(found + 1, p7.getVisits().size()); - } - } diff --git a/src/test/java/org/springframework/samples/petclinic/AbstractVetRepositoryTests.java b/src/test/java/org/springframework/samples/petclinic/AbstractVetRepositoryTests.java new file mode 100644 index 0000000..8db1f77 --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/AbstractVetRepositoryTests.java @@ -0,0 +1,107 @@ +package org.springframework.samples.petclinic; + +import java.util.Collection; +import java.util.Date; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.samples.petclinic.repository.VetRepository; +import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.samples.petclinic.util.EntityUtils; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests; +import org.springframework.transaction.annotation.Transactional; + +/** + * <p> + * Base class for {@link ClinicService} integration tests. + * </p> + * <p> + * "AbstractClinicTests-context.xml" declares a common + * {@link javax.sql.DataSource DataSource}. Subclasses should specify + * additional context locations which declare a + * {@link org.springframework.transaction.PlatformTransactionManager PlatformTransactionManager} + * and a concrete implementation of {@link ClinicService}. + * </p> + * <p> + * This class extends {@link AbstractTransactionalJUnit4SpringContextTests}, + * one of the valuable testing support classes provided by the + * <em>Spring TestContext Framework</em> found in the + * <code>org.springframework.test.context</code> package. The + * annotation-driven configuration used here represents best practice for + * integration tests with Spring. Note, however, that + * AbstractTransactionalJUnit4SpringContextTests serves only as a convenience + * for extension. For example, if you do not wish for your test classes to be + * tied to a Spring-specific class hierarchy, you may configure your tests with + * annotations such as {@link ContextConfiguration @ContextConfiguration}, + * {@link org.springframework.test.context.TestExecutionListeners @TestExecutionListeners}, + * {@link org.springframework.transaction.annotation.Transactional @Transactional}, + * etc. + * </p> + * <p> + * AbstractClinicTests and its subclasses benefit from the following services + * provided by the Spring TestContext Framework: + * </p> + * <ul> + * <li><strong>Spring IoC container caching</strong> which spares us + * unnecessary set up time between test execution.</li> + * <li><strong>Dependency Injection</strong> of test fixture instances, + * meaning that we don't need to perform application context lookups. See the + * use of {@link Autowired @Autowired} on the <code>petRepository</code> instance + * variable, which uses autowiring <em>by type</em>. As an alternative, we + * could annotate <code>petRepository</code> with + * {@link javax.annotation.Resource @Resource} to achieve dependency injection + * <em>by name</em>. + * <em>(see: {@link ContextConfiguration @ContextConfiguration}, + * {@link org.springframework.test.context.support.DependencyInjectionTestExecutionListener DependencyInjectionTestExecutionListener})</em></li> + * <li><strong>Transaction management</strong>, meaning each test method is + * executed in its own transaction, which is automatically rolled back by + * default. Thus, even if tests insert or otherwise change database state, there + * is no need for a teardown or cleanup script. + * <em>(see: {@link org.springframework.test.context.transaction.TransactionConfiguration @TransactionConfiguration}, + * {@link org.springframework.transaction.annotation.Transactional @Transactional}, + * {@link org.springframework.test.context.transaction.TransactionalTestExecutionListener TransactionalTestExecutionListener})</em></li> + * <li><strong>Useful inherited protected fields</strong>, such as a + * {@link org.springframework.jdbc.core.simple.SimpleJdbcTemplate SimpleJdbcTemplate} + * that can be used to verify database state after test operations or to verify + * the results of queries performed by application code. An + * {@link org.springframework.context.ApplicationContext ApplicationContext} is + * also inherited and can be used for explicit bean lookup if necessary. + * <em>(see: {@link org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests AbstractJUnit4SpringContextTests}, + * {@link AbstractTransactionalJUnit4SpringContextTests})</em></li> + * </ul> + * <p> + * The Spring TestContext Framework and related unit and integration testing + * support classes are shipped in <code>spring-test.jar</code>. + * </p> + * + * @author Ken Krebs + * @author Rod Johnson + * @author Juergen Hoeller + * @author Sam Brannen + */ +public abstract class AbstractVetRepositoryTests { + + @Autowired + protected VetRepository vetRepository; + + + @Test @Transactional + public void getVets() { + Collection<Vet> vets = this.vetRepository.getVets(); + + Vet v1 = EntityUtils.getById(vets, Vet.class, 2); + assertEquals("Leary", v1.getLastName()); + assertEquals(1, v1.getNrOfSpecialties()); + assertEquals("radiology", (v1.getSpecialties().get(0)).getName()); + Vet v2 = EntityUtils.getById(vets, Vet.class, 3); + assertEquals("Douglas", v2.getLastName()); + assertEquals(2, v2.getNrOfSpecialties()); + assertEquals("dentistry", (v2.getSpecialties().get(0)).getName()); + assertEquals("surgery", (v2.getSpecialties().get(1)).getName()); + } + +} diff --git a/src/test/java/org/springframework/samples/petclinic/AbstractVisitRepositoryTests.java b/src/test/java/org/springframework/samples/petclinic/AbstractVisitRepositoryTests.java new file mode 100644 index 0000000..bdae7a8 --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/AbstractVisitRepositoryTests.java @@ -0,0 +1,111 @@ +package org.springframework.samples.petclinic; + +import java.util.Collection; +import java.util.Date; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.samples.petclinic.repository.PetRepository; +import org.springframework.samples.petclinic.repository.VisitRepository; +import org.springframework.samples.petclinic.service.ClinicService; +import org.springframework.samples.petclinic.util.EntityUtils; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests; +import org.springframework.transaction.annotation.Transactional; + +/** + * <p> + * Base class for {@link ClinicService} integration tests. + * </p> + * <p> + * "AbstractClinicTests-context.xml" declares a common + * {@link javax.sql.DataSource DataSource}. Subclasses should specify + * additional context locations which declare a + * {@link org.springframework.transaction.PlatformTransactionManager PlatformTransactionManager} + * and a concrete implementation of {@link ClinicService}. + * </p> + * <p> + * This class extends {@link AbstractTransactionalJUnit4SpringContextTests}, + * one of the valuable testing support classes provided by the + * <em>Spring TestContext Framework</em> found in the + * <code>org.springframework.test.context</code> package. The + * annotation-driven configuration used here represents best practice for + * integration tests with Spring. Note, however, that + * AbstractTransactionalJUnit4SpringContextTests serves only as a convenience + * for extension. For example, if you do not wish for your test classes to be + * tied to a Spring-specific class hierarchy, you may configure your tests with + * annotations such as {@link ContextConfiguration @ContextConfiguration}, + * {@link org.springframework.test.context.TestExecutionListeners @TestExecutionListeners}, + * {@link org.springframework.transaction.annotation.Transactional @Transactional}, + * etc. + * </p> + * <p> + * AbstractClinicTests and its subclasses benefit from the following services + * provided by the Spring TestContext Framework: + * </p> + * <ul> + * <li><strong>Spring IoC container caching</strong> which spares us + * unnecessary set up time between test execution.</li> + * <li><strong>Dependency Injection</strong> of test fixture instances, + * meaning that we don't need to perform application context lookups. See the + * use of {@link Autowired @Autowired} on the <code>petRepository</code> instance + * variable, which uses autowiring <em>by type</em>. As an alternative, we + * could annotate <code>petRepository</code> with + * {@link javax.annotation.Resource @Resource} to achieve dependency injection + * <em>by name</em>. + * <em>(see: {@link ContextConfiguration @ContextConfiguration}, + * {@link org.springframework.test.context.support.DependencyInjectionTestExecutionListener DependencyInjectionTestExecutionListener})</em></li> + * <li><strong>Transaction management</strong>, meaning each test method is + * executed in its own transaction, which is automatically rolled back by + * default. Thus, even if tests insert or otherwise change database state, there + * is no need for a teardown or cleanup script. + * <em>(see: {@link org.springframework.test.context.transaction.TransactionConfiguration @TransactionConfiguration}, + * {@link org.springframework.transaction.annotation.Transactional @Transactional}, + * {@link org.springframework.test.context.transaction.TransactionalTestExecutionListener TransactionalTestExecutionListener})</em></li> + * <li><strong>Useful inherited protected fields</strong>, such as a + * {@link org.springframework.jdbc.core.simple.SimpleJdbcTemplate SimpleJdbcTemplate} + * that can be used to verify database state after test operations or to verify + * the results of queries performed by application code. An + * {@link org.springframework.context.ApplicationContext ApplicationContext} is + * also inherited and can be used for explicit bean lookup if necessary. + * <em>(see: {@link org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests AbstractJUnit4SpringContextTests}, + * {@link AbstractTransactionalJUnit4SpringContextTests})</em></li> + * </ul> + * <p> + * The Spring TestContext Framework and related unit and integration testing + * support classes are shipped in <code>spring-test.jar</code>. + * </p> + * + * @author Ken Krebs + * @author Rod Johnson + * @author Juergen Hoeller + * @author Sam Brannen + */ +public abstract class AbstractVisitRepositoryTests { + + @Autowired + protected VisitRepository visitRepository; + + @Autowired + protected PetRepository petRepository; + + + @Test @Transactional + public void insertVisit() { + Pet p7 = this.petRepository.findById(7); + int found = p7.getVisits().size(); + Visit visit = new Visit(); + p7.addVisit(visit); + visit.setDescription("test"); + // both storeVisit and storePet are necessary to cover all ORM tools + this.visitRepository.storeVisit(visit); + this.petRepository.storePet(p7); + // assertTrue(!visit.isNew()); -- NOT TRUE FOR TOPLINK (before commit) + p7 = this.petRepository.findById(7); + assertEquals(found + 1, p7.getVisits().size()); + } + +} diff --git a/src/test/java/org/springframework/samples/petclinic/aspects/UsageLogAspectTests.java b/src/test/java/org/springframework/samples/petclinic/aspects/UsageLogAspectTests.java index 2768909..929e1b9 100644 --- a/src/test/java/org/springframework/samples/petclinic/aspects/UsageLogAspectTests.java +++ b/src/test/java/org/springframework/samples/petclinic/aspects/UsageLogAspectTests.java @@ -1,18 +1,17 @@ package org.springframework.samples.petclinic.aspects; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertTrue; + import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.samples.petclinic.Clinic; -import org.springframework.samples.petclinic.aspects.UsageLogAspect; -import org.springframework.samples.petclinic.jpa.JpaClinicImplTests; +import org.springframework.samples.petclinic.repository.OwnerRepository; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import static junit.framework.Assert.assertTrue; -import static junit.framework.Assert.assertFalse; /** * <p> @@ -36,7 +35,7 @@ public class UsageLogAspectTests { private UsageLogAspect usageLogAspect; @Autowired - private Clinic clinic; + private OwnerRepository ownerRepository; @Test @@ -45,8 +44,8 @@ public class UsageLogAspectTests { String lastName2 = "Davis"; String lastName3 = "foo"; - assertFalse(this.clinic.findOwners(lastName1).isEmpty()); - assertFalse(this.clinic.findOwners(lastName2).isEmpty()); + assertFalse(this.ownerRepository.findByLastName(lastName1).isEmpty()); + assertFalse(this.ownerRepository.findByLastName(lastName2).isEmpty()); List<String> namesRequested = this.usageLogAspect.getNamesRequested(); assertTrue(namesRequested.contains(lastName1)); diff --git a/src/test/java/org/springframework/samples/petclinic/jdbc/JdbcOwnerRepositoryImplTests.java b/src/test/java/org/springframework/samples/petclinic/jdbc/JdbcOwnerRepositoryImplTests.java new file mode 100644 index 0000000..4c2d352 --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/jdbc/JdbcOwnerRepositoryImplTests.java @@ -0,0 +1,29 @@ +package org.springframework.samples.petclinic.jdbc; + +import org.junit.runner.RunWith; +import org.springframework.samples.petclinic.AbstractOwnerRepositoryTests; +import org.springframework.samples.petclinic.repository.jdbc.JdbcClinicImpl; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * <p> + * Integration tests for the {@link JdbcClinicImpl} implementation. + * </p> + * <p> + * </p> + * + * @author Thomas Risberg + * @author Michael Isvy + */ +@ContextConfiguration(locations={"classpath:spring/applicationContext-dao.xml"}) +@RunWith(SpringJUnit4ClassRunner.class) +@DirtiesContext +@ActiveProfiles("jdbc") +public class JdbcOwnerRepositoryImplTests extends AbstractOwnerRepositoryTests { + + + +} diff --git a/src/test/java/org/springframework/samples/petclinic/jdbc/JdbcClinicImplTests.java b/src/test/java/org/springframework/samples/petclinic/jdbc/JdbcPetRepositoryImplTests.java similarity index 74% rename from src/test/java/org/springframework/samples/petclinic/jdbc/JdbcClinicImplTests.java rename to src/test/java/org/springframework/samples/petclinic/jdbc/JdbcPetRepositoryImplTests.java index bba9193..d62454a 100644 --- a/src/test/java/org/springframework/samples/petclinic/jdbc/JdbcClinicImplTests.java +++ b/src/test/java/org/springframework/samples/petclinic/jdbc/JdbcPetRepositoryImplTests.java @@ -1,7 +1,8 @@ package org.springframework.samples.petclinic.jdbc; import org.junit.runner.RunWith; -import org.springframework.samples.petclinic.AbstractClinicTests; +import org.springframework.samples.petclinic.AbstractPetRepositoryTests; +import org.springframework.samples.petclinic.repository.jdbc.JdbcClinicImpl; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; @@ -21,7 +22,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @DirtiesContext @ActiveProfiles("jdbc") -public class JdbcClinicImplTests extends AbstractClinicTests { +public class JdbcPetRepositoryImplTests extends AbstractPetRepositoryTests { diff --git a/src/test/java/org/springframework/samples/petclinic/jdbc/JdbcVetRepositoryImplTests.java b/src/test/java/org/springframework/samples/petclinic/jdbc/JdbcVetRepositoryImplTests.java new file mode 100644 index 0000000..4e05009 --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/jdbc/JdbcVetRepositoryImplTests.java @@ -0,0 +1,29 @@ +package org.springframework.samples.petclinic.jdbc; + +import org.junit.runner.RunWith; +import org.springframework.samples.petclinic.AbstractVetRepositoryTests; +import org.springframework.samples.petclinic.repository.jdbc.JdbcClinicImpl; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * <p> + * Integration tests for the {@link JdbcClinicImpl} implementation. + * </p> + * <p> + * </p> + * + * @author Thomas Risberg + * @author Michael Isvy + */ +@ContextConfiguration(locations={"classpath:spring/applicationContext-dao.xml"}) +@RunWith(SpringJUnit4ClassRunner.class) +@DirtiesContext +@ActiveProfiles("jdbc") +public class JdbcVetRepositoryImplTests extends AbstractVetRepositoryTests { + + + +} diff --git a/src/test/java/org/springframework/samples/petclinic/jdbc/JdbcVisitRepositoryImplTests.java b/src/test/java/org/springframework/samples/petclinic/jdbc/JdbcVisitRepositoryImplTests.java new file mode 100644 index 0000000..7d272aa --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/jdbc/JdbcVisitRepositoryImplTests.java @@ -0,0 +1,29 @@ +package org.springframework.samples.petclinic.jdbc; + +import org.junit.runner.RunWith; +import org.springframework.samples.petclinic.AbstractVisitRepositoryTests; +import org.springframework.samples.petclinic.repository.jdbc.JdbcClinicImpl; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * <p> + * Integration tests for the {@link JdbcClinicImpl} implementation. + * </p> + * <p> + * </p> + * + * @author Thomas Risberg + * @author Michael Isvy + */ +@ContextConfiguration(locations={"classpath:spring/applicationContext-dao.xml"}) +@RunWith(SpringJUnit4ClassRunner.class) +@DirtiesContext +@ActiveProfiles("jdbc") +public class JdbcVisitRepositoryImplTests extends AbstractVisitRepositoryTests { + + + +} diff --git a/src/test/java/org/springframework/samples/petclinic/jpa/JpaClinicImplTests.java b/src/test/java/org/springframework/samples/petclinic/jpa/JpaOwnerRepositoryImplTests.java similarity index 57% rename from src/test/java/org/springframework/samples/petclinic/jpa/JpaClinicImplTests.java rename to src/test/java/org/springframework/samples/petclinic/jpa/JpaOwnerRepositoryImplTests.java index aed4fcb..92eee5e 100644 --- a/src/test/java/org/springframework/samples/petclinic/jpa/JpaClinicImplTests.java +++ b/src/test/java/org/springframework/samples/petclinic/jpa/JpaOwnerRepositoryImplTests.java @@ -1,16 +1,8 @@ package org.springframework.samples.petclinic.jpa; -import static junit.framework.Assert.fail; - -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; - -import org.junit.Test; import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.samples.petclinic.AbstractClinicTests; -import org.springframework.samples.petclinic.Clinic; +import org.springframework.samples.petclinic.AbstractOwnerRepositoryTests; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -37,23 +29,6 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @ContextConfiguration(locations={"classpath:spring/applicationContext-dao.xml"}) @RunWith(SpringJUnit4ClassRunner.class) @ActiveProfiles({"jpa","plain-jpa"}) -public class JpaClinicImplTests extends AbstractClinicTests { - - @PersistenceContext - private EntityManager entityManager; - - @Autowired - private Clinic clinic; - - - @Test - public void testBogusJpql() { - try { - this.entityManager.createQuery("SELECT RUBBISH FROM RUBBISH HEAP").executeUpdate(); - fail("exception was expected because of incorrect SQL statement"); - } catch (Exception e) { - // expected - } - } +public class JpaOwnerRepositoryImplTests extends AbstractOwnerRepositoryTests { } \ No newline at end of file diff --git a/src/test/java/org/springframework/samples/petclinic/jpa/JpaPetRepositoryImplTests.java b/src/test/java/org/springframework/samples/petclinic/jpa/JpaPetRepositoryImplTests.java new file mode 100644 index 0000000..12e123b --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/jpa/JpaPetRepositoryImplTests.java @@ -0,0 +1,29 @@ +package org.springframework.samples.petclinic.jpa; + +import org.junit.runner.RunWith; +import org.springframework.samples.petclinic.AbstractPetRepositoryTests; +import org.springframework.samples.petclinic.repository.jdbc.JdbcClinicImpl; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * <p> + * Integration tests for the {@link JdbcClinicImpl} implementation. + * </p> + * <p> + * </p> + * + * @author Thomas Risberg + * @author Michael Isvy + */ +@ContextConfiguration(locations={"classpath:spring/applicationContext-dao.xml"}) +@RunWith(SpringJUnit4ClassRunner.class) +@DirtiesContext +@ActiveProfiles({"jpa","plain-jpa"}) +public class JpaPetRepositoryImplTests extends AbstractPetRepositoryTests { + + + +} diff --git a/src/test/java/org/springframework/samples/petclinic/jpa/JpaVetRepositoryImplTests.java b/src/test/java/org/springframework/samples/petclinic/jpa/JpaVetRepositoryImplTests.java new file mode 100644 index 0000000..7a0e0eb --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/jpa/JpaVetRepositoryImplTests.java @@ -0,0 +1,29 @@ +package org.springframework.samples.petclinic.jpa; + +import org.junit.runner.RunWith; +import org.springframework.samples.petclinic.AbstractVetRepositoryTests; +import org.springframework.samples.petclinic.repository.jdbc.JdbcClinicImpl; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * <p> + * Integration tests for the {@link JdbcClinicImpl} implementation. + * </p> + * <p> + * </p> + * + * @author Thomas Risberg + * @author Michael Isvy + */ +@ContextConfiguration(locations={"classpath:spring/applicationContext-dao.xml"}) +@RunWith(SpringJUnit4ClassRunner.class) +@DirtiesContext +@ActiveProfiles({"jpa","plain-jpa"}) +public class JpaVetRepositoryImplTests extends AbstractVetRepositoryTests { + + + +} diff --git a/src/test/java/org/springframework/samples/petclinic/jpa/JpaVisitRepositoryImplTests.java b/src/test/java/org/springframework/samples/petclinic/jpa/JpaVisitRepositoryImplTests.java new file mode 100644 index 0000000..5205307 --- /dev/null +++ b/src/test/java/org/springframework/samples/petclinic/jpa/JpaVisitRepositoryImplTests.java @@ -0,0 +1,29 @@ +package org.springframework.samples.petclinic.jpa; + +import org.junit.runner.RunWith; +import org.springframework.samples.petclinic.AbstractVisitRepositoryTests; +import org.springframework.samples.petclinic.repository.jdbc.JdbcClinicImpl; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + * <p> + * Integration tests for the {@link JdbcClinicImpl} implementation. + * </p> + * <p> + * </p> + * + * @author Thomas Risberg + * @author Michael Isvy + */ +@ContextConfiguration(locations={"classpath:spring/applicationContext-dao.xml"}) +@RunWith(SpringJUnit4ClassRunner.class) +@DirtiesContext +@ActiveProfiles({"jpa","plain-jpa"}) +public class JpaVisitRepositoryImplTests extends AbstractVisitRepositoryTests { + + + +} diff --git a/src/test/java/org/springframework/samples/petclinic/jpa/SpringDataClinicTests.java b/src/test/java/org/springframework/samples/petclinic/jpa/SpringDataOwnerRepositoryTests.java similarity index 75% rename from src/test/java/org/springframework/samples/petclinic/jpa/SpringDataClinicTests.java rename to src/test/java/org/springframework/samples/petclinic/jpa/SpringDataOwnerRepositoryTests.java index a7e1768..67706e0 100644 --- a/src/test/java/org/springframework/samples/petclinic/jpa/SpringDataClinicTests.java +++ b/src/test/java/org/springframework/samples/petclinic/jpa/SpringDataOwnerRepositoryTests.java @@ -2,7 +2,7 @@ package org.springframework.samples.petclinic.jpa; import org.junit.runner.RunWith; -import org.springframework.samples.petclinic.AbstractClinicTests; +import org.springframework.samples.petclinic.AbstractOwnerRepositoryTests; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -14,6 +14,6 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @ContextConfiguration(locations={"classpath:spring/applicationContext-dao.xml"}) @RunWith(SpringJUnit4ClassRunner.class) @ActiveProfiles({"jpa","spring-data-jpa"}) -public class SpringDataClinicTests extends AbstractClinicTests { +public class SpringDataOwnerRepositoryTests extends AbstractOwnerRepositoryTests { } \ No newline at end of file -- GitLab