PageRenderTime 51ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/petclinic/branches/michaelGitMigration/src/main/java/org/springframework/samples/petclinic/jdbc/SimpleJdbcClinic.java

https://bitbucket.org/wenner/spring-samples
Java | 341 lines | 239 code | 37 blank | 65 comment | 12 complexity | 05f9dffd9633a1d108897f7a7f9cddde MD5 | raw file
  1. package org.springframework.samples.petclinic.jdbc;
  2. import java.sql.ResultSet;
  3. import java.sql.SQLException;
  4. import java.util.ArrayList;
  5. import java.util.Collection;
  6. import java.util.List;
  7. import javax.sql.DataSource;
  8. import org.slf4j.Logger;
  9. import org.slf4j.LoggerFactory;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11. import org.springframework.dao.DataAccessException;
  12. import org.springframework.dao.EmptyResultDataAccessException;
  13. import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
  14. import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
  15. import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;
  16. import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
  17. import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
  18. import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
  19. import org.springframework.jmx.export.annotation.ManagedOperation;
  20. import org.springframework.jmx.export.annotation.ManagedResource;
  21. import org.springframework.orm.ObjectRetrievalFailureException;
  22. import org.springframework.samples.petclinic.Clinic;
  23. import org.springframework.samples.petclinic.Owner;
  24. import org.springframework.samples.petclinic.Pet;
  25. import org.springframework.samples.petclinic.PetType;
  26. import org.springframework.samples.petclinic.Specialty;
  27. import org.springframework.samples.petclinic.Vet;
  28. import org.springframework.samples.petclinic.Visit;
  29. import org.springframework.samples.petclinic.util.EntityUtils;
  30. import org.springframework.stereotype.Service;
  31. import org.springframework.transaction.annotation.Transactional;
  32. /**
  33. * A simple JDBC-based implementation of the {@link Clinic} interface.
  34. *
  35. * <p>This class uses Java 5 language features and the {@link SimpleJdbcTemplate}
  36. * plus {@link SimpleJdbcInsert}. It also takes advantage of classes like
  37. * {@link BeanPropertySqlParameterSource} and
  38. * {@link ParameterizedBeanPropertyRowMapper} which provide automatic mapping
  39. * between JavaBean properties and JDBC parameters or query results.
  40. *
  41. * <p>SimpleJdbcClinic is a rewrite of the AbstractJdbcClinic which was the base
  42. * class for JDBC implementations of the Clinic interface for Spring 2.0.
  43. *
  44. * @author Ken Krebs
  45. * @author Juergen Hoeller
  46. * @author Rob Harrop
  47. * @author Sam Brannen
  48. * @author Thomas Risberg
  49. * @author Mark Fisher
  50. */
  51. @Service
  52. @ManagedResource("petclinic:type=Clinic")
  53. public class SimpleJdbcClinic implements Clinic, SimpleJdbcClinicMBean {
  54. private final Logger logger = LoggerFactory.getLogger(getClass());
  55. private SimpleJdbcTemplate simpleJdbcTemplate;
  56. private SimpleJdbcInsert insertOwner;
  57. private SimpleJdbcInsert insertPet;
  58. private SimpleJdbcInsert insertVisit;
  59. private final List<Vet> vets = new ArrayList<Vet>();
  60. @Autowired
  61. public void init(DataSource dataSource) {
  62. this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
  63. this.insertOwner = new SimpleJdbcInsert(dataSource)
  64. .withTableName("owners")
  65. .usingGeneratedKeyColumns("id");
  66. this.insertPet = new SimpleJdbcInsert(dataSource)
  67. .withTableName("pets")
  68. .usingGeneratedKeyColumns("id");
  69. this.insertVisit = new SimpleJdbcInsert(dataSource)
  70. .withTableName("visits")
  71. .usingGeneratedKeyColumns("id");
  72. }
  73. /**
  74. * Refresh the cache of Vets that the Clinic is holding.
  75. * @see org.springframework.samples.petclinic.Clinic#getVets()
  76. */
  77. @ManagedOperation
  78. @Transactional(readOnly = true)
  79. public void refreshVetsCache() throws DataAccessException {
  80. synchronized (this.vets) {
  81. this.logger.info("Refreshing vets cache");
  82. // Retrieve the list of all vets.
  83. this.vets.clear();
  84. this.vets.addAll(this.simpleJdbcTemplate.query(
  85. "SELECT id, first_name, last_name FROM vets ORDER BY last_name,first_name",
  86. ParameterizedBeanPropertyRowMapper.newInstance(Vet.class)));
  87. // Retrieve the list of all possible specialties.
  88. final List<Specialty> specialties = this.simpleJdbcTemplate.query(
  89. "SELECT id, name FROM specialties",
  90. ParameterizedBeanPropertyRowMapper.newInstance(Specialty.class));
  91. // Build each vet's list of specialties.
  92. for (Vet vet : this.vets) {
  93. final List<Integer> vetSpecialtiesIds = this.simpleJdbcTemplate.query(
  94. "SELECT specialty_id FROM vet_specialties WHERE vet_id=?",
  95. new ParameterizedRowMapper<Integer>() {
  96. public Integer mapRow(ResultSet rs, int row) throws SQLException {
  97. return Integer.valueOf(rs.getInt(1));
  98. }},
  99. vet.getId().intValue());
  100. for (int specialtyId : vetSpecialtiesIds) {
  101. Specialty specialty = EntityUtils.getById(specialties, Specialty.class, specialtyId);
  102. vet.addSpecialty(specialty);
  103. }
  104. }
  105. }
  106. }
  107. // START of Clinic implementation section *******************************
  108. @Transactional(readOnly = true)
  109. public Collection<Vet> getVets() throws DataAccessException {
  110. synchronized (this.vets) {
  111. if (this.vets.isEmpty()) {
  112. refreshVetsCache();
  113. }
  114. return this.vets;
  115. }
  116. }
  117. @Transactional(readOnly = true)
  118. public Collection<PetType> getPetTypes() throws DataAccessException {
  119. return this.simpleJdbcTemplate.query(
  120. "SELECT id, name FROM types ORDER BY name",
  121. ParameterizedBeanPropertyRowMapper.newInstance(PetType.class));
  122. }
  123. /**
  124. * Loads {@link Owner Owners} from the data store by last name, returning
  125. * all owners whose last name <i>starts</i> with the given name; also loads
  126. * the {@link Pet Pets} and {@link Visit Visits} for the corresponding
  127. * owners, if not already loaded.
  128. */
  129. @Transactional(readOnly = true)
  130. public Collection<Owner> findOwners(String lastName) throws DataAccessException {
  131. List<Owner> owners = this.simpleJdbcTemplate.query(
  132. "SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE last_name like ?",
  133. ParameterizedBeanPropertyRowMapper.newInstance(Owner.class),
  134. lastName + "%");
  135. loadOwnersPetsAndVisits(owners);
  136. return owners;
  137. }
  138. /**
  139. * Loads the {@link Owner} with the supplied <code>id</code>; also loads
  140. * the {@link Pet Pets} and {@link Visit Visits} for the corresponding
  141. * owner, if not already loaded.
  142. */
  143. @Transactional(readOnly = true)
  144. public Owner loadOwner(int id) throws DataAccessException {
  145. Owner owner;
  146. try {
  147. owner = this.simpleJdbcTemplate.queryForObject(
  148. "SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE id=?",
  149. ParameterizedBeanPropertyRowMapper.newInstance(Owner.class),
  150. id);
  151. }
  152. catch (EmptyResultDataAccessException ex) {
  153. throw new ObjectRetrievalFailureException(Owner.class, new Integer(id));
  154. }
  155. loadPetsAndVisits(owner);
  156. return owner;
  157. }
  158. @Transactional(readOnly = true)
  159. public Pet loadPet(int id) throws DataAccessException {
  160. JdbcPet pet;
  161. try {
  162. pet = this.simpleJdbcTemplate.queryForObject(
  163. "SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE id=?",
  164. new JdbcPetRowMapper(),
  165. id);
  166. }
  167. catch (EmptyResultDataAccessException ex) {
  168. throw new ObjectRetrievalFailureException(Pet.class, new Integer(id));
  169. }
  170. Owner owner = loadOwner(pet.getOwnerId());
  171. owner.addPet(pet);
  172. pet.setType(EntityUtils.getById(getPetTypes(), PetType.class, pet.getTypeId()));
  173. loadVisits(pet);
  174. return pet;
  175. }
  176. @Transactional
  177. public void storeOwner(Owner owner) throws DataAccessException {
  178. if (owner.isNew()) {
  179. Number newKey = this.insertOwner.executeAndReturnKey(
  180. new BeanPropertySqlParameterSource(owner));
  181. owner.setId(newKey.intValue());
  182. }
  183. else {
  184. this.simpleJdbcTemplate.update(
  185. "UPDATE owners SET first_name=:firstName, last_name=:lastName, address=:address, " +
  186. "city=:city, telephone=:telephone WHERE id=:id",
  187. new BeanPropertySqlParameterSource(owner));
  188. }
  189. }
  190. @Transactional
  191. public void storePet(Pet pet) throws DataAccessException {
  192. if (pet.isNew()) {
  193. Number newKey = this.insertPet.executeAndReturnKey(
  194. createPetParameterSource(pet));
  195. pet.setId(newKey.intValue());
  196. }
  197. else {
  198. this.simpleJdbcTemplate.update(
  199. "UPDATE pets SET name=:name, birth_date=:birth_date, type_id=:type_id, " +
  200. "owner_id=:owner_id WHERE id=:id",
  201. createPetParameterSource(pet));
  202. }
  203. }
  204. @Transactional
  205. public void storeVisit(Visit visit) throws DataAccessException {
  206. if (visit.isNew()) {
  207. Number newKey = this.insertVisit.executeAndReturnKey(
  208. createVisitParameterSource(visit));
  209. visit.setId(newKey.intValue());
  210. }
  211. else {
  212. throw new UnsupportedOperationException("Visit update not supported");
  213. }
  214. }
  215. public void deletePet(int id) throws DataAccessException {
  216. this.simpleJdbcTemplate.update("DELETE FROM pets WHERE id=?", id);
  217. }
  218. // END of Clinic implementation section ************************************
  219. /**
  220. * Creates a {@link MapSqlParameterSource} based on data values from the
  221. * supplied {@link Pet} instance.
  222. */
  223. private MapSqlParameterSource createPetParameterSource(Pet pet) {
  224. return new MapSqlParameterSource()
  225. .addValue("id", pet.getId())
  226. .addValue("name", pet.getName())
  227. .addValue("birth_date", pet.getBirthDate())
  228. .addValue("type_id", pet.getType().getId())
  229. .addValue("owner_id", pet.getOwner().getId());
  230. }
  231. /**
  232. * Creates a {@link MapSqlParameterSource} based on data values from the
  233. * supplied {@link Visit} instance.
  234. */
  235. private MapSqlParameterSource createVisitParameterSource(Visit visit) {
  236. return new MapSqlParameterSource()
  237. .addValue("id", visit.getId())
  238. .addValue("visit_date", visit.getDate())
  239. .addValue("description", visit.getDescription())
  240. .addValue("pet_id", visit.getPet().getId());
  241. }
  242. /**
  243. * Loads the {@link Visit} data for the supplied {@link Pet}.
  244. */
  245. private void loadVisits(JdbcPet pet) {
  246. final List<Visit> visits = this.simpleJdbcTemplate.query(
  247. "SELECT id, visit_date, description FROM visits WHERE pet_id=?",
  248. new ParameterizedRowMapper<Visit>() {
  249. public Visit mapRow(ResultSet rs, int row) throws SQLException {
  250. Visit visit = new Visit();
  251. visit.setId(rs.getInt("id"));
  252. visit.setDate(rs.getTimestamp("visit_date"));
  253. visit.setDescription(rs.getString("description"));
  254. return visit;
  255. }
  256. },
  257. pet.getId().intValue());
  258. for (Visit visit : visits) {
  259. pet.addVisit(visit);
  260. }
  261. }
  262. /**
  263. * Loads the {@link Pet} and {@link Visit} data for the supplied
  264. * {@link Owner}.
  265. */
  266. private void loadPetsAndVisits(final Owner owner) {
  267. final List<JdbcPet> pets = this.simpleJdbcTemplate.query(
  268. "SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE owner_id=?",
  269. new JdbcPetRowMapper(),
  270. owner.getId().intValue());
  271. for (JdbcPet pet : pets) {
  272. owner.addPet(pet);
  273. pet.setType(EntityUtils.getById(getPetTypes(), PetType.class, pet.getTypeId()));
  274. loadVisits(pet);
  275. }
  276. }
  277. /**
  278. * Loads the {@link Pet} and {@link Visit} data for the supplied
  279. * {@link List} of {@link Owner Owners}.
  280. *
  281. * @param owners the list of owners for whom the pet and visit data should be loaded
  282. * @see #loadPetsAndVisits(Owner)
  283. */
  284. private void loadOwnersPetsAndVisits(List<Owner> owners) {
  285. for (Owner owner : owners) {
  286. loadPetsAndVisits(owner);
  287. }
  288. }
  289. /**
  290. * {@link ParameterizedRowMapper} implementation mapping data from a
  291. * {@link ResultSet} to the corresponding properties of the {@link JdbcPet} class.
  292. */
  293. private class JdbcPetRowMapper implements ParameterizedRowMapper<JdbcPet> {
  294. public JdbcPet mapRow(ResultSet rs, int rownum) throws SQLException {
  295. JdbcPet pet = new JdbcPet();
  296. pet.setId(rs.getInt("id"));
  297. pet.setName(rs.getString("name"));
  298. pet.setBirthDate(rs.getDate("birth_date"));
  299. pet.setTypeId(rs.getInt("type_id"));
  300. pet.setOwnerId(rs.getInt("owner_id"));
  301. return pet;
  302. }
  303. }
  304. }