moved the ClinicRepository into some separate repos

There is still some polish up to be done.
This commit is contained in:
Mic 2013-01-17 15:27:27 +08:00
parent 16b1476c40
commit c9c8c4e085
47 changed files with 1666 additions and 728 deletions

View file

@ -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;
}

View file

@ -126,19 +126,12 @@ public class Owner extends Person {
return new ToStringCreator(this) return new ToStringCreator(this)
.append("id", this.getId()) .append("id", this.getId())
.append("new", this.isNew()) .append("new", this.isNew())
.append("lastName", this.getLastName()) .append("lastName", this.getLastName())
.append("firstName", this.getFirstName()) .append("firstName", this.getFirstName())
.append("address", this.address) .append("address", this.address)
.append("city", this.city) .append("city", this.city)
.append("telephone", this.telephone) .append("telephone", this.telephone)
.toString(); .toString();
} }
} }

View file

@ -9,7 +9,7 @@ import org.aspectj.lang.annotation.Before;
/** /**
* Sample AspectJ annotation-style aspect that saves * 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 Rod Johnson
* @author Juergen Hoeller * @author Juergen Hoeller

View file

@ -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;
}
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -1,4 +1,4 @@
package org.springframework.samples.petclinic.jdbc; package org.springframework.samples.petclinic.repository.jdbc;
/** /**
* Interface that defines a cache refresh operation. * Interface that defines a cache refresh operation.
@ -11,8 +11,8 @@ package org.springframework.samples.petclinic.jdbc;
public interface JdbcClinicImplMBean { public interface JdbcClinicImplMBean {
/** /**
* Refresh the cache of Vets that the Clinic is holding. * Refresh the cache of Vets that the ClinicService is holding.
* @see org.springframework.samples.petclinic.Clinic#getVets() * @see org.springframework.samples.petclinic.service.ClinicService#getVets()
* @see JdbcClinicImpl#refreshVetsCache() * @see JdbcClinicImpl#refreshVetsCache()
*/ */
void refreshVetsCache(); void refreshVetsCache();

View file

@ -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);
}
}
}

View file

@ -1,10 +1,10 @@
package org.springframework.samples.petclinic.jdbc; package org.springframework.samples.petclinic.repository.jdbc;
import org.springframework.samples.petclinic.Pet; import org.springframework.samples.petclinic.Pet;
/** /**
* Subclass of Pet that carries temporary id properties which * 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 * @author Juergen Hoeller
* @see JdbcClinicImpl * @see JdbcClinicImpl

View file

@ -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}.
*/
}

View file

@ -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;
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -5,5 +5,5 @@
* of PetClinic's persistence layer. * of PetClinic's persistence layer.
* *
*/ */
package org.springframework.samples.petclinic.jdbc; package org.springframework.samples.petclinic.repository.jdbc;

View file

@ -1,4 +1,4 @@
package org.springframework.samples.petclinic.jpa; package org.springframework.samples.petclinic.repository.jpa;
import java.util.Collection; import java.util.Collection;
@ -6,18 +6,18 @@ import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext; import javax.persistence.PersistenceContext;
import javax.persistence.Query; import javax.persistence.Query;
import org.springframework.samples.petclinic.Clinic;
import org.springframework.samples.petclinic.Owner; import org.springframework.samples.petclinic.Owner;
import org.springframework.samples.petclinic.Pet; import org.springframework.samples.petclinic.Pet;
import org.springframework.samples.petclinic.PetType; import org.springframework.samples.petclinic.PetType;
import org.springframework.samples.petclinic.Vet; import org.springframework.samples.petclinic.Vet;
import org.springframework.samples.petclinic.Visit; import org.springframework.samples.petclinic.Visit;
import org.springframework.samples.petclinic.service.ClinicService;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.dao.DataAccessException; 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. * <p>The mappings are defined in "orm.xml" located in the META-INF directory.
* *
@ -29,7 +29,7 @@ import org.springframework.dao.DataAccessException;
*/ */
@Repository @Repository
@Transactional @Transactional
public class JpaClinicImpl implements Clinic { public class JpaClinicImpl implements ClinicService {
@PersistenceContext @PersistenceContext
private EntityManager em; private EntityManager em;

View file

@ -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);
}
}

View file

@ -1,22 +1,22 @@
package org.springframework.samples.petclinic.jpa; package org.springframework.samples.petclinic.repository.jpa;
import java.util.Collection; import java.util.Collection;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
import org.springframework.samples.petclinic.Clinic;
import org.springframework.samples.petclinic.Owner; import org.springframework.samples.petclinic.Owner;
import org.springframework.samples.petclinic.Pet; import org.springframework.samples.petclinic.Pet;
import org.springframework.samples.petclinic.PetType; import org.springframework.samples.petclinic.PetType;
import org.springframework.samples.petclinic.Vet; import org.springframework.samples.petclinic.Vet;
import org.springframework.samples.petclinic.Visit; import org.springframework.samples.petclinic.Visit;
import org.springframework.samples.petclinic.service.ClinicService;
/** /**
* *
* @author Michael Isvy * @author Michael Isvy
* @since 15.1.2013 * @since 15.1.2013
*/ */
public interface SpringDataClinic extends Clinic, Repository { public interface SpringDataClinic extends ClinicService, Repository {

View file

@ -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> {
}

View file

@ -5,5 +5,5 @@
* of PetClinic's persistence layer. * of PetClinic's persistence layer.
* *
*/ */
package org.springframework.samples.petclinic.jpa; package org.springframework.samples.petclinic.repository.jpa;

View file

@ -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;
}

View file

@ -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();
}
}

View file

@ -6,8 +6,8 @@ import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor; import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.beans.propertyeditors.StringTrimmerEditor; import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.samples.petclinic.Clinic;
import org.springframework.samples.petclinic.PetType; import org.springframework.samples.petclinic.PetType;
import org.springframework.samples.petclinic.service.ClinicService;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebBindingInitializer; import org.springframework.web.bind.support.WebBindingInitializer;
import org.springframework.web.context.request.WebRequest; import org.springframework.web.context.request.WebRequest;
@ -24,14 +24,14 @@ import org.springframework.web.context.request.WebRequest;
public class ClinicBindingInitializer implements WebBindingInitializer { public class ClinicBindingInitializer implements WebBindingInitializer {
@Autowired @Autowired
private Clinic clinic; private ClinicService clinicService;
public void initBinder(WebDataBinder binder, WebRequest request) { public void initBinder(WebDataBinder binder, WebRequest request) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false); dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
binder.registerCustomEditor(String.class, new StringTrimmerEditor(false)); binder.registerCustomEditor(String.class, new StringTrimmerEditor(false));
binder.registerCustomEditor(PetType.class, new PetTypeEditor(this.clinic)); binder.registerCustomEditor(PetType.class, new PetTypeEditor(this.clinicService));
} }
} }

View file

@ -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"
* -&gt; "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" -&gt; "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;
}
}

View file

@ -6,8 +6,8 @@ import java.util.Collection;
import javax.validation.Valid; import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.Clinic;
import org.springframework.samples.petclinic.Owner; import org.springframework.samples.petclinic.Owner;
import org.springframework.samples.petclinic.repository.OwnerRepository;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.validation.BindingResult; 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.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus; 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 . * 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) @SessionAttributes(types = Owner.class)
public class OwnerController { public class OwnerController {
private final Clinic clinic; private final OwnerRepository ownerRepository;
@Autowired @Autowired
public OwnerController(Clinic clinic) { public OwnerController(OwnerRepository ownerRepository) {
this.clinic = clinic; this.ownerRepository = ownerRepository;
} }
@InitBinder @InitBinder
@ -57,7 +58,7 @@ public class OwnerController {
return "owners/createOrUpdateOwnerForm"; return "owners/createOrUpdateOwnerForm";
} }
else { else {
this.clinic.storeOwner(owner); this.ownerRepository.save(owner);
status.setComplete(); status.setComplete();
return "redirect:/owners/" + owner.getId(); return "redirect:/owners/" + owner.getId();
} }
@ -78,7 +79,7 @@ public class OwnerController {
} }
// find owners by last name // 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) { if (results.size() < 1) {
// no owners found // no owners found
result.rejectValue("lastName", "notFound", "not found"); result.rejectValue("lastName", "notFound", "not found");
@ -98,7 +99,7 @@ public class OwnerController {
@RequestMapping(value="/owners/{ownerId}/edit", method = RequestMethod.GET) @RequestMapping(value="/owners/{ownerId}/edit", method = RequestMethod.GET)
public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) { public String initUpdateOwnerForm(@PathVariable("ownerId") int ownerId, Model model) {
Owner owner = this.clinic.findOwner(ownerId); Owner owner = this.ownerRepository.findById(ownerId);
model.addAttribute(owner); model.addAttribute(owner);
return "owners/createOrUpdateOwnerForm"; return "owners/createOrUpdateOwnerForm";
} }
@ -109,10 +110,23 @@ public class OwnerController {
return "owners/createOrUpdateOwnerForm"; return "owners/createOrUpdateOwnerForm";
} }
else { else {
this.clinic.storeOwner(owner); this.ownerRepository.save(owner);
status.setComplete(); status.setComplete();
return "redirect:/owners/" + owner.getId(); 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;
}
} }

View file

@ -4,10 +4,10 @@ package org.springframework.samples.petclinic.web;
import java.util.Collection; import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.Clinic;
import org.springframework.samples.petclinic.Owner; import org.springframework.samples.petclinic.Owner;
import org.springframework.samples.petclinic.Pet; import org.springframework.samples.petclinic.Pet;
import org.springframework.samples.petclinic.PetType; import org.springframework.samples.petclinic.PetType;
import org.springframework.samples.petclinic.service.ClinicService;
import org.springframework.samples.petclinic.validation.PetValidator; import org.springframework.samples.petclinic.validation.PetValidator;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
@ -33,17 +33,17 @@ import org.springframework.web.bind.support.SessionStatus;
@SessionAttributes("pet") @SessionAttributes("pet")
public class PetController { public class PetController {
private final Clinic clinic; private final ClinicService clinicService;
@Autowired @Autowired
public PetController(Clinic clinic) { public PetController(ClinicService clinicService) {
this.clinic = clinic; this.clinicService = clinicService;
} }
@ModelAttribute("types") @ModelAttribute("types")
public Collection<PetType> populatePetTypes() { public Collection<PetType> populatePetTypes() {
return this.clinic.getPetTypes(); return this.clinicService.getPetTypes();
} }
@InitBinder @InitBinder
@ -53,7 +53,7 @@ public class PetController {
@RequestMapping(value="/owners/{ownerId}/pets/new", method = RequestMethod.GET) @RequestMapping(value="/owners/{ownerId}/pets/new", method = RequestMethod.GET)
public String initCreationForm(@PathVariable("ownerId") int ownerId, Model model) { 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(); Pet pet = new Pet();
owner.addPet(pet); owner.addPet(pet);
model.addAttribute("pet", pet); model.addAttribute("pet", pet);
@ -67,7 +67,7 @@ public class PetController {
return "pets/createOrUpdatePetForm"; return "pets/createOrUpdatePetForm";
} }
else { else {
this.clinic.storePet(pet); this.clinicService.storePet(pet);
status.setComplete(); status.setComplete();
return "redirect:/owners/" + pet.getOwner().getId(); return "redirect:/owners/" + pet.getOwner().getId();
} }
@ -75,7 +75,7 @@ public class PetController {
@RequestMapping(value="/owners/*/pets/{petId}/edit", method = RequestMethod.GET) @RequestMapping(value="/owners/*/pets/{petId}/edit", method = RequestMethod.GET)
public String initUpdateForm(@PathVariable("petId") int petId, Model model) { 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); model.addAttribute("pet", pet);
return "pets/createOrUpdatePetForm"; return "pets/createOrUpdatePetForm";
} }
@ -88,7 +88,7 @@ public class PetController {
return "pets/createOrUpdatePetForm"; return "pets/createOrUpdatePetForm";
} }
else { else {
this.clinic.storePet(pet); this.clinicService.storePet(pet);
status.setComplete(); status.setComplete();
return "redirect:/owners/" + pet.getOwner().getId(); return "redirect:/owners/" + pet.getOwner().getId();
} }
@ -96,8 +96,8 @@ public class PetController {
@RequestMapping(value="/owners/*/pets/{petId}/edit", method = RequestMethod.DELETE) @RequestMapping(value="/owners/*/pets/{petId}/edit", method = RequestMethod.DELETE)
public String deletePet(@PathVariable("petId") int petId) { public String deletePet(@PathVariable("petId") int petId) {
Pet pet = this.clinic.findPet(petId); Pet pet = this.clinicService.findPetById(petId);
this.clinic.deletePet(petId); this.clinicService.deletePet(petId);
return "redirect:/owners/" + pet.getOwner().getId(); return "redirect:/owners/" + pet.getOwner().getId();
} }

View file

@ -2,8 +2,8 @@ package org.springframework.samples.petclinic.web;
import java.beans.PropertyEditorSupport; import java.beans.PropertyEditorSupport;
import org.springframework.samples.petclinic.Clinic;
import org.springframework.samples.petclinic.PetType; import org.springframework.samples.petclinic.PetType;
import org.springframework.samples.petclinic.service.ClinicService;
/** /**
* @author Mark Fisher * @author Mark Fisher
@ -11,16 +11,16 @@ import org.springframework.samples.petclinic.PetType;
*/ */
public class PetTypeEditor extends PropertyEditorSupport { public class PetTypeEditor extends PropertyEditorSupport {
private final Clinic clinic; private final ClinicService clinicService;
public PetTypeEditor(Clinic clinic) { public PetTypeEditor(ClinicService clinicService) {
this.clinic = clinic; this.clinicService = clinicService;
} }
@Override @Override
public void setAsText(String text) throws IllegalArgumentException { public void setAsText(String text) throws IllegalArgumentException {
for (PetType type : this.clinic.getPetTypes()) { for (PetType type : this.clinicService.getPetTypes()) {
if (type.getName().equals(text)) { if (type.getName().equals(text)) {
setValue(type); setValue(type);
} }

View file

@ -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" -&gt; "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";
}
}

View file

@ -4,9 +4,9 @@ package org.springframework.samples.petclinic.web;
import javax.validation.Valid; import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.Clinic;
import org.springframework.samples.petclinic.Pet; import org.springframework.samples.petclinic.Pet;
import org.springframework.samples.petclinic.Visit; import org.springframework.samples.petclinic.Visit;
import org.springframework.samples.petclinic.service.ClinicService;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.validation.BindingResult; 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.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus; 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 * 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") @SessionAttributes("visit")
public class VisitController { public class VisitController {
private final Clinic clinic; private final ClinicService clinicService;
@Autowired @Autowired
public VisitController(Clinic clinic) { public VisitController(ClinicService clinicService) {
this.clinic = clinic; this.clinicService = clinicService;
} }
@InitBinder @InitBinder
@ -44,8 +45,8 @@ public class VisitController {
} }
@RequestMapping(value="/owners/*/pets/{petId}/visits/new", method = RequestMethod.GET) @RequestMapping(value="/owners/*/pets/{petId}/visits/new", method = RequestMethod.GET)
public String setupForm(@PathVariable("petId") int petId, Model model) { public String initNewVisitForm(@PathVariable("petId") int petId, Model model) {
Pet pet = this.clinic.findPet(petId); Pet pet = this.clinicService.findPetById(petId);
Visit visit = new Visit(); Visit visit = new Visit();
pet.addVisit(visit); pet.addVisit(visit);
model.addAttribute("visit", visit); model.addAttribute("visit", visit);
@ -53,15 +54,28 @@ public class VisitController {
} }
@RequestMapping(value="/owners/*/pets/{petId}/visits/new", method = RequestMethod.POST) @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()) { if (result.hasErrors()) {
return "pets/createOrUpdateVisitForm"; return "pets/createOrUpdateVisitForm";
} }
else { else {
this.clinic.storeVisit(visit); this.clinicService.storeVisit(visit);
status.setComplete(); status.setComplete();
return "redirect:/owners/" + visit.getPet().getOwner().getId(); 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;
}
} }

View file

@ -41,7 +41,7 @@ public class VisitsAtomView extends AbstractAtomFeedView {
@Override @Override
protected void buildFeedMetadata(Map<String, Object> model, Feed feed, HttpServletRequest request) { protected void buildFeedMetadata(Map<String, Object> model, Feed feed, HttpServletRequest request) {
feed.setId("tag:springsource.com"); feed.setId("tag:springsource.com");
feed.setTitle("Pet Clinic Visits"); feed.setTitle("Pet ClinicService Visits");
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<Visit> visits = (List<Visit>) model.get("visits"); List<Visit> visits = (List<Visit>) model.get("visits");
for (Visit visit : visits) { for (Visit visit : visits) {

View file

@ -96,10 +96,16 @@
<!-- Transaction manager for a single JDBC DataSource (alternative to JTA) --> <!-- Transaction manager for a single JDBC DataSource (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/> p:dataSource-ref="dataSource"/>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!-- PetClinic's central data access object using Spring's SimpleJdbcTemplate --> <constructor-arg ref="dataSource" />
<bean id="clinic" class="org.springframework.samples.petclinic.jdbc.JdbcClinicImpl"/> </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> </beans>
@ -109,12 +115,12 @@
EntityManager will be auto-injected due to @PersistenceContext. EntityManager will be auto-injected due to @PersistenceContext.
PersistenceExceptions will be auto-translated due to @Repository. 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>
<beans profile="spring-data-jpa"> <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>
</beans> </beans>

View file

@ -13,7 +13,7 @@
<!-- <!--
- The controllers are autodetected POJOs labeled with the @Controller annotation. - 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 /> <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) --> <!-- 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: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, - This view resolver delegates to the InternalResourceViewResolver and BeanNameViewResolver,

View file

@ -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>
* &quot;AbstractClinicTests-context.xml&quot; 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());
}
}

View file

@ -8,6 +8,9 @@ import static org.junit.Assert.assertTrue;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; 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.samples.petclinic.util.EntityUtils;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests; import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
@ -15,14 +18,14 @@ import org.springframework.transaction.annotation.Transactional;
/** /**
* <p> * <p>
* Base class for {@link Clinic} integration tests. * Base class for {@link ClinicService} integration tests.
* </p> * </p>
* <p> * <p>
* &quot;AbstractClinicTests-context.xml&quot; declares a common * &quot;AbstractClinicTests-context.xml&quot; declares a common
* {@link javax.sql.DataSource DataSource}. Subclasses should specify * {@link javax.sql.DataSource DataSource}. Subclasses should specify
* additional context locations which declare a * additional context locations which declare a
* {@link org.springframework.transaction.PlatformTransactionManager PlatformTransactionManager} * {@link org.springframework.transaction.PlatformTransactionManager PlatformTransactionManager}
* and a concrete implementation of {@link Clinic}. * and a concrete implementation of {@link ClinicService}.
* </p> * </p>
* <p> * <p>
* This class extends {@link AbstractTransactionalJUnit4SpringContextTests}, * This class extends {@link AbstractTransactionalJUnit4SpringContextTests},
@ -48,9 +51,9 @@ import org.springframework.transaction.annotation.Transactional;
* unnecessary set up time between test execution.</li> * unnecessary set up time between test execution.</li>
* <li><strong>Dependency Injection</strong> of test fixture instances, * <li><strong>Dependency Injection</strong> of test fixture instances,
* meaning that we don't need to perform application context lookups. See the * 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 * 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 * {@link javax.annotation.Resource @Resource} to achieve dependency injection
* <em>by name</em>. * <em>by name</em>.
* <em>(see: {@link ContextConfiguration @ContextConfiguration}, * <em>(see: {@link ContextConfiguration @ContextConfiguration},
@ -81,30 +84,18 @@ import org.springframework.transaction.annotation.Transactional;
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sam Brannen * @author Sam Brannen
*/ */
public abstract class AbstractClinicTests { public abstract class AbstractPetRepositoryTests {
@Autowired @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 @Test
public void getPetTypes() { public void getPetTypes() {
Collection<PetType> petTypes = this.clinic.getPetTypes(); Collection<PetType> petTypes = this.petRepository.getPetTypes();
PetType t1 = EntityUtils.getById(petTypes, PetType.class, 1); PetType t1 = EntityUtils.getById(petTypes, PetType.class, 1);
assertEquals("cat", t1.getName()); assertEquals("cat", t1.getName());
@ -112,63 +103,14 @@ public abstract class AbstractClinicTests {
assertEquals("snake", t4.getName()); 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 @Test
public void findPet() { public void findPet() {
Collection<PetType> types = this.clinic.getPetTypes(); Collection<PetType> types = this.petRepository.getPetTypes();
Pet p7 = this.clinic.findPet(7); Pet p7 = this.petRepository.findById(7);
assertTrue(p7.getName().startsWith("Samantha")); assertTrue(p7.getName().startsWith("Samantha"));
assertEquals(EntityUtils.getById(types, PetType.class, 1).getId(), p7.getType().getId()); assertEquals(EntityUtils.getById(types, PetType.class, 1).getId(), p7.getType().getId());
assertEquals("Jean", p7.getOwner().getFirstName()); assertEquals("Jean", p7.getOwner().getFirstName());
Pet p6 = this.clinic.findPet(6); Pet p6 = this.petRepository.findById(6);
assertEquals("George", p6.getName()); assertEquals("George", p6.getName());
assertEquals(EntityUtils.getById(types, PetType.class, 4).getId(), p6.getType().getId()); assertEquals(EntityUtils.getById(types, PetType.class, 4).getId(), p6.getType().getId());
assertEquals("Peter", p6.getOwner().getFirstName()); assertEquals("Peter", p6.getOwner().getFirstName());
@ -176,46 +118,30 @@ public abstract class AbstractClinicTests {
@Test @Transactional @Test @Transactional
public void insertPet() { public void insertPet() {
Owner o6 = this.clinic.findOwner(6); Owner o6 = this.ownerRepository.findById(6);
int found = o6.getPets().size(); int found = o6.getPets().size();
Pet pet = new Pet(); Pet pet = new Pet();
pet.setName("bowser"); pet.setName("bowser");
Collection<PetType> types = this.clinic.getPetTypes(); Collection<PetType> types = this.petRepository.getPetTypes();
pet.setType(EntityUtils.getById(types, PetType.class, 2)); pet.setType(EntityUtils.getById(types, PetType.class, 2));
pet.setBirthDate(new Date()); pet.setBirthDate(new Date());
o6.addPet(pet); o6.addPet(pet);
assertEquals(found + 1, o6.getPets().size()); assertEquals(found + 1, o6.getPets().size());
// both storePet and storeOwner are necessary to cover all ORM tools // both storePet and storeOwner are necessary to cover all ORM tools
this.clinic.storePet(pet); this.petRepository.storePet(pet);
this.clinic.storeOwner(o6); this.ownerRepository.save(o6);
// assertTrue(!pet.isNew()); -- NOT TRUE FOR TOPLINK (before commit) o6 = this.ownerRepository.findById(6);
o6 = this.clinic.findOwner(6);
assertEquals(found + 1, o6.getPets().size()); assertEquals(found + 1, o6.getPets().size());
} }
@Test @Test
public void updatePet() throws Exception { public void updatePet() throws Exception {
Pet p7 = this.clinic.findPet(7); Pet p7 = this.petRepository.findById(7);
String old = p7.getName(); String old = p7.getName();
p7.setName(old + "X"); p7.setName(old + "X");
this.clinic.storePet(p7); this.petRepository.storePet(p7);
p7 = this.clinic.findPet(7); p7 = this.petRepository.findById(7);
assertEquals(old + "X", p7.getName()); 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());
}
} }

View file

@ -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>
* &quot;AbstractClinicTests-context.xml&quot; 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());
}
}

View file

@ -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>
* &quot;AbstractClinicTests-context.xml&quot; 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());
}
}

View file

@ -1,18 +1,17 @@
package org.springframework.samples.petclinic.aspects; package org.springframework.samples.petclinic.aspects;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import java.util.List; import java.util.List;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.Clinic; import org.springframework.samples.petclinic.repository.OwnerRepository;
import org.springframework.samples.petclinic.aspects.UsageLogAspect;
import org.springframework.samples.petclinic.jpa.JpaClinicImplTests;
import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.assertFalse;
/** /**
* <p> * <p>
@ -36,7 +35,7 @@ public class UsageLogAspectTests {
private UsageLogAspect usageLogAspect; private UsageLogAspect usageLogAspect;
@Autowired @Autowired
private Clinic clinic; private OwnerRepository ownerRepository;
@Test @Test
@ -45,8 +44,8 @@ public class UsageLogAspectTests {
String lastName2 = "Davis"; String lastName2 = "Davis";
String lastName3 = "foo"; String lastName3 = "foo";
assertFalse(this.clinic.findOwners(lastName1).isEmpty()); assertFalse(this.ownerRepository.findByLastName(lastName1).isEmpty());
assertFalse(this.clinic.findOwners(lastName2).isEmpty()); assertFalse(this.ownerRepository.findByLastName(lastName2).isEmpty());
List<String> namesRequested = this.usageLogAspect.getNamesRequested(); List<String> namesRequested = this.usageLogAspect.getNamesRequested();
assertTrue(namesRequested.contains(lastName1)); assertTrue(namesRequested.contains(lastName1));

View file

@ -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 {
}

View file

@ -1,7 +1,8 @@
package org.springframework.samples.petclinic.jdbc; package org.springframework.samples.petclinic.jdbc;
import org.junit.runner.RunWith; 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.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
@ -21,7 +22,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext @DirtiesContext
@ActiveProfiles("jdbc") @ActiveProfiles("jdbc")
public class JdbcClinicImplTests extends AbstractClinicTests { public class JdbcPetRepositoryImplTests extends AbstractPetRepositoryTests {

View file

@ -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 {
}

View file

@ -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 {
}

View file

@ -1,16 +1,8 @@
package org.springframework.samples.petclinic.jpa; 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.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.samples.petclinic.AbstractOwnerRepositoryTests;
import org.springframework.samples.petclinic.AbstractClinicTests;
import org.springframework.samples.petclinic.Clinic;
import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 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"}) @ContextConfiguration(locations={"classpath:spring/applicationContext-dao.xml"})
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles({"jpa","plain-jpa"}) @ActiveProfiles({"jpa","plain-jpa"})
public class JpaClinicImplTests extends AbstractClinicTests { public class JpaOwnerRepositoryImplTests extends AbstractOwnerRepositoryTests {
@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
}
}
} }

View file

@ -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 {
}

View file

@ -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 {
}

View file

@ -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 {
}

View file

@ -2,7 +2,7 @@
package org.springframework.samples.petclinic.jpa; package org.springframework.samples.petclinic.jpa;
import org.junit.runner.RunWith; 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.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 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"}) @ContextConfiguration(locations={"classpath:spring/applicationContext-dao.xml"})
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles({"jpa","spring-data-jpa"}) @ActiveProfiles({"jpa","spring-data-jpa"})
public class SpringDataClinicTests extends AbstractClinicTests { public class SpringDataOwnerRepositoryTests extends AbstractOwnerRepositoryTests {
} }