1 package org.springframework.samples.petclinic.jdbc;
2
3 import java.sql.ResultSet;
4 import java.sql.SQLException;
5 import java.util.ArrayList;
6 import java.util.Collection;
7 import java.util.List;
8
9 import javax.sql.DataSource;
10
11 import org.slf4j.Logger;
12 import org.slf4j.LoggerFactory;
13 import org.springframework.beans.factory.annotation.Autowired;
14 import org.springframework.dao.DataAccessException;
15 import org.springframework.dao.EmptyResultDataAccessException;
16 import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
17 import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
18 import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;
19 import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
20 import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
21 import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
22 import org.springframework.jmx.export.annotation.ManagedOperation;
23 import org.springframework.jmx.export.annotation.ManagedResource;
24 import org.springframework.orm.ObjectRetrievalFailureException;
25 import org.springframework.samples.petclinic.Clinic;
26 import org.springframework.samples.petclinic.Owner;
27 import org.springframework.samples.petclinic.Pet;
28 import org.springframework.samples.petclinic.PetType;
29 import org.springframework.samples.petclinic.Specialty;
30 import org.springframework.samples.petclinic.Vet;
31 import org.springframework.samples.petclinic.Visit;
32 import org.springframework.samples.petclinic.util.EntityUtils;
33 import org.springframework.stereotype.Service;
34 import org.springframework.transaction.annotation.Transactional;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 @Service
56 @ManagedResource("petclinic:type=Clinic")
57 public class SimpleJdbcClinic implements Clinic, SimpleJdbcClinicMBean {
58
59 private final Logger logger = LoggerFactory.getLogger(getClass());
60
61 private SimpleJdbcTemplate simpleJdbcTemplate;
62
63 private SimpleJdbcInsert insertOwner;
64 private SimpleJdbcInsert insertPet;
65 private SimpleJdbcInsert insertVisit;
66
67 private final List<Vet> vets = new ArrayList<Vet>();
68
69
70 @Autowired
71 public void init(DataSource dataSource) {
72 this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
73
74 this.insertOwner = new SimpleJdbcInsert(dataSource)
75 .withTableName("owners")
76 .usingGeneratedKeyColumns("id");
77 this.insertPet = new SimpleJdbcInsert(dataSource)
78 .withTableName("pets")
79 .usingGeneratedKeyColumns("id");
80 this.insertVisit = new SimpleJdbcInsert(dataSource)
81 .withTableName("visits")
82 .usingGeneratedKeyColumns("id");
83 }
84
85
86
87
88
89
90 @ManagedOperation
91 @Transactional(readOnly = true)
92 public void refreshVetsCache() throws DataAccessException {
93 synchronized (this.vets) {
94 this.logger.info("Refreshing vets cache");
95
96
97 this.vets.clear();
98 this.vets.addAll(this.simpleJdbcTemplate.query(
99 "SELECT id, first_name, last_name FROM vets ORDER BY last_name,first_name",
100 ParameterizedBeanPropertyRowMapper.newInstance(Vet.class)));
101
102
103 final List<Specialty> specialties = this.simpleJdbcTemplate.query(
104 "SELECT id, name FROM specialties",
105 ParameterizedBeanPropertyRowMapper.newInstance(Specialty.class));
106
107
108 for (Vet vet : this.vets) {
109 final List<Integer> vetSpecialtiesIds = this.simpleJdbcTemplate.query(
110 "SELECT specialty_id FROM vet_specialties WHERE vet_id=?",
111 new ParameterizedRowMapper<Integer>() {
112 public Integer mapRow(ResultSet rs, int row) throws SQLException {
113 return Integer.valueOf(rs.getInt(1));
114 }},
115 vet.getId().intValue());
116 for (int specialtyId : vetSpecialtiesIds) {
117 Specialty specialty = EntityUtils.getById(specialties, Specialty.class, specialtyId);
118 vet.addSpecialty(specialty);
119 }
120 }
121 }
122 }
123
124
125
126
127 @Transactional(readOnly = true)
128 public Collection<Vet> getVets() throws DataAccessException {
129 synchronized (this.vets) {
130 if (this.vets.isEmpty()) {
131 refreshVetsCache();
132 }
133 return this.vets;
134 }
135 }
136
137 @Transactional(readOnly = true)
138 public Collection<PetType> getPetTypes() throws DataAccessException {
139 return this.simpleJdbcTemplate.query(
140 "SELECT id, name FROM types ORDER BY name",
141 ParameterizedBeanPropertyRowMapper.newInstance(PetType.class));
142 }
143
144
145
146
147
148
149
150 @Transactional(readOnly = true)
151 public Collection<Owner> findOwners(String lastName) throws DataAccessException {
152 List<Owner> owners = this.simpleJdbcTemplate.query(
153 "SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE last_name like ?",
154 ParameterizedBeanPropertyRowMapper.newInstance(Owner.class),
155 lastName + "%");
156 loadOwnersPetsAndVisits(owners);
157 return owners;
158 }
159
160
161
162
163
164
165 @Transactional(readOnly = true)
166 public Owner loadOwner(int id) throws DataAccessException {
167 Owner owner;
168 try {
169 owner = this.simpleJdbcTemplate.queryForObject(
170 "SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE id=?",
171 ParameterizedBeanPropertyRowMapper.newInstance(Owner.class),
172 id);
173 }
174 catch (EmptyResultDataAccessException ex) {
175 throw new ObjectRetrievalFailureException(Owner.class, new Integer(id));
176 }
177 loadPetsAndVisits(owner);
178 return owner;
179 }
180
181 @Transactional(readOnly = true)
182 public Pet loadPet(int id) throws DataAccessException {
183 JdbcPet pet;
184 try {
185 pet = this.simpleJdbcTemplate.queryForObject(
186 "SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE id=?",
187 new JdbcPetRowMapper(),
188 id);
189 }
190 catch (EmptyResultDataAccessException ex) {
191 throw new ObjectRetrievalFailureException(Pet.class, new Integer(id));
192 }
193 Owner owner = loadOwner(pet.getOwnerId());
194 owner.addPet(pet);
195 pet.setType(EntityUtils.getById(getPetTypes(), PetType.class, pet.getTypeId()));
196 loadVisits(pet);
197 return pet;
198 }
199
200 @Transactional
201 public void storeOwner(Owner owner) throws DataAccessException {
202 if (owner.isNew()) {
203 Number newKey = this.insertOwner.executeAndReturnKey(
204 new BeanPropertySqlParameterSource(owner));
205 owner.setId(newKey.intValue());
206 }
207 else {
208 this.simpleJdbcTemplate.update(
209 "UPDATE owners SET first_name=:firstName, last_name=:lastName, address=:address, " +
210 "city=:city, telephone=:telephone WHERE id=:id",
211 new BeanPropertySqlParameterSource(owner));
212 }
213 }
214
215 @Transactional
216 public void storePet(Pet pet) throws DataAccessException {
217 if (pet.isNew()) {
218 Number newKey = this.insertPet.executeAndReturnKey(
219 createPetParameterSource(pet));
220 pet.setId(newKey.intValue());
221 }
222 else {
223 this.simpleJdbcTemplate.update(
224 "UPDATE pets SET name=:name, birth_date=:birth_date, type_id=:type_id, " +
225 "owner_id=:owner_id WHERE id=:id",
226 createPetParameterSource(pet));
227 }
228 }
229
230 @Transactional
231 public void storeVisit(Visit visit) throws DataAccessException {
232 if (visit.isNew()) {
233 Number newKey = this.insertVisit.executeAndReturnKey(
234 createVisitParameterSource(visit));
235 visit.setId(newKey.intValue());
236 }
237 else {
238 throw new UnsupportedOperationException("Visit update not supported");
239 }
240 }
241
242 public void deletePet(int id) throws DataAccessException {
243 this.simpleJdbcTemplate.update("DELETE FROM pets WHERE id=?", id);
244 }
245
246
247
248
249
250
251
252
253 private MapSqlParameterSource createPetParameterSource(Pet pet) {
254 return new MapSqlParameterSource()
255 .addValue("id", pet.getId())
256 .addValue("name", pet.getName())
257 .addValue("birth_date", pet.getBirthDate())
258 .addValue("type_id", pet.getType().getId())
259 .addValue("owner_id", pet.getOwner().getId());
260 }
261
262
263
264
265
266 private MapSqlParameterSource createVisitParameterSource(Visit visit) {
267 return new MapSqlParameterSource()
268 .addValue("id", visit.getId())
269 .addValue("visit_date", visit.getDate())
270 .addValue("description", visit.getDescription())
271 .addValue("pet_id", visit.getPet().getId());
272 }
273
274
275
276
277 private void loadVisits(JdbcPet pet) {
278 final List<Visit> visits = this.simpleJdbcTemplate.query(
279 "SELECT id, visit_date, description FROM visits WHERE pet_id=?",
280 new ParameterizedRowMapper<Visit>() {
281 public Visit mapRow(ResultSet rs, int row) throws SQLException {
282 Visit visit = new Visit();
283 visit.setId(rs.getInt("id"));
284 visit.setDate(rs.getTimestamp("visit_date"));
285 visit.setDescription(rs.getString("description"));
286 return visit;
287 }
288 },
289 pet.getId().intValue());
290 for (Visit visit : visits) {
291 pet.addVisit(visit);
292 }
293 }
294
295
296
297
298
299 private void loadPetsAndVisits(final Owner owner) {
300 final List<JdbcPet> pets = this.simpleJdbcTemplate.query(
301 "SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE owner_id=?",
302 new JdbcPetRowMapper(),
303 owner.getId().intValue());
304 for (JdbcPet pet : pets) {
305 owner.addPet(pet);
306 pet.setType(EntityUtils.getById(getPetTypes(), PetType.class, pet.getTypeId()));
307 loadVisits(pet);
308 }
309 }
310
311
312
313
314
315
316
317
318 private void loadOwnersPetsAndVisits(List<Owner> owners) {
319 for (Owner owner : owners) {
320 loadPetsAndVisits(owner);
321 }
322 }
323
324
325
326
327
328 private class JdbcPetRowMapper implements ParameterizedRowMapper<JdbcPet> {
329
330 public JdbcPet mapRow(ResultSet rs, int rownum) throws SQLException {
331 JdbcPet pet = new JdbcPet();
332 pet.setId(rs.getInt("id"));
333 pet.setName(rs.getString("name"));
334 pet.setBirthDate(rs.getDate("birth_date"));
335 pet.setTypeId(rs.getInt("type_id"));
336 pet.setOwnerId(rs.getInt("owner_id"));
337 return pet;
338 }
339 }
340
341 }