petclinic-uncached
Changes
src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcClinicImplMBean.java 6(+3 -3)
src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcOwnerRepositoryImpl.java 173(+173 -0)
src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPetRepositoryImpl.java 160(+160 -0)
src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcPetRowMapper.java 23(+23 -0)
src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcVetRepositoryImpl.java 118(+118 -0)
src/main/java/org/springframework/samples/petclinic/repository/jdbc/JdbcVisitRepositoryImpl.java 131(+131 -0)
src/main/java/org/springframework/samples/petclinic/repository/jpa/JpaOwnerRepositoryImpl.java 57(+57 -0)
src/main/java/org/springframework/samples/petclinic/repository/jpa/SpringDataOwnerRepository.java 13(+13 -0)
src/test/java/org/springframework/samples/petclinic/jdbc/JdbcOwnerRepositoryImplTests.java 29(+29 -0)
Details
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/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/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/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/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/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/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/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/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/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/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/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/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/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 {
+
+
+
+}