Merge pull request #2 from gordonad/master

Build and logging improvements
This commit is contained in:
michaelisvy 2013-02-19 16:59:04 -08:00
commit ed116de007
90 changed files with 3393 additions and 2999 deletions

1254
pom.xml

File diff suppressed because it is too large Load diff

View file

@ -21,28 +21,28 @@ import javax.persistence.Id;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
/** /**
* Simple JavaBean domain object with an id property. * Simple JavaBean domain object with an id property. Used as a base class for objects needing this property.
* Used as a base class for objects needing this property.
* *
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
*/ */
@MappedSuperclass @MappedSuperclass
public class BaseEntity { public class BaseEntity {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Id
protected Integer id; @GeneratedValue(strategy = GenerationType.IDENTITY)
protected Integer id;
public void setId(Integer id) {
this.id = id;
}
public Integer getId() { public void setId(Integer id) {
return id; this.id = id;
} }
public boolean isNew() { public Integer getId() {
return (this.id == null); return id;
} }
public boolean isNew() {
return (this.id == null);
}
} }

View file

@ -20,8 +20,8 @@ import javax.persistence.MappedSuperclass;
/** /**
* Simple JavaBean domain object adds a name property to <code>BaseEntity</code>. * Simple JavaBean domain object adds a name property to <code>BaseEntity</code>. Used as a base class for objects
* Used as a base class for objects needing these properties. * needing these properties.
* *
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
@ -29,21 +29,21 @@ import javax.persistence.MappedSuperclass;
@MappedSuperclass @MappedSuperclass
public class NamedEntity extends BaseEntity { public class NamedEntity extends BaseEntity {
@Column(name="name") @Column(name = "name")
private String name; private String name;
public void setName(String name) {
this.name = name;
}
public String getName() { public void setName(String name) {
return this.name; this.name = name;
} }
@Override public String getName() {
public String toString() { return this.name;
return this.getName(); }
}
@Override
public String toString() {
return this.getName();
}
} }

View file

@ -15,24 +15,15 @@
*/ */
package org.springframework.samples.petclinic.model; package org.springframework.samples.petclinic.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.Digits;
import org.hibernate.validator.constraints.NotEmpty; import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.MutableSortDefinition;
import org.springframework.beans.support.PropertyComparator; import org.springframework.beans.support.PropertyComparator;
import org.springframework.core.style.ToStringCreator; import org.springframework.core.style.ToStringCreator;
import javax.persistence.*;
import javax.validation.constraints.Digits;
import java.util.*;
/** /**
* Simple JavaBean domain object representing an owner. * Simple JavaBean domain object representing an owner.
* *
@ -41,111 +32,113 @@ import org.springframework.core.style.ToStringCreator;
* @author Sam Brannen * @author Sam Brannen
* @author Michael Isvy * @author Michael Isvy
*/ */
@Entity @Table(name="owners") @Entity
@Table(name = "owners")
public class Owner extends Person { public class Owner extends Person {
@Column(name="address") @Column(name = "address")
@NotEmpty @NotEmpty
private String address; private String address;
@Column(name="city")
@NotEmpty
private String city;
@Column(name="telephone") @Column(name = "city")
@NotEmpty @Digits(fraction = 0, integer = 10) @NotEmpty
private String telephone; private String city;
@OneToMany(cascade=CascadeType.ALL, mappedBy="owner") @Column(name = "telephone")
private Set<Pet> pets; @NotEmpty
@Digits(fraction = 0, integer = 10)
private String telephone;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
private Set<Pet> pets;
public String getAddress() { public String getAddress() {
return this.address; return this.address;
} }
public void setAddress(String address) { public void setAddress(String address) {
this.address = address; this.address = address;
} }
public String getCity() { public String getCity() {
return this.city; return this.city;
} }
public void setCity(String city) { public void setCity(String city) {
this.city = city; this.city = city;
} }
public String getTelephone() { public String getTelephone() {
return this.telephone; return this.telephone;
} }
public void setTelephone(String telephone) { public void setTelephone(String telephone) {
this.telephone = telephone; this.telephone = telephone;
} }
protected void setPetsInternal(Set<Pet> pets) { protected void setPetsInternal(Set<Pet> pets) {
this.pets = pets; this.pets = pets;
} }
protected Set<Pet> getPetsInternal() { protected Set<Pet> getPetsInternal() {
if (this.pets == null) { if (this.pets == null) {
this.pets = new HashSet<Pet>(); this.pets = new HashSet<Pet>();
} }
return this.pets; return this.pets;
} }
public List<Pet> getPets() { public List<Pet> getPets() {
List<Pet> sortedPets = new ArrayList<Pet>(getPetsInternal()); List<Pet> sortedPets = new ArrayList<Pet>(getPetsInternal());
PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true)); PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true));
return Collections.unmodifiableList(sortedPets); return Collections.unmodifiableList(sortedPets);
} }
public void addPet(Pet pet) { public void addPet(Pet pet) {
getPetsInternal().add(pet); getPetsInternal().add(pet);
pet.setOwner(this); pet.setOwner(this);
} }
/** /**
* Return the Pet with the given name, or null if none found for this Owner. * Return the Pet with the given name, or null if none found for this Owner.
* *
* @param name to test * @param name to test
* @return true if pet name is already in use * @return true if pet name is already in use
*/ */
public Pet getPet(String name) { public Pet getPet(String name) {
return getPet(name, false); return getPet(name, false);
} }
/** /**
* Return the Pet with the given name, or null if none found for this Owner. * Return the Pet with the given name, or null if none found for this Owner.
* *
* @param name to test * @param name to test
* @return true if pet name is already in use * @return true if pet name is already in use
*/ */
public Pet getPet(String name, boolean ignoreNew) { public Pet getPet(String name, boolean ignoreNew) {
name = name.toLowerCase(); name = name.toLowerCase();
for (Pet pet : getPetsInternal()) { for (Pet pet : getPetsInternal()) {
if (!ignoreNew || !pet.isNew()) { if (!ignoreNew || !pet.isNew()) {
String compName = pet.getName(); String compName = pet.getName();
compName = compName.toLowerCase(); compName = compName.toLowerCase();
if (compName.equals(name)) { if (compName.equals(name)) {
return pet; return pet;
} }
} }
} }
return null; return null;
} }
@Override @Override
public String toString() { public String toString() {
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

@ -15,11 +15,11 @@
*/ */
package org.springframework.samples.petclinic.model; package org.springframework.samples.petclinic.model;
import org.hibernate.validator.constraints.NotEmpty;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
import org.hibernate.validator.constraints.NotEmpty;
/** /**
* Simple JavaBean domain object representing an person. * Simple JavaBean domain object representing an person.
* *
@ -27,31 +27,30 @@ import org.hibernate.validator.constraints.NotEmpty;
*/ */
@MappedSuperclass @MappedSuperclass
public class Person extends BaseEntity { public class Person extends BaseEntity {
@Column(name="first_name")
@NotEmpty
protected String firstName;
@Column(name="last_name") @Column(name = "first_name")
@NotEmpty @NotEmpty
protected String lastName; protected String firstName;
public String getFirstName() { @Column(name = "last_name")
return this.firstName; @NotEmpty
} protected String lastName;
public void setFirstName(String firstName) { public String getFirstName() {
this.firstName = firstName; return this.firstName;
} }
public String getLastName() { public void setFirstName(String firstName) {
return this.lastName; this.firstName = firstName;
} }
public void setLastName(String lastName) { public String getLastName() {
this.lastName = lastName; return this.lastName;
} }
public void setLastName(String lastName) {
this.lastName = lastName;
}
} }

View file

@ -15,27 +15,15 @@
*/ */
package org.springframework.samples.petclinic.model; package org.springframework.samples.petclinic.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.Type; import org.hibernate.annotations.Type;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.MutableSortDefinition;
import org.springframework.beans.support.PropertyComparator; import org.springframework.beans.support.PropertyComparator;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
import javax.persistence.*;
import java.util.*;
/** /**
* Simple business object representing a pet. * Simple business object representing a pet.
* *
@ -43,70 +31,71 @@ import org.springframework.format.annotation.DateTimeFormat;
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sam Brannen * @author Sam Brannen
*/ */
@Entity @Table(name="pets") @Entity
@Table(name = "pets")
public class Pet extends NamedEntity { public class Pet extends NamedEntity {
@Column(name="birth_date") @Column(name = "birth_date")
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime") @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
@DateTimeFormat(pattern="yyyy/MM/dd") @DateTimeFormat(pattern = "yyyy/MM/dd")
private DateTime birthDate; private DateTime birthDate;
@ManyToOne @ManyToOne
@JoinColumn(name = "type_id") @JoinColumn(name = "type_id")
private PetType type; private PetType type;
@ManyToOne @ManyToOne
@JoinColumn(name = "owner_id") @JoinColumn(name = "owner_id")
private Owner owner; private Owner owner;
@OneToMany(cascade=CascadeType.ALL, mappedBy="pet", fetch=FetchType.EAGER) @OneToMany(cascade = CascadeType.ALL, mappedBy = "pet", fetch = FetchType.EAGER)
private Set<Visit> visits; private Set<Visit> visits;
public void setBirthDate(DateTime birthDate) { public void setBirthDate(DateTime birthDate) {
this.birthDate = birthDate; this.birthDate = birthDate;
} }
public DateTime getBirthDate() { public DateTime getBirthDate() {
return this.birthDate; return this.birthDate;
} }
public void setType(PetType type) { public void setType(PetType type) {
this.type = type; this.type = type;
} }
public PetType getType() { public PetType getType() {
return this.type; return this.type;
} }
protected void setOwner(Owner owner) { protected void setOwner(Owner owner) {
this.owner = owner; this.owner = owner;
} }
public Owner getOwner() { public Owner getOwner() {
return this.owner; return this.owner;
} }
protected void setVisitsInternal(Set<Visit> visits) { protected void setVisitsInternal(Set<Visit> visits) {
this.visits = visits; this.visits = visits;
} }
protected Set<Visit> getVisitsInternal() { protected Set<Visit> getVisitsInternal() {
if (this.visits == null) { if (this.visits == null) {
this.visits = new HashSet<Visit>(); this.visits = new HashSet<Visit>();
} }
return this.visits; return this.visits;
} }
public List<Visit> getVisits() { public List<Visit> getVisits() {
List<Visit> sortedVisits = new ArrayList<Visit>(getVisitsInternal()); List<Visit> sortedVisits = new ArrayList<Visit>(getVisitsInternal());
PropertyComparator.sort(sortedVisits, new MutableSortDefinition("date", false, false)); PropertyComparator.sort(sortedVisits, new MutableSortDefinition("date", false, false));
return Collections.unmodifiableList(sortedVisits); return Collections.unmodifiableList(sortedVisits);
} }
public void addVisit(Visit visit) { public void addVisit(Visit visit) {
getVisitsInternal().add(visit); getVisitsInternal().add(visit);
visit.setPet(this); visit.setPet(this);
} }
} }

View file

@ -21,7 +21,8 @@ import javax.persistence.Table;
/** /**
* @author Juergen Hoeller * @author Juergen Hoeller
*/ */
@Entity @Table(name="types") @Entity
@Table(name = "types")
public class PetType extends NamedEntity { public class PetType extends NamedEntity {
} }

View file

@ -20,10 +20,11 @@ import javax.persistence.Table;
/** /**
* Models a {@link Vet Vet's} specialty (for example, dentistry). * Models a {@link Vet Vet's} specialty (for example, dentistry).
* *
* @author Juergen Hoeller * @author Juergen Hoeller
*/ */
@Entity @Table(name="specialties") @Entity
@Table(name = "specialties")
public class Specialty extends NamedEntity { public class Specialty extends NamedEntity {
} }

View file

@ -15,23 +15,13 @@
*/ */
package org.springframework.samples.petclinic.model; package org.springframework.samples.petclinic.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlElement;
import org.springframework.beans.support.MutableSortDefinition; import org.springframework.beans.support.MutableSortDefinition;
import org.springframework.beans.support.PropertyComparator; import org.springframework.beans.support.PropertyComparator;
import javax.persistence.*;
import javax.xml.bind.annotation.XmlElement;
import java.util.*;
/** /**
* Simple JavaBean domain object representing a veterinarian. * Simple JavaBean domain object representing a veterinarian.
* *
@ -40,39 +30,40 @@ import org.springframework.beans.support.PropertyComparator;
* @author Sam Brannen * @author Sam Brannen
* @author Arjen Poutsma * @author Arjen Poutsma
*/ */
@Entity @Table(name="vets") @Entity
@Table(name = "vets")
public class Vet extends Person { public class Vet extends Person {
@ManyToMany(fetch=FetchType.EAGER) @ManyToMany(fetch = FetchType.EAGER)
@JoinTable (name="vet_specialties",joinColumns = @JoinColumn(name = "vet_id"), @JoinTable(name = "vet_specialties", joinColumns = @JoinColumn(name = "vet_id"),
inverseJoinColumns= @JoinColumn(name = "specialty_id")) inverseJoinColumns = @JoinColumn(name = "specialty_id"))
private Set<Specialty> specialties; private Set<Specialty> specialties;
protected void setSpecialtiesInternal(Set<Specialty> specialties) { protected void setSpecialtiesInternal(Set<Specialty> specialties) {
this.specialties = specialties; this.specialties = specialties;
} }
protected Set<Specialty> getSpecialtiesInternal() { protected Set<Specialty> getSpecialtiesInternal() {
if (this.specialties == null) { if (this.specialties == null) {
this.specialties = new HashSet<Specialty>(); this.specialties = new HashSet<Specialty>();
} }
return this.specialties; return this.specialties;
} }
@XmlElement @XmlElement
public List<Specialty> getSpecialties() { public List<Specialty> getSpecialties() {
List<Specialty> sortedSpecs = new ArrayList<Specialty>(getSpecialtiesInternal()); List<Specialty> sortedSpecs = new ArrayList<Specialty>(getSpecialtiesInternal());
PropertyComparator.sort(sortedSpecs, new MutableSortDefinition("name", true, true)); PropertyComparator.sort(sortedSpecs, new MutableSortDefinition("name", true, true));
return Collections.unmodifiableList(sortedSpecs); return Collections.unmodifiableList(sortedSpecs);
} }
public int getNrOfSpecialties() { public int getNrOfSpecialties() {
return getSpecialtiesInternal().size(); return getSpecialtiesInternal().size();
} }
public void addSpecialty(Specialty specialty) { public void addSpecialty(Specialty specialty) {
getSpecialtiesInternal().add(specialty); getSpecialtiesInternal().add(specialty);
} }
} }

View file

@ -16,29 +16,28 @@
*/ */
package org.springframework.samples.petclinic.model; package org.springframework.samples.petclinic.model;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/** /**
* Simple domain object representing a list of veterinarians. Mostly here to be used for the 'vets' * Simple domain object representing a list of veterinarians. Mostly here to be used for the 'vets' {@link
* {@link org.springframework.web.servlet.view.xml.MarshallingView}. * org.springframework.web.servlet.view.xml.MarshallingView}.
* *
* @author Arjen Poutsma * @author Arjen Poutsma
*/ */
@XmlRootElement @XmlRootElement
public class Vets { public class Vets {
private List<Vet> vets; private List<Vet> vets;
@XmlElement @XmlElement
public List<Vet> getVetList() { public List<Vet> getVetList() {
if (vets == null) { if (vets == null) {
vets = new ArrayList<Vet>(); vets = new ArrayList<Vet>();
} }
return vets; return vets;
} }
} }

View file

@ -15,88 +15,105 @@
*/ */
package org.springframework.samples.petclinic.model; package org.springframework.samples.petclinic.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.annotations.Type; import org.hibernate.annotations.Type;
import org.hibernate.validator.constraints.NotEmpty; import org.hibernate.validator.constraints.NotEmpty;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
import javax.persistence.*;
/** /**
* Simple JavaBean domain object representing a visit. * Simple JavaBean domain object representing a visit.
* *
* @author Ken Krebs * @author Ken Krebs
*/ */
@Entity @Table(name="visits") @Entity
@Table(name = "visits")
public class Visit extends BaseEntity { public class Visit extends BaseEntity {
/** Holds value of property date. */ /**
@Column(name="visit_date") * Holds value of property date.
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime") */
@DateTimeFormat(pattern="yyyy/MM/dd") @Column(name = "visit_date")
private DateTime date; @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
@DateTimeFormat(pattern = "yyyy/MM/dd")
private DateTime date;
/** Holds value of property description. */ /**
@NotEmpty * Holds value of property description.
@Column(name="description") */
private String description; @NotEmpty
@Column(name = "description")
private String description;
/** Holds value of property pet. */ /**
@ManyToOne * Holds value of property pet.
*/
@ManyToOne
@JoinColumn(name = "pet_id") @JoinColumn(name = "pet_id")
private Pet pet; private Pet pet;
/** Creates a new instance of Visit for the current date */ /**
public Visit() { * Creates a new instance of Visit for the current date
this.date = new DateTime(); */
} public Visit() {
this.date = new DateTime();
}
/** Getter for property date. /**
* @return Value of property date. * Getter for property date.
*/ *
public DateTime getDate() { * @return Value of property date.
return this.date; */
} public DateTime getDate() {
return this.date;
}
/** Setter for property date. /**
* @param date New value of property date. * Setter for property date.
*/ *
public void setDate(DateTime date) { * @param date New value of property date.
this.date = date; */
} public void setDate(DateTime date) {
this.date = date;
}
/** Getter for property description. /**
* @return Value of property description. * Getter for property description.
*/ *
public String getDescription() { * @return Value of property description.
return this.description; */
} public String getDescription() {
return this.description;
}
/** Setter for property description. /**
* @param description New value of property description. * Setter for property description.
*/ *
public void setDescription(String description) { * @param description New value of property description.
this.description = description; */
} public void setDescription(String description) {
this.description = description;
}
/** Getter for property pet. /**
* @return Value of property pet. * Getter for property pet.
*/ *
public Pet getPet() { * @return Value of property pet.
return this.pet; */
} public Pet getPet() {
return this.pet;
}
/** Setter for property pet. /**
* @param pet New value of property pet. * Setter for property pet.
*/ *
public void setPet(Pet pet) { * @param pet New value of property pet.
this.pet = pet; */
} public void setPet(Pet pet) {
this.pet = pet;
}
} }

View file

@ -30,49 +30,51 @@
*/ */
package org.springframework.samples.petclinic.repository; package org.springframework.samples.petclinic.repository;
import java.util.Collection;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.samples.petclinic.model.BaseEntity; import org.springframework.samples.petclinic.model.BaseEntity;
import org.springframework.samples.petclinic.model.Owner; import org.springframework.samples.petclinic.model.Owner;
import java.util.Collection;
/** /**
* Repository class for <code>Owner</code> domain objects * Repository class for <code>Owner</code> domain objects All method names are compliant with Spring Data naming
* All method names are compliant with Spring Data naming conventions so this interface can easily be * conventions so this interface can easily be extended for Spring Data See here: http://static.springsource.org/spring-data/jpa/docs/current/reference/html/jpa.repositories.html#jpa.query-methods.query-creation
* extended for Spring Data *
* See here: http://static.springsource.org/spring-data/jpa/docs/current/reference/html/jpa.repositories.html#jpa.query-methods.query-creation
*
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sam Brannen * @author Sam Brannen
* @author Michael Isvy * @author Michael Isvy
*/ */
public interface OwnerRepository { public interface OwnerRepository {
/** /**
* Retrieve <code>Owner</code>s from the data store by last name, * Retrieve <code>Owner</code>s from the data store by last name, returning all owners whose last name <i>starts</i>
* returning all owners whose last name <i>starts</i> with the given name. * with the given name.
* @param lastName Value to search for *
* @return a <code>Collection</code> of matching <code>Owner</code>s * @param lastName Value to search for
* (or an empty <code>Collection</code> if none found) * @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; */
Collection<Owner> findByLastName(String lastName) throws DataAccessException;
/** /**
* Retrieve an <code>Owner</code> from the data store by id. * 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 * @param id the id to search for
* @throws org.springframework.dao.DataRetrievalFailureException if not found * @return the <code>Owner</code> if found
*/ * @throws org.springframework.dao.DataRetrievalFailureException
Owner findById(int id) throws DataAccessException; * if not found
*/
Owner findById(int id) throws DataAccessException;
/** /**
* Save an <code>Owner</code> to the data store, either inserting or updating it. * 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 * @param owner the <code>Owner</code> to save
*/ * @see BaseEntity#isNew
void save(Owner owner) throws DataAccessException; */
void save(Owner owner) throws DataAccessException;
} }

View file

@ -15,18 +15,16 @@
*/ */
package org.springframework.samples.petclinic.repository; package org.springframework.samples.petclinic.repository;
import java.util.List;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.samples.petclinic.model.BaseEntity; import org.springframework.samples.petclinic.model.BaseEntity;
import org.springframework.samples.petclinic.model.Pet; import org.springframework.samples.petclinic.model.Pet;
import org.springframework.samples.petclinic.model.PetType; import org.springframework.samples.petclinic.model.PetType;
import java.util.List;
/** /**
* Repository class for <code>Pet</code> domain objects * Repository class for <code>Pet</code> domain objects All method names are compliant with Spring Data naming
* All method names are compliant with Spring Data naming conventions so this interface can easily be * conventions so this interface can easily be extended for Spring Data See here: http://static.springsource.org/spring-data/jpa/docs/current/reference/html/jpa.repositories.html#jpa.query-methods.query-creation
* extended for Spring Data
* See here: http://static.springsource.org/spring-data/jpa/docs/current/reference/html/jpa.repositories.html#jpa.query-methods.query-creation
* *
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
@ -35,25 +33,29 @@ import org.springframework.samples.petclinic.model.PetType;
*/ */
public interface PetRepository { public interface PetRepository {
/** /**
* Retrieve all <code>PetType</code>s from the data store. * Retrieve all <code>PetType</code>s from the data store.
* @return a <code>Collection</code> of <code>PetType</code>s *
*/ * @return a <code>Collection</code> of <code>PetType</code>s
List<PetType> findPetTypes() throws DataAccessException; */
List<PetType> findPetTypes() throws DataAccessException;
/** /**
* Retrieve a <code>Pet</code> from the data store by id. * 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 * @param id the id to search for
* @throws org.springframework.dao.DataRetrievalFailureException if not found * @return the <code>Pet</code> if found
*/ * @throws org.springframework.dao.DataRetrievalFailureException
Pet findById(int id) throws DataAccessException; * if not found
*/
Pet findById(int id) throws DataAccessException;
/** /**
* Save a <code>Pet</code> to the data store, either inserting or updating it. * 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 * @param pet the <code>Pet</code> to save
*/ * @see BaseEntity#isNew
void save(Pet pet) throws DataAccessException; */
void save(Pet pet) throws DataAccessException;
} }

View file

@ -15,16 +15,14 @@
*/ */
package org.springframework.samples.petclinic.repository; package org.springframework.samples.petclinic.repository;
import java.util.Collection;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.samples.petclinic.model.Vet; import org.springframework.samples.petclinic.model.Vet;
import java.util.Collection;
/** /**
* Repository class for <code>Vet</code> domain objects * Repository class for <code>Vet</code> domain objects All method names are compliant with Spring Data naming
* All method names are compliant with Spring Data naming conventions so this interface can easily be * conventions so this interface can easily be extended for Spring Data See here: http://static.springsource.org/spring-data/jpa/docs/current/reference/html/jpa.repositories.html#jpa.query-methods.query-creation
* extended for Spring Data
* See here: http://static.springsource.org/spring-data/jpa/docs/current/reference/html/jpa.repositories.html#jpa.query-methods.query-creation
* *
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
@ -33,11 +31,12 @@ import org.springframework.samples.petclinic.model.Vet;
*/ */
public interface VetRepository { public interface VetRepository {
/** /**
* Retrieve all <code>Vet</code>s from the data store. * Retrieve all <code>Vet</code>s from the data store.
* @return a <code>Collection</code> of <code>Vet</code>s *
*/ * @return a <code>Collection</code> of <code>Vet</code>s
Collection<Vet> findAll() throws DataAccessException; */
Collection<Vet> findAll() throws DataAccessException;
} }

View file

@ -15,17 +15,15 @@
*/ */
package org.springframework.samples.petclinic.repository; package org.springframework.samples.petclinic.repository;
import java.util.List;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.samples.petclinic.model.BaseEntity; import org.springframework.samples.petclinic.model.BaseEntity;
import org.springframework.samples.petclinic.model.Visit; import org.springframework.samples.petclinic.model.Visit;
import java.util.List;
/** /**
* Repository class for <code>Visit</code> domain objects * Repository class for <code>Visit</code> domain objects All method names are compliant with Spring Data naming
* All method names are compliant with Spring Data naming conventions so this interface can easily be * conventions so this interface can easily be extended for Spring Data See here: http://static.springsource.org/spring-data/jpa/docs/current/reference/html/jpa.repositories.html#jpa.query-methods.query-creation
* extended for Spring Data
* See here: http://static.springsource.org/spring-data/jpa/docs/current/reference/html/jpa.repositories.html#jpa.query-methods.query-creation
* *
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
@ -34,13 +32,14 @@ import org.springframework.samples.petclinic.model.Visit;
*/ */
public interface VisitRepository { public interface VisitRepository {
/** /**
* Save a <code>Visit</code> to the data store, either inserting or updating it. * 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 * @param visit the <code>Visit</code> to save
*/ * @see BaseEntity#isNew
void save(Visit visit) throws DataAccessException; */
void save(Visit visit) throws DataAccessException;
List<Visit> findByPetId(Integer petId); List<Visit> findByPetId(Integer petId);
} }

View file

@ -15,13 +15,6 @@
*/ */
package org.springframework.samples.petclinic.repository.jdbc; package org.springframework.samples.petclinic.repository.jdbc;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.dao.EmptyResultDataAccessException;
@ -39,10 +32,15 @@ import org.springframework.samples.petclinic.repository.VisitRepository;
import org.springframework.samples.petclinic.util.EntityUtils; import org.springframework.samples.petclinic.util.EntityUtils;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import javax.sql.DataSource;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** /**
* A simple JDBC-based implementation of the {@link OwnerRepository} interface. * A simple JDBC-based implementation of the {@link OwnerRepository} interface.
* *
*
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Rob Harrop * @author Rob Harrop
@ -53,119 +51,115 @@ import org.springframework.stereotype.Repository;
@Repository @Repository
public class JdbcOwnerRepositoryImpl implements OwnerRepository { public class JdbcOwnerRepositoryImpl implements OwnerRepository {
private VisitRepository visitRepository; private VisitRepository visitRepository;
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private SimpleJdbcInsert insertOwner; private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@Autowired private SimpleJdbcInsert insertOwner;
public JdbcOwnerRepositoryImpl(DataSource dataSource, NamedParameterJdbcTemplate namedParameterJdbcTemplate,
VisitRepository visitRepository) {
this.insertOwner = new SimpleJdbcInsert(dataSource) @Autowired
.withTableName("owners") public JdbcOwnerRepositoryImpl(DataSource dataSource, NamedParameterJdbcTemplate namedParameterJdbcTemplate,
.usingGeneratedKeyColumns("id"); VisitRepository visitRepository) {
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
this.visitRepository = visitRepository; this.insertOwner = new SimpleJdbcInsert(dataSource)
} .withTableName("owners")
.usingGeneratedKeyColumns("id");
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
this.visitRepository = visitRepository;
}
/**
* 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.
*/
@Override
public Collection<Owner> findByLastName(String lastName) throws DataAccessException {
Map<String, Object> params = new HashMap<String, Object>();
params.put("lastName", lastName + "%");
List<Owner> owners = this.namedParameterJdbcTemplate.query(
"SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE last_name like :lastName",
params,
ParameterizedBeanPropertyRowMapper.newInstance(Owner.class)
);
loadOwnersPetsAndVisits(owners);
return owners;
}
/** /**
* Loads {@link Owner Owners} from the data store by last name, returning * Loads the {@link Owner} with the supplied <code>id</code>; also loads the {@link Pet Pets} and {@link Visit Visits}
* all owners whose last name <i>starts</i> with the given name; also loads * for the corresponding owner, if not already loaded.
* the {@link Pet Pets} and {@link Visit Visits} for the corresponding */
* owners, if not already loaded. @Override
*/ public Owner findById(int id) throws DataAccessException {
public Collection<Owner> findByLastName(String lastName) throws DataAccessException { Owner owner;
Map<String, Object> params = new HashMap<String, Object>(); try {
params.put("lastName", lastName+"%"); Map<String, Object> params = new HashMap<String, Object>();
List<Owner> owners = this.namedParameterJdbcTemplate.query( params.put("id", id);
"SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE last_name like :lastName", owner = this.namedParameterJdbcTemplate.queryForObject(
params, "SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE id= :id",
ParameterizedBeanPropertyRowMapper.newInstance(Owner.class) params,
); ParameterizedBeanPropertyRowMapper.newInstance(Owner.class)
loadOwnersPetsAndVisits(owners); );
return owners; } catch (EmptyResultDataAccessException ex) {
} throw new ObjectRetrievalFailureException(Owner.class, new Integer(id));
}
loadPetsAndVisits(owner);
return owner;
}
/** public void loadPetsAndVisits(final Owner owner) {
* Loads the {@link Owner} with the supplied <code>id</code>; also loads Map<String, Object> params = new HashMap<String, Object>();
* the {@link Pet Pets} and {@link Visit Visits} for the corresponding params.put("id", owner.getId().intValue());
* owner, if not already loaded. final List<JdbcPet> pets = this.namedParameterJdbcTemplate.query(
*/ "SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE owner_id=:id",
public Owner findById(int id) throws DataAccessException { params,
Owner owner; new JdbcPetRowMapper()
try { );
Map<String, Object> params = new HashMap<String, Object>(); for (JdbcPet pet : pets) {
params.put("id", id); owner.addPet(pet);
owner = this.namedParameterJdbcTemplate.queryForObject( pet.setType(EntityUtils.getById(getPetTypes(), PetType.class, pet.getTypeId()));
"SELECT id, first_name, last_name, address, city, telephone FROM owners WHERE id= :id", List<Visit> visits = this.visitRepository.findByPetId(pet.getId());
params, for (Visit visit : visits) {
ParameterizedBeanPropertyRowMapper.newInstance(Owner.class) pet.addVisit(visit);
); }
} }
catch (EmptyResultDataAccessException ex) { }
throw new ObjectRetrievalFailureException(Owner.class, new Integer(id));
}
loadPetsAndVisits(owner);
return owner;
}
public void loadPetsAndVisits(final Owner owner) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("id", owner.getId().intValue());
final List<JdbcPet> pets = this.namedParameterJdbcTemplate.query(
"SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE owner_id=:id",
params,
new JdbcPetRowMapper()
);
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);
}
}
}
public void save(Owner owner) throws DataAccessException { @Override
BeanPropertySqlParameterSource parameterSource = new BeanPropertySqlParameterSource(owner); public void save(Owner owner) throws DataAccessException {
if (owner.isNew()) { BeanPropertySqlParameterSource parameterSource = new BeanPropertySqlParameterSource(owner);
Number newKey = this.insertOwner.executeAndReturnKey(parameterSource); if (owner.isNew()) {
owner.setId(newKey.intValue()); Number newKey = this.insertOwner.executeAndReturnKey(parameterSource);
} owner.setId(newKey.intValue());
else { } else {
this.namedParameterJdbcTemplate.update( this.namedParameterJdbcTemplate.update(
"UPDATE owners SET first_name=:firstName, last_name=:lastName, address=:address, " + "UPDATE owners SET first_name=:firstName, last_name=:lastName, address=:address, " +
"city=:city, telephone=:telephone WHERE id=:id", "city=:city, telephone=:telephone WHERE id=:id",
parameterSource); parameterSource);
} }
} }
public Collection<PetType> getPetTypes() throws DataAccessException { public Collection<PetType> getPetTypes() throws DataAccessException {
return this.namedParameterJdbcTemplate.query( return this.namedParameterJdbcTemplate.query(
"SELECT id, name FROM types ORDER BY name", new HashMap<String,Object>(), "SELECT id, name FROM types ORDER BY name", new HashMap<String, Object>(),
ParameterizedBeanPropertyRowMapper.newInstance(PetType.class)); ParameterizedBeanPropertyRowMapper.newInstance(PetType.class));
} }
/** /**
* Loads the {@link Pet} and {@link Visit} data for the supplied * Loads the {@link Pet} and {@link Visit} data for the supplied {@link List} of {@link Owner Owners}.
* {@link List} of {@link Owner Owners}. *
* * @param owners the list of owners for whom the pet and visit data should be loaded
* @param owners the list of owners for whom the pet and visit data should be loaded * @see #loadPetsAndVisits(Owner)
* @see #loadPetsAndVisits(Owner) */
*/ private void loadOwnersPetsAndVisits(List<Owner> owners) {
private void loadOwnersPetsAndVisits(List<Owner> owners) { for (Owner owner : owners) {
for (Owner owner : owners) { loadPetsAndVisits(owner);
loadPetsAndVisits(owner); }
} }
}
} }

View file

@ -18,33 +18,33 @@ package org.springframework.samples.petclinic.repository.jdbc;
import org.springframework.samples.petclinic.model.Pet; import org.springframework.samples.petclinic.model.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
* are only relevant for a JDBC implmentation of the ClinicService. * ClinicService.
* *
* @author Juergen Hoeller * @author Juergen Hoeller
* @see JdbcClinicImpl * @see JdbcClinicImpl
*/ */
class JdbcPet extends Pet { class JdbcPet extends Pet {
private int typeId; private int typeId;
private int ownerId; private int ownerId;
public void setTypeId(int typeId) { public void setTypeId(int typeId) {
this.typeId = typeId; this.typeId = typeId;
} }
public int getTypeId() { public int getTypeId() {
return this.typeId; return this.typeId;
} }
public void setOwnerId(int ownerId) { public void setOwnerId(int ownerId) {
this.ownerId = ownerId; this.ownerId = ownerId;
} }
public int getOwnerId() { public int getOwnerId() {
return this.ownerId; return this.ownerId;
} }
} }

View file

@ -15,12 +15,6 @@
*/ */
package org.springframework.samples.petclinic.repository.jdbc; package org.springframework.samples.petclinic.repository.jdbc;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.dao.EmptyResultDataAccessException;
@ -39,8 +33,12 @@ import org.springframework.samples.petclinic.repository.VisitRepository;
import org.springframework.samples.petclinic.util.EntityUtils; import org.springframework.samples.petclinic.util.EntityUtils;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** /**
*
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Rob Harrop * @author Rob Harrop
@ -51,84 +49,84 @@ import org.springframework.stereotype.Repository;
@Repository @Repository
public class JdbcPetRepositoryImpl implements PetRepository { public class JdbcPetRepositoryImpl implements PetRepository {
private NamedParameterJdbcTemplate namedParameterJdbcTemplate; private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private SimpleJdbcInsert insertPet; private SimpleJdbcInsert insertPet;
private OwnerRepository ownerRepository;
private VisitRepository visitRepository;
@Autowired private OwnerRepository ownerRepository;
public JdbcPetRepositoryImpl(DataSource dataSource, OwnerRepository ownerRepository, VisitRepository visitRepository) {
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
this.insertPet = new SimpleJdbcInsert(dataSource) private VisitRepository visitRepository;
.withTableName("pets")
.usingGeneratedKeyColumns("id");
this.ownerRepository = ownerRepository;
this.visitRepository = visitRepository;
}
public List<PetType> findPetTypes() throws DataAccessException {
Map<String, Object> params = new HashMap<String,Object>();
return this.namedParameterJdbcTemplate.query(
"SELECT id, name FROM types ORDER BY name",
params,
ParameterizedBeanPropertyRowMapper.newInstance(PetType.class));
}
public Pet findById(int id) throws DataAccessException { @Autowired
JdbcPet pet; public JdbcPetRepositoryImpl(DataSource dataSource, OwnerRepository ownerRepository, VisitRepository visitRepository) {
try { this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
Map<String, Object> params = new HashMap<String, Object>();
params.put("id", id);
pet = this.namedParameterJdbcTemplate.queryForObject(
"SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE id=:id",
params,
new JdbcPetRowMapper());
}
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(findPetTypes(), PetType.class, pet.getTypeId()));
List<Visit> visits = this.visitRepository.findByPetId(pet.getId());
for (Visit visit : visits) {
pet.addVisit(visit);
}
return pet;
}
public void save(Pet pet) throws DataAccessException { this.insertPet = new SimpleJdbcInsert(dataSource)
if (pet.isNew()) { .withTableName("pets")
Number newKey = this.insertPet.executeAndReturnKey( .usingGeneratedKeyColumns("id");
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));
}
}
/** this.ownerRepository = ownerRepository;
* Creates a {@link MapSqlParameterSource} based on data values from the this.visitRepository = visitRepository;
* supplied {@link Pet} instance. }
*/
private MapSqlParameterSource createPetParameterSource(Pet pet) { @Override
return new MapSqlParameterSource() public List<PetType> findPetTypes() throws DataAccessException {
.addValue("id", pet.getId()) Map<String, Object> params = new HashMap<String, Object>();
.addValue("name", pet.getName()) return this.namedParameterJdbcTemplate.query(
.addValue("birth_date", pet.getBirthDate().toDate()) "SELECT id, name FROM types ORDER BY name",
.addValue("type_id", pet.getType().getId()) params,
.addValue("owner_id", pet.getOwner().getId()); ParameterizedBeanPropertyRowMapper.newInstance(PetType.class));
} }
@Override
public Pet findById(int id) throws DataAccessException {
JdbcPet pet;
try {
Map<String, Object> params = new HashMap<String, Object>();
params.put("id", id);
pet = this.namedParameterJdbcTemplate.queryForObject(
"SELECT id, name, birth_date, type_id, owner_id FROM pets WHERE id=:id",
params,
new JdbcPetRowMapper());
} 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(findPetTypes(), PetType.class, pet.getTypeId()));
List<Visit> visits = this.visitRepository.findByPetId(pet.getId());
for (Visit visit : visits) {
pet.addVisit(visit);
}
return pet;
}
@Override
public void save(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().toDate())
.addValue("type_id", pet.getType().getId())
.addValue("owner_id", pet.getOwner().getId());
}
} }

View file

@ -15,27 +15,28 @@
*/ */
package org.springframework.samples.petclinic.repository.jdbc; package org.springframework.samples.petclinic.repository.jdbc;
import org.joda.time.DateTime;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Date; import java.util.Date;
import org.joda.time.DateTime;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
/** /**
* {@link ParameterizedRowMapper} implementation mapping data from a * {@link ParameterizedRowMapper} implementation mapping data from a {@link ResultSet} to the corresponding properties
* {@link ResultSet} to the corresponding properties of the {@link JdbcPet} class. * of the {@link JdbcPet} class.
*/ */
class JdbcPetRowMapper implements ParameterizedRowMapper<JdbcPet> { class JdbcPetRowMapper implements ParameterizedRowMapper<JdbcPet> {
public JdbcPet mapRow(ResultSet rs, int rownum) throws SQLException { @Override
JdbcPet pet = new JdbcPet(); public JdbcPet mapRow(ResultSet rs, int rownum) throws SQLException {
pet.setId(rs.getInt("id")); JdbcPet pet = new JdbcPet();
pet.setName(rs.getString("name")); pet.setId(rs.getInt("id"));
Date birthDate = rs.getDate("birth_date"); pet.setName(rs.getString("name"));
pet.setBirthDate(new DateTime(birthDate)); Date birthDate = rs.getDate("birth_date");
pet.setTypeId(rs.getInt("type_id")); pet.setBirthDate(new DateTime(birthDate));
pet.setOwnerId(rs.getInt("owner_id")); pet.setTypeId(rs.getInt("type_id"));
return pet; pet.setOwnerId(rs.getInt("owner_id"));
} return pet;
}
} }

View file

@ -15,12 +15,6 @@
*/ */
package org.springframework.samples.petclinic.repository.jdbc; 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 org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
@ -33,11 +27,16 @@ import org.springframework.samples.petclinic.repository.VetRepository;
import org.springframework.samples.petclinic.util.EntityUtils; import org.springframework.samples.petclinic.util.EntityUtils;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/** /**
* A simple JDBC-based implementation of the {@link VetRepository} interface. Uses @Cacheable to cache the result of the
* {@link findAll} method
* *
* A simple JDBC-based implementation of the {@link VetRepository} interface.
* Uses @Cacheable to cache the result of the {@link findAll} method
*
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Rob Harrop * @author Rob Harrop
@ -49,44 +48,48 @@ import org.springframework.stereotype.Repository;
@Repository @Repository
public class JdbcVetRepositoryImpl implements VetRepository { public class JdbcVetRepositoryImpl implements VetRepository {
private JdbcTemplate jdbcTemplate; private JdbcTemplate jdbcTemplate;
@Autowired @Autowired
public JdbcVetRepositoryImpl(JdbcTemplate jdbcTemplate) { public JdbcVetRepositoryImpl(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate; this.jdbcTemplate = jdbcTemplate;
} }
/** /**
* Refresh the cache of Vets that the ClinicService is holding. * Refresh the cache of Vets that the ClinicService is holding.
* @see org.springframework.samples.petclinic.model.service.ClinicService#findVets() *
*/ * @see org.springframework.samples.petclinic.model.service.ClinicService#findVets()
@Cacheable(value="vets") */
public Collection<Vet> findAll() throws DataAccessException { @Override
List<Vet> vets = new ArrayList<Vet>(); @Cacheable(value = "vets")
// Retrieve the list of all vets. public Collection<Vet> findAll() throws DataAccessException {
vets.addAll(this.jdbcTemplate.query( List<Vet> vets = new ArrayList<Vet>();
"SELECT id, first_name, last_name FROM vets ORDER BY last_name,first_name", // Retrieve the list of all vets.
ParameterizedBeanPropertyRowMapper.newInstance(Vet.class))); 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. // Retrieve the list of all possible specialties.
final List<Specialty> specialties = this.jdbcTemplate.query( final List<Specialty> specialties = this.jdbcTemplate.query(
"SELECT id, name FROM specialties", "SELECT id, name FROM specialties",
ParameterizedBeanPropertyRowMapper.newInstance(Specialty.class)); ParameterizedBeanPropertyRowMapper.newInstance(Specialty.class));
// Build each vet's list of specialties. // Build each vet's list of specialties.
for (Vet vet : vets) { for (Vet vet : vets) {
final List<Integer> vetSpecialtiesIds = this.jdbcTemplate.query( final List<Integer> vetSpecialtiesIds = this.jdbcTemplate.query(
"SELECT specialty_id FROM vet_specialties WHERE vet_id=?", "SELECT specialty_id FROM vet_specialties WHERE vet_id=?",
new ParameterizedRowMapper<Integer>() { new ParameterizedRowMapper<Integer>() {
public Integer mapRow(ResultSet rs, int row) throws SQLException { @Override
return Integer.valueOf(rs.getInt(1)); 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.getId().intValue());
vet.addSpecialty(specialty); for (int specialtyId : vetSpecialtiesIds) {
} Specialty specialty = EntityUtils.getById(specialties, Specialty.class, specialtyId);
} vet.addSpecialty(specialty);
return vets; }
} }
return vets;
}
} }

View file

@ -15,13 +15,6 @@
*/ */
package org.springframework.samples.petclinic.repository.jdbc; package org.springframework.samples.petclinic.repository.jdbc;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import javax.sql.DataSource;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
@ -33,10 +26,15 @@ import org.springframework.samples.petclinic.model.Visit;
import org.springframework.samples.petclinic.repository.VisitRepository; import org.springframework.samples.petclinic.repository.VisitRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import javax.sql.DataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
/** /**
* A simple JDBC-based implementation of the {@link VisitRepository} interface. * A simple JDBC-based implementation of the {@link VisitRepository} interface.
* *
*
* @author Ken Krebs * @author Ken Krebs
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Rob Harrop * @author Rob Harrop
@ -48,63 +46,64 @@ import org.springframework.stereotype.Repository;
@Repository @Repository
public class JdbcVisitRepositoryImpl implements VisitRepository { public class JdbcVisitRepositoryImpl implements VisitRepository {
private JdbcTemplate jdbcTemplate; private JdbcTemplate jdbcTemplate;
private SimpleJdbcInsert insertVisit; private SimpleJdbcInsert insertVisit;
@Autowired @Autowired
public JdbcVisitRepositoryImpl(DataSource dataSource) { public JdbcVisitRepositoryImpl(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource); this.jdbcTemplate = new JdbcTemplate(dataSource);
this.insertVisit = new SimpleJdbcInsert(dataSource) this.insertVisit = new SimpleJdbcInsert(dataSource)
.withTableName("visits") .withTableName("visits")
.usingGeneratedKeyColumns("id"); .usingGeneratedKeyColumns("id");
} }
public void save(Visit visit) throws DataAccessException { @Override
if (visit.isNew()) { public void save(Visit visit) throws DataAccessException {
Number newKey = this.insertVisit.executeAndReturnKey( if (visit.isNew()) {
createVisitParameterSource(visit)); Number newKey = this.insertVisit.executeAndReturnKey(
visit.setId(newKey.intValue()); createVisitParameterSource(visit));
} visit.setId(newKey.intValue());
else { } else {
throw new UnsupportedOperationException("Visit update not supported"); throw new UnsupportedOperationException("Visit update not supported");
} }
} }
public void deletePet(int id) throws DataAccessException { public void deletePet(int id) throws DataAccessException {
this.jdbcTemplate.update("DELETE FROM pets WHERE id=?", id); this.jdbcTemplate.update("DELETE FROM pets WHERE id=?", id);
} }
/** /**
* Creates a {@link MapSqlParameterSource} based on data values from the * Creates a {@link MapSqlParameterSource} based on data values from the supplied {@link Visit} instance.
* supplied {@link Visit} instance. */
*/ private MapSqlParameterSource createVisitParameterSource(Visit visit) {
private MapSqlParameterSource createVisitParameterSource(Visit visit) { return new MapSqlParameterSource()
return new MapSqlParameterSource() .addValue("id", visit.getId())
.addValue("id", visit.getId()) .addValue("visit_date", visit.getDate().toDate())
.addValue("visit_date", visit.getDate().toDate()) .addValue("description", visit.getDescription())
.addValue("description", visit.getDescription()) .addValue("pet_id", visit.getPet().getId());
.addValue("pet_id", visit.getPet().getId()); }
}
public List<Visit> findByPetId(Integer petId) { @Override
final List<Visit> visits = this.jdbcTemplate.query( public List<Visit> findByPetId(Integer petId) {
"SELECT id, visit_date, description FROM visits WHERE pet_id=?", final List<Visit> visits = this.jdbcTemplate.query(
new ParameterizedRowMapper<Visit>() { "SELECT id, visit_date, description FROM visits WHERE pet_id=?",
public Visit mapRow(ResultSet rs, int row) throws SQLException { new ParameterizedRowMapper<Visit>() {
Visit visit = new Visit(); @Override
visit.setId(rs.getInt("id")); public Visit mapRow(ResultSet rs, int row) throws SQLException {
Date visitDate = rs.getDate("visit_date"); Visit visit = new Visit();
visit.setDate(new DateTime(visitDate)); visit.setId(rs.getInt("id"));
visit.setDescription(rs.getString("description")); Date visitDate = rs.getDate("visit_date");
return visit; visit.setDate(new DateTime(visitDate));
} visit.setDescription(rs.getString("description"));
}, return visit;
petId); }
return visits; },
} petId);
return visits;
}
} }

View file

@ -15,15 +15,14 @@
*/ */
package org.springframework.samples.petclinic.repository.jpa; package org.springframework.samples.petclinic.repository.jpa;
import java.util.Collection; import org.springframework.samples.petclinic.model.Owner;
import org.springframework.samples.petclinic.repository.OwnerRepository;
import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext; import javax.persistence.PersistenceContext;
import javax.persistence.Query; import javax.persistence.Query;
import java.util.Collection;
import org.springframework.samples.petclinic.model.Owner;
import org.springframework.samples.petclinic.repository.OwnerRepository;
import org.springframework.stereotype.Repository;
/** /**
* JPA implementation of the {@link OwnerRepository} interface. * JPA implementation of the {@link OwnerRepository} interface.
@ -37,31 +36,34 @@ import org.springframework.stereotype.Repository;
@Repository @Repository
public class JpaOwnerRepositoryImpl implements OwnerRepository { public class JpaOwnerRepositoryImpl implements OwnerRepository {
@PersistenceContext @PersistenceContext
private EntityManager em; private EntityManager em;
@SuppressWarnings("unchecked")
public Collection<Owner> findByLastName(String lastName) {
// using 'join fetch' because a single query should load both owners and pets
// using 'left join fetch' because it might happen that an owner does not have pets yet
Query query = this.em.createQuery("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName");
query.setParameter("lastName", lastName + "%");
return query.getResultList();
}
public Owner findById(int id) {
// using 'join fetch' because a single query should load both owners and pets
// using 'left join fetch' because it might happen that an owner does not have pets yet
Query query = this.em.createQuery("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id");
query.setParameter("id", id);
return (Owner) query.getSingleResult();
}
public void save(Owner owner) { @Override
this.em.merge(owner); @SuppressWarnings("unchecked")
public Collection<Owner> findByLastName(String lastName) {
// using 'join fetch' because a single query should load both owners and pets
// using 'left join fetch' because it might happen that an owner does not have pets yet
Query query = this.em.createQuery("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName");
query.setParameter("lastName", lastName + "%");
return query.getResultList();
}
} @Override
public Owner findById(int id) {
// using 'join fetch' because a single query should load both owners and pets
// using 'left join fetch' because it might happen that an owner does not have pets yet
Query query = this.em.createQuery("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id");
query.setParameter("id", id);
return (Owner) query.getSingleResult();
}
@Override
public void save(Owner owner) {
this.em.merge(owner);
}
} }

View file

@ -15,16 +15,15 @@
*/ */
package org.springframework.samples.petclinic.repository.jpa; package org.springframework.samples.petclinic.repository.jpa;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.samples.petclinic.model.Pet; import org.springframework.samples.petclinic.model.Pet;
import org.springframework.samples.petclinic.model.PetType; import org.springframework.samples.petclinic.model.PetType;
import org.springframework.samples.petclinic.repository.PetRepository; import org.springframework.samples.petclinic.repository.PetRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;
/** /**
* JPA implementation of the {@link PetRepository} interface. * JPA implementation of the {@link PetRepository} interface.
* *
@ -37,20 +36,23 @@ import org.springframework.stereotype.Repository;
@Repository @Repository
public class JpaPetRepositoryImpl implements PetRepository { public class JpaPetRepositoryImpl implements PetRepository {
@PersistenceContext @PersistenceContext
private EntityManager em; private EntityManager em;
@SuppressWarnings("unchecked") @Override
public List<PetType> findPetTypes() { @SuppressWarnings("unchecked")
return this.em.createQuery("SELECT ptype FROM PetType ptype ORDER BY ptype.name").getResultList(); public List<PetType> findPetTypes() {
} return this.em.createQuery("SELECT ptype FROM PetType ptype ORDER BY ptype.name").getResultList();
}
public Pet findById(int id) { @Override
return this.em.find(Pet.class, id); public Pet findById(int id) {
} return this.em.find(Pet.class, id);
}
public void save(Pet pet) { @Override
this.em.merge(pet); public void save(Pet pet) {
} this.em.merge(pet);
}
} }

View file

@ -15,19 +15,18 @@
*/ */
package org.springframework.samples.petclinic.repository.jpa; package org.springframework.samples.petclinic.repository.jpa;
import java.util.Collection;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Cacheable;
import org.springframework.samples.petclinic.model.Vet; import org.springframework.samples.petclinic.model.Vet;
import org.springframework.samples.petclinic.repository.VetRepository; import org.springframework.samples.petclinic.repository.VetRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.Collection;
/** /**
* JPA implementation of the {@link VetRepository} interface. * JPA implementation of the {@link VetRepository} interface.
* *
* @author Mike Keith * @author Mike Keith
* @author Rod Johnson * @author Rod Johnson
* @author Sam Brannen * @author Sam Brannen
@ -37,14 +36,15 @@ import org.springframework.stereotype.Repository;
@Repository @Repository
public class JpaVetRepositoryImpl implements VetRepository { public class JpaVetRepositoryImpl implements VetRepository {
@PersistenceContext @PersistenceContext
private EntityManager em; private EntityManager em;
@Cacheable(value="vets") @Override
@SuppressWarnings("unchecked") @Cacheable(value = "vets")
public Collection<Vet> findAll() { @SuppressWarnings("unchecked")
return this.em.createQuery("SELECT vet FROM Vet vet join fetch vet.specialties ORDER BY vet.lastName, vet.firstName").getResultList(); public Collection<Vet> findAll() {
} return this.em.createQuery("SELECT vet FROM Vet vet join fetch vet.specialties ORDER BY vet.lastName, vet.firstName").getResultList();
}
} }

View file

@ -15,19 +15,18 @@
*/ */
package org.springframework.samples.petclinic.repository.jpa; package org.springframework.samples.petclinic.repository.jpa;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.springframework.samples.petclinic.model.Visit; import org.springframework.samples.petclinic.model.Visit;
import org.springframework.samples.petclinic.repository.VisitRepository; import org.springframework.samples.petclinic.repository.VisitRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.List;
/** /**
* JPA implementation of the ClinicService interface using EntityManager. * JPA implementation of the ClinicService interface using EntityManager.
* * <p/>
* <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.
* *
* @author Mike Keith * @author Mike Keith
@ -39,20 +38,22 @@ import org.springframework.stereotype.Repository;
@Repository @Repository
public class JpaVisitRepositoryImpl implements VisitRepository { public class JpaVisitRepositoryImpl implements VisitRepository {
@PersistenceContext @PersistenceContext
private EntityManager em; private EntityManager em;
public void save(Visit visit) { @Override
this.em.merge(visit); public void save(Visit visit) {
} this.em.merge(visit);
}
@SuppressWarnings("unchecked") @Override
public List<Visit> findByPetId(Integer petId) { @SuppressWarnings("unchecked")
Query query = this.em.createQuery("SELECT visit FROM Visit v where v.pets.id= :id"); public List<Visit> findByPetId(Integer petId) {
query.setParameter("id", petId); Query query = this.em.createQuery("SELECT visit FROM Visit v where v.pets.id= :id");
return query.getResultList(); query.setParameter("id", petId);
} return query.getResultList();
}
} }

View file

@ -15,51 +15,53 @@
*/ */
package org.springframework.samples.petclinic.repository.springdatajpa; package org.springframework.samples.petclinic.repository.springdatajpa;
import java.util.Collection;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.springframework.samples.petclinic.model.Owner; import org.springframework.samples.petclinic.model.Owner;
import org.springframework.samples.petclinic.repository.OwnerRepository; import org.springframework.samples.petclinic.repository.OwnerRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.Collection;
/** /**
* Using native JPA instead of Spring Data JPA here because of this query: * Using native JPA instead of Spring Data JPA here because of this query: "SELECT owner FROM Owner owner left join
* "SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName" * fetch owner.pets WHERE owner.lastName LIKE :lastName" See https://jira.springsource.org/browse/DATAJPA-292 for more
* See https://jira.springsource.org/browse/DATAJPA-292 for more details. * details.
* *
* @author Michael Isvy * @author Michael Isvy
*/ */
@Repository @Repository
public class JpaOwnerRepositoryImpl implements OwnerRepository { public class JpaOwnerRepositoryImpl implements OwnerRepository {
@PersistenceContext @PersistenceContext
private EntityManager em; private EntityManager em;
@SuppressWarnings("unchecked")
public Collection<Owner> findByLastName(String lastName) {
// using 'join fetch' because a single query should load both owners and pets
// using 'left join fetch' because it might happen that an owner does not have pets yet
Query query = this.em.createQuery("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName");
query.setParameter("lastName", lastName + "%");
return query.getResultList();
}
public Owner findById(int id) {
// using 'join fetch' because a single query should load both owners and pets
// using 'left join fetch' because it might happen that an owner does not have pets yet
Query query = this.em.createQuery("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id");
query.setParameter("id", id);
return (Owner) query.getSingleResult();
}
public void save(Owner owner) { @Override
this.em.merge(owner); @SuppressWarnings("unchecked")
public Collection<Owner> findByLastName(String lastName) {
// using 'join fetch' because a single query should load both owners and pets
// using 'left join fetch' because it might happen that an owner does not have pets yet
Query query = this.em.createQuery("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.lastName LIKE :lastName");
query.setParameter("lastName", lastName + "%");
return query.getResultList();
}
} @Override
public Owner findById(int id) {
// using 'join fetch' because a single query should load both owners and pets
// using 'left join fetch' because it might happen that an owner does not have pets yet
Query query = this.em.createQuery("SELECT owner FROM Owner owner left join fetch owner.pets WHERE owner.id =:id");
query.setParameter("id", id);
return (Owner) query.getSingleResult();
}
@Override
public void save(Owner owner) {
this.em.merge(owner);
}
} }

View file

@ -15,8 +15,6 @@
*/ */
package org.springframework.samples.petclinic.repository.springdatajpa; package org.springframework.samples.petclinic.repository.springdatajpa;
import java.util.List;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
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;
@ -24,6 +22,8 @@ import org.springframework.samples.petclinic.model.Pet;
import org.springframework.samples.petclinic.model.PetType; import org.springframework.samples.petclinic.model.PetType;
import org.springframework.samples.petclinic.repository.PetRepository; import org.springframework.samples.petclinic.repository.PetRepository;
import java.util.List;
/** /**
* Spring Data JPA specialization of the {@link PetRepository} interface * Spring Data JPA specialization of the {@link PetRepository} interface
* *
@ -31,7 +31,8 @@ import org.springframework.samples.petclinic.repository.PetRepository;
* @since 15.1.2013 * @since 15.1.2013
*/ */
public interface SpringDataPetRepository extends PetRepository, Repository<Pet, Integer> { public interface SpringDataPetRepository extends PetRepository, Repository<Pet, Integer> {
@Query("SELECT ptype FROM PetType ptype ORDER BY ptype.name") @Override
List<PetType> findPetTypes() throws DataAccessException; @Query("SELECT ptype FROM PetType ptype ORDER BY ptype.name")
List<PetType> findPetTypes() throws DataAccessException;
} }

View file

@ -18,7 +18,7 @@ package org.springframework.samples.petclinic.repository.springdatajpa;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
import org.springframework.samples.petclinic.model.Visit; import org.springframework.samples.petclinic.model.Visit;
import org.springframework.samples.petclinic.repository.VisitRepository; import org.springframework.samples.petclinic.repository.VisitRepository;
/** /**
* Spring Data JPA specialization of the {@link VisitRepository} interface * Spring Data JPA specialization of the {@link VisitRepository} interface
* *

View file

@ -15,14 +15,10 @@
*/ */
package org.springframework.samples.petclinic.service; package org.springframework.samples.petclinic.service;
import java.util.Collection;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.samples.petclinic.model.Owner; import org.springframework.samples.petclinic.model.*;
import org.springframework.samples.petclinic.model.Pet;
import org.springframework.samples.petclinic.model.PetType; import java.util.Collection;
import org.springframework.samples.petclinic.model.Vet;
import org.springframework.samples.petclinic.model.Visit;
/** /**
@ -31,21 +27,21 @@ import org.springframework.samples.petclinic.model.Visit;
* @author Michael Isvy * @author Michael Isvy
*/ */
public interface ClinicService { public interface ClinicService {
public Collection<PetType> findPetTypes() throws DataAccessException;
public Owner findOwnerById(int id) throws DataAccessException;
public Pet findPetById(int id) throws DataAccessException;
public void savePet(Pet pet) throws DataAccessException; public Collection<PetType> findPetTypes() throws DataAccessException;
public void saveVisit(Visit visit) throws DataAccessException; public Owner findOwnerById(int id) throws DataAccessException;
public Collection<Vet> findVets() throws DataAccessException;
public void saveOwner(Owner owner) throws DataAccessException; public Pet findPetById(int id) throws DataAccessException;
Collection<Owner> findOwnerByLastName(String lastName) throws DataAccessException; public void savePet(Pet pet) throws DataAccessException;
public void saveVisit(Visit visit) throws DataAccessException;
public Collection<Vet> findVets() throws DataAccessException;
public void saveOwner(Owner owner) throws DataAccessException;
Collection<Owner> findOwnerByLastName(String lastName) throws DataAccessException;
} }

View file

@ -15,15 +15,9 @@
*/ */
package org.springframework.samples.petclinic.service; package org.springframework.samples.petclinic.service;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.samples.petclinic.model.Owner; import org.springframework.samples.petclinic.model.*;
import org.springframework.samples.petclinic.model.Pet;
import org.springframework.samples.petclinic.model.PetType;
import org.springframework.samples.petclinic.model.Vet;
import org.springframework.samples.petclinic.model.Visit;
import org.springframework.samples.petclinic.repository.OwnerRepository; import org.springframework.samples.petclinic.repository.OwnerRepository;
import org.springframework.samples.petclinic.repository.PetRepository; import org.springframework.samples.petclinic.repository.PetRepository;
import org.springframework.samples.petclinic.repository.VetRepository; import org.springframework.samples.petclinic.repository.VetRepository;
@ -31,6 +25,8 @@ import org.springframework.samples.petclinic.repository.VisitRepository;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
/** /**
* Mostly used as a facade for all Petclinic controllers * Mostly used as a facade for all Petclinic controllers
* *
@ -38,70 +34,69 @@ import org.springframework.transaction.annotation.Transactional;
*/ */
@Service @Service
public class ClinicServiceImpl implements ClinicService { public class ClinicServiceImpl implements ClinicService {
private PetRepository petRepository;
private VetRepository vetRepository;
private OwnerRepository ownerRepository;
private VisitRepository visitRepository;
@Autowired private PetRepository petRepository;
public ClinicServiceImpl(PetRepository petRepository, VetRepository vetRepository, OwnerRepository ownerRepository, VisitRepository visitRepository) { private VetRepository vetRepository;
this.petRepository = petRepository; private OwnerRepository ownerRepository;
this.vetRepository = vetRepository; private VisitRepository visitRepository;
this.ownerRepository = ownerRepository;
this.visitRepository = visitRepository;
}
@Transactional(readOnly=true) @Autowired
public Collection<PetType> findPetTypes() throws DataAccessException { public ClinicServiceImpl(PetRepository petRepository, VetRepository vetRepository, OwnerRepository ownerRepository, VisitRepository visitRepository) {
return petRepository.findPetTypes(); this.petRepository = petRepository;
} this.vetRepository = vetRepository;
this.ownerRepository = ownerRepository;
this.visitRepository = visitRepository;
}
@Transactional(readOnly=true) @Override
public Owner findOwnerById(int id) throws DataAccessException { @Transactional(readOnly = true)
return ownerRepository.findById(id); public Collection<PetType> findPetTypes() throws DataAccessException {
} return petRepository.findPetTypes();
}
@Transactional(readOnly=true)
public Collection<Owner> findOwnerByLastName(String lastName) throws DataAccessException {
return ownerRepository.findByLastName(lastName);
}
@Transactional @Override
public void saveOwner(Owner owner) throws DataAccessException { @Transactional(readOnly = true)
ownerRepository.save(owner); public Owner findOwnerById(int id) throws DataAccessException {
} return ownerRepository.findById(id);
}
@Transactional
public void saveVisit(Visit visit) throws DataAccessException {
visitRepository.save(visit);
}
@Transactional(readOnly=true) @Override
public Pet findPetById(int id) throws DataAccessException { @Transactional(readOnly = true)
return petRepository.findById(id); public Collection<Owner> findOwnerByLastName(String lastName) throws DataAccessException {
} return ownerRepository.findByLastName(lastName);
}
@Transactional @Override
public void savePet(Pet pet) throws DataAccessException { @Transactional
petRepository.save(pet); public void saveOwner(Owner owner) throws DataAccessException {
} ownerRepository.save(owner);
}
@Override
@Transactional
public void saveVisit(Visit visit) throws DataAccessException {
visitRepository.save(visit);
}
@Override
@Transactional(readOnly = true)
public Pet findPetById(int id) throws DataAccessException {
return petRepository.findById(id);
}
@Override
@Transactional
public void savePet(Pet pet) throws DataAccessException {
petRepository.save(pet);
}
@Override
@Transactional(readOnly = true)
public Collection<Vet> findVets() throws DataAccessException {
return vetRepository.findAll();
}
@Transactional(readOnly=true)
public Collection<Vet> findVets() throws DataAccessException {
return vetRepository.findAll();
}
} }

View file

@ -24,8 +24,8 @@ import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.util.StopWatch; import org.springframework.util.StopWatch;
/** /**
* Simple aspect that monitors call count and call invocation time. * Simple aspect that monitors call count and call invocation time. It uses JMX annotations and therefore can be
* It uses JMX annotations and therefore can be monitored using any JMX console such as the jConsole * monitored using any JMX console such as the jConsole
* *
* @author Rob Harrop * @author Rob Harrop
* @author Juergen Hoeller * @author Juergen Hoeller
@ -36,61 +36,58 @@ import org.springframework.util.StopWatch;
@Aspect @Aspect
public class CallMonitoringAspect { public class CallMonitoringAspect {
private boolean isEnabled = true; private boolean isEnabled = true;
private int callCount = 0; private int callCount = 0;
private long accumulatedCallTime = 0; private long accumulatedCallTime = 0;
@ManagedAttribute @ManagedAttribute
public void setEnabled(boolean enabled) { public void setEnabled(boolean enabled) {
isEnabled = enabled; isEnabled = enabled;
} }
@ManagedAttribute @ManagedAttribute
public boolean isEnabled() { public boolean isEnabled() {
return isEnabled; return isEnabled;
} }
@ManagedOperation @ManagedOperation
public void reset() { public void reset() {
this.callCount = 0; this.callCount = 0;
this.accumulatedCallTime = 0; this.accumulatedCallTime = 0;
} }
@ManagedAttribute @ManagedAttribute
public int getCallCount() { public int getCallCount() {
return callCount; return callCount;
} }
@ManagedAttribute @ManagedAttribute
public long getCallTime() { public long getCallTime() {
return (this.callCount > 0 ? this.accumulatedCallTime / this.callCount : 0); return (this.callCount > 0 ? this.accumulatedCallTime / this.callCount : 0);
} }
@Around("within(@org.springframework.stereotype.Repository *)") @Around("within(@org.springframework.stereotype.Repository *)")
public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable { public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable {
if (this.isEnabled) { if (this.isEnabled) {
StopWatch sw = new StopWatch(joinPoint.toShortString()); StopWatch sw = new StopWatch(joinPoint.toShortString());
sw.start("invoke"); sw.start("invoke");
try { try {
return joinPoint.proceed(); return joinPoint.proceed();
} } finally {
finally { sw.stop();
sw.stop(); synchronized (this) {
synchronized (this) { this.callCount++;
this.callCount++; this.accumulatedCallTime += sw.getTotalTimeMillis();
this.accumulatedCallTime += sw.getTotalTimeMillis(); }
} }
} } else {
} return joinPoint.proceed();
}
else { }
return joinPoint.proceed();
}
}
} }

View file

@ -16,41 +16,40 @@
package org.springframework.samples.petclinic.util; package org.springframework.samples.petclinic.util;
import java.util.Collection;
import org.springframework.orm.ObjectRetrievalFailureException; import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.samples.petclinic.model.BaseEntity; import org.springframework.samples.petclinic.model.BaseEntity;
import java.util.Collection;
/** /**
* Utility methods for handling entities. Separate from the BaseEntity class * Utility methods for handling entities. Separate from the BaseEntity class mainly because of dependency on the
* mainly because of dependency on the ORM-associated * ORM-associated ObjectRetrievalFailureException.
* ObjectRetrievalFailureException.
* *
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sam Brannen * @author Sam Brannen
* @since 29.10.2003
* @see org.springframework.samples.petclinic.model.BaseEntity * @see org.springframework.samples.petclinic.model.BaseEntity
* @since 29.10.2003
*/ */
public abstract class EntityUtils { public abstract class EntityUtils {
/** /**
* Look up the entity of the given class with the given id in the given * Look up the entity of the given class with the given id in the given collection.
* collection. *
* * @param entities the collection to search
* @param entities the collection to search * @param entityClass the entity class to look up
* @param entityClass the entity class to look up * @param entityId the entity id to look up
* @param entityId the entity id to look up * @return the found entity
* @return the found entity * @throws ObjectRetrievalFailureException
* @throws ObjectRetrievalFailureException if the entity was not found * if the entity was not found
*/ */
public static <T extends BaseEntity> T getById(Collection<T> entities, Class<T> entityClass, int entityId) public static <T extends BaseEntity> T getById(Collection<T> entities, Class<T> entityClass, int entityId)
throws ObjectRetrievalFailureException { throws ObjectRetrievalFailureException {
for (T entity : entities) { for (T entity : entities) {
if (entity.getId().intValue() == entityId && entityClass.isInstance(entity)) { if (entity.getId().intValue() == entityId && entityClass.isInstance(entity)) {
return entity; return entity;
} }
} }
throw new ObjectRetrievalFailureException(entityClass, new Integer(entityId)); throw new ObjectRetrievalFailureException(entityClass, new Integer(entityId));
} }
} }

View file

@ -21,20 +21,20 @@ import org.springframework.web.bind.annotation.RequestMethod;
/** /**
* Controller used to showcase what happens when an exception is thrown * Controller used to showcase what happens when an exception is thrown
* *
* @author Michael Isvy * @author Michael Isvy
* * <p/>
* Also see how the bean of type 'SimpleMappingExceptionResolver' has been declared inside /WEB-INF/mvc-core-config.xml * Also see how the bean of type 'SimpleMappingExceptionResolver' has been declared inside
* /WEB-INF/mvc-core-config.xml
*/ */
@Controller @Controller
public class CrashController { public class CrashController {
@RequestMapping(value="/oups", method = RequestMethod.GET) @RequestMapping(value = "/oups", method = RequestMethod.GET)
public String triggerException() { public String triggerException() {
throw new RuntimeException("Expected: controller used to showcase what " + throw new RuntimeException("Expected: controller used to showcase what " +
"happens when an exception is thrown"); "happens when an exception is thrown");
} }
} }

View file

@ -15,10 +15,6 @@
*/ */
package org.springframework.samples.petclinic.web; package org.springframework.samples.petclinic.web;
import java.util.Collection;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.model.Owner; import org.springframework.samples.petclinic.model.Owner;
import org.springframework.samples.petclinic.service.ClinicService; import org.springframework.samples.petclinic.service.ClinicService;
@ -26,16 +22,14 @@ 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;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.*;
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.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus; import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
import javax.validation.Valid;
import java.util.Collection;
/** /**
*
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Ken Krebs * @author Ken Krebs
* @author Arjen Poutsma * @author Arjen Poutsma
@ -45,101 +39,98 @@ import org.springframework.web.servlet.ModelAndView;
@SessionAttributes(types = Owner.class) @SessionAttributes(types = Owner.class)
public class OwnerController { public class OwnerController {
private final ClinicService clinicService; private final ClinicService clinicService;
@Autowired @Autowired
public OwnerController(ClinicService clinicService) { public OwnerController(ClinicService clinicService) {
this.clinicService = clinicService; this.clinicService = clinicService;
} }
@InitBinder @InitBinder
public void setAllowedFields(WebDataBinder dataBinder) { public void setAllowedFields(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id"); dataBinder.setDisallowedFields("id");
} }
@RequestMapping(value="/owners/new", method = RequestMethod.GET) @RequestMapping(value = "/owners/new", method = RequestMethod.GET)
public String initCreationForm(Model model) { public String initCreationForm(Model model) {
Owner owner = new Owner(); Owner owner = new Owner();
model.addAttribute(owner); model.addAttribute(owner);
return "owners/createOrUpdateOwnerForm"; return "owners/createOrUpdateOwnerForm";
} }
@RequestMapping(value="/owners/new", method = RequestMethod.POST) @RequestMapping(value = "/owners/new", method = RequestMethod.POST)
public String processCreationForm(@Valid Owner owner, BindingResult result, SessionStatus status) { public String processCreationForm(@Valid Owner owner, BindingResult result, SessionStatus status) {
if (result.hasErrors()) { if (result.hasErrors()) {
return "owners/createOrUpdateOwnerForm"; return "owners/createOrUpdateOwnerForm";
} } else {
else { this.clinicService.saveOwner(owner);
this.clinicService.saveOwner(owner); status.setComplete();
status.setComplete(); return "redirect:/owners/" + owner.getId();
return "redirect:/owners/" + owner.getId(); }
} }
}
@RequestMapping(value = "/owners/find", method = RequestMethod.GET) @RequestMapping(value = "/owners/find", method = RequestMethod.GET)
public String initFindForm(Model model) { public String initFindForm(Model model) {
model.addAttribute("owner", new Owner()); model.addAttribute("owner", new Owner());
return "owners/findOwners"; return "owners/findOwners";
} }
@RequestMapping(value = "/owners", method = RequestMethod.GET) @RequestMapping(value = "/owners", method = RequestMethod.GET)
public String processFindForm(Owner owner, BindingResult result, Model model) { public String processFindForm(Owner owner, BindingResult result, Model model) {
// allow parameterless GET request for /owners to return all records // allow parameterless GET request for /owners to return all records
if (owner.getLastName() == null) { if (owner.getLastName() == null) {
owner.setLastName(""); // empty string signifies broadest possible search owner.setLastName(""); // empty string signifies broadest possible search
} }
// find owners by last name // find owners by last name
Collection<Owner> results = this.clinicService.findOwnerByLastName(owner.getLastName()); Collection<Owner> results = this.clinicService.findOwnerByLastName(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");
return "owners/findOwners"; return "owners/findOwners";
} }
if (results.size() > 1) { if (results.size() > 1) {
// multiple owners found // multiple owners found
model.addAttribute("selections", results); model.addAttribute("selections", results);
return "owners/ownersList"; return "owners/ownersList";
} } else {
else { // 1 owner found
// 1 owner found owner = results.iterator().next();
owner = results.iterator().next(); return "redirect:/owners/" + owner.getId();
return "redirect:/owners/" + owner.getId(); }
} }
}
@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.clinicService.findOwnerById(ownerId); Owner owner = this.clinicService.findOwnerById(ownerId);
model.addAttribute(owner); model.addAttribute(owner);
return "owners/createOrUpdateOwnerForm"; return "owners/createOrUpdateOwnerForm";
} }
@RequestMapping(value="/owners/{ownerId}/edit", method = RequestMethod.PUT) @RequestMapping(value = "/owners/{ownerId}/edit", method = RequestMethod.PUT)
public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result, SessionStatus status) { public String processUpdateOwnerForm(@Valid Owner owner, BindingResult result, SessionStatus status) {
if (result.hasErrors()) { if (result.hasErrors()) {
return "owners/createOrUpdateOwnerForm"; return "owners/createOrUpdateOwnerForm";
} } else {
else { this.clinicService.saveOwner(owner);
this.clinicService.saveOwner(owner); status.setComplete();
status.setComplete(); return "redirect:/owners/{ownerId}";
return "redirect:/owners/{ownerId}"; }
} }
}
/** /**
* Custom handler for displaying an owner. * Custom handler for displaying an owner.
* *
* @param ownerId the ID of the owner to display * @param ownerId the ID of the owner to display
* @return a ModelMap with the model attributes for the view * @return a ModelMap with the model attributes for the view
*/ */
@RequestMapping("/owners/{ownerId}") @RequestMapping("/owners/{ownerId}")
public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) { public ModelAndView showOwner(@PathVariable("ownerId") int ownerId) {
ModelAndView mav = new ModelAndView("owners/ownerDetails"); ModelAndView mav = new ModelAndView("owners/ownerDetails");
mav.addObject(this.clinicService.findOwnerById(ownerId)); mav.addObject(this.clinicService.findOwnerById(ownerId));
return mav; return mav;
} }
} }

View file

@ -15,8 +15,6 @@
*/ */
package org.springframework.samples.petclinic.web; package org.springframework.samples.petclinic.web;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.model.Owner; import org.springframework.samples.petclinic.model.Owner;
import org.springframework.samples.petclinic.model.Pet; import org.springframework.samples.petclinic.model.Pet;
@ -26,16 +24,12 @@ 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;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.ModelAttribute;
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.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus; import org.springframework.web.bind.support.SessionStatus;
import java.util.Collection;
/** /**
*
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Ken Krebs * @author Ken Krebs
* @author Arjen Poutsma * @author Arjen Poutsma
@ -44,65 +38,63 @@ import org.springframework.web.bind.support.SessionStatus;
@SessionAttributes("pet") @SessionAttributes("pet")
public class PetController { public class PetController {
private final ClinicService clinicService; private final ClinicService clinicService;
@Autowired @Autowired
public PetController(ClinicService clinicService) { public PetController(ClinicService clinicService) {
this.clinicService = clinicService; this.clinicService = clinicService;
} }
@ModelAttribute("types") @ModelAttribute("types")
public Collection<PetType> populatePetTypes() { public Collection<PetType> populatePetTypes() {
return this.clinicService.findPetTypes(); return this.clinicService.findPetTypes();
} }
@InitBinder @InitBinder
public void setAllowedFields(WebDataBinder dataBinder) { public void setAllowedFields(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id"); dataBinder.setDisallowedFields("id");
} }
@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.clinicService.findOwnerById(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);
return "pets/createOrUpdatePetForm"; return "pets/createOrUpdatePetForm";
} }
@RequestMapping(value="/owners/{ownerId}/pets/new", method = RequestMethod.POST) @RequestMapping(value = "/owners/{ownerId}/pets/new", method = RequestMethod.POST)
public String processCreationForm(@ModelAttribute("pet") Pet pet, BindingResult result, SessionStatus status) { public String processCreationForm(@ModelAttribute("pet") Pet pet, BindingResult result, SessionStatus status) {
new PetValidator().validate(pet, result); new PetValidator().validate(pet, result);
if (result.hasErrors()) { if (result.hasErrors()) {
return "pets/createOrUpdatePetForm"; return "pets/createOrUpdatePetForm";
} } else {
else { this.clinicService.savePet(pet);
this.clinicService.savePet(pet); status.setComplete();
status.setComplete(); return "redirect:/owners/{ownerId}";
return "redirect:/owners/{ownerId}"; }
} }
}
@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.clinicService.findPetById(petId); Pet pet = this.clinicService.findPetById(petId);
model.addAttribute("pet", pet); model.addAttribute("pet", pet);
return "pets/createOrUpdatePetForm"; return "pets/createOrUpdatePetForm";
} }
@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = { RequestMethod.PUT, RequestMethod.POST }) @RequestMapping(value = "/owners/{ownerId}/pets/{petId}/edit", method = {RequestMethod.PUT, RequestMethod.POST})
public String processUpdateForm(@ModelAttribute("pet") Pet pet, BindingResult result, SessionStatus status) { public String processUpdateForm(@ModelAttribute("pet") Pet pet, BindingResult result, SessionStatus status) {
// we're not using @Valid annotation here because it is easier to define such validation rule in Java // we're not using @Valid annotation here because it is easier to define such validation rule in Java
new PetValidator().validate(pet, result); new PetValidator().validate(pet, result);
if (result.hasErrors()) { if (result.hasErrors()) {
return "pets/createOrUpdatePetForm"; return "pets/createOrUpdatePetForm";
} } else {
else { this.clinicService.savePet(pet);
this.clinicService.savePet(pet); status.setComplete();
status.setComplete(); return "redirect:/owners/{ownerId}";
return "redirect:/owners/{ownerId}"; }
} }
}
} }

View file

@ -16,52 +16,51 @@
package org.springframework.samples.petclinic.web; package org.springframework.samples.petclinic.web;
import java.text.ParseException;
import java.util.Collection;
import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.Formatter; import org.springframework.format.Formatter;
import org.springframework.samples.petclinic.model.PetType; import org.springframework.samples.petclinic.model.PetType;
import org.springframework.samples.petclinic.service.ClinicService; import org.springframework.samples.petclinic.service.ClinicService;
import java.text.ParseException;
import java.util.Collection;
import java.util.Locale;
/** /**
* Instructs Spring MVC on how to parse and print elements of type 'PetType'. * Instructs Spring MVC on how to parse and print elements of type 'PetType'. Starting from Spring 3.0, Formatters have
* Starting from Spring 3.0, Formatters have come as an improvement in comparison to legacy PropertyEditors. * come as an improvement in comparison to legacy PropertyEditors. See the following links for more details: - The
* See the following links for more details: * Spring ref doc: http://static.springsource.org/spring/docs/current/spring-framework-reference/html/validation.html#format-Formatter-SPI
* - The Spring ref doc: http://static.springsource.org/spring/docs/current/spring-framework-reference/html/validation.html#format-Formatter-SPI
* - A nice blog entry from Gordon Dickens: http://gordondickens.com/wordpress/2010/09/30/using-spring-3-0-custom-type-converter/ * - A nice blog entry from Gordon Dickens: http://gordondickens.com/wordpress/2010/09/30/using-spring-3-0-custom-type-converter/
* * <p/>
* Also see how the bean 'conversionService' has been declared inside /WEB-INF/mvc-core-config.xml * Also see how the bean 'conversionService' has been declared inside /WEB-INF/mvc-core-config.xml
* *
* @author Mark Fisher * @author Mark Fisher
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Michael Isvy * @author Michael Isvy
*/ */
public class PetTypeFormatter implements Formatter<PetType> { public class PetTypeFormatter implements Formatter<PetType> {
private final ClinicService clinicService; private final ClinicService clinicService;
@Autowired @Autowired
public PetTypeFormatter(ClinicService clinicService) { public PetTypeFormatter(ClinicService clinicService) {
this.clinicService = clinicService; this.clinicService = clinicService;
} }
@Override @Override
public String print(PetType petType, Locale locale) { public String print(PetType petType, Locale locale) {
return petType.getName(); return petType.getName();
} }
@Override @Override
public PetType parse(String text, Locale locale) throws ParseException { public PetType parse(String text, Locale locale) throws ParseException {
Collection<PetType> findPetTypes = this.clinicService.findPetTypes(); Collection<PetType> findPetTypes = this.clinicService.findPetTypes();
for (PetType type : findPetTypes) { for (PetType type : findPetTypes) {
if (type.getName().equals(text)) { if (type.getName().equals(text)) {
return type; return type;
} }
} }
throw new ParseException("type not found: "+text, 0); throw new ParseException("type not found: " + text, 0);
} }
} }

View file

@ -27,14 +27,13 @@ import org.springframework.validation.Errors;
*/ */
public class PetValidator { public class PetValidator {
public void validate(Pet pet, Errors errors) { public void validate(Pet pet, Errors errors) {
String name = pet.getName(); String name = pet.getName();
if (!StringUtils.hasLength(name)) { if (!StringUtils.hasLength(name)) {
errors.rejectValue("name", "required", "required"); errors.rejectValue("name", "required", "required");
} } else if (pet.isNew() && pet.getOwner().getPet(name, true) != null) {
else if (pet.isNew() && pet.getOwner().getPet(name, true) != null) { errors.rejectValue("name", "duplicate", "already exists");
errors.rejectValue("name", "duplicate", "already exists"); }
} }
}
} }

View file

@ -23,7 +23,6 @@ import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
/** /**
*
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Mark Fisher * @author Mark Fisher
* @author Ken Krebs * @author Ken Krebs
@ -32,26 +31,23 @@ import org.springframework.web.bind.annotation.RequestMapping;
@Controller @Controller
public class VetController { public class VetController {
private final ClinicService clinicService; private final ClinicService clinicService;
@Autowired
public VetController(ClinicService clinicService) {
this.clinicService = clinicService;
}
@RequestMapping("/vets")
public String showVetList(Model model) {
// Here we are returning an object of type 'Vets' rather than a collection of Vet objects
// so it is simpler for Object-Xml mapping
Vets vets = new Vets();
vets.getVetList().addAll(this.clinicService.findVets());
model.addAttribute("vets", vets);
return "vets/vetList";
}
@Autowired
public VetController(ClinicService clinicService) {
this.clinicService = clinicService;
}
@RequestMapping("/vets")
public String showVetList(Model model) {
// Here we are returning an object of type 'Vets' rather than a collection of Vet objects
// so it is simpler for Object-Xml mapping
Vets vets = new Vets();
vets.getVetList().addAll(this.clinicService.findVets());
model.addAttribute("vets", vets);
return "vets/vetList";
}
} }

View file

@ -15,60 +15,58 @@
*/ */
package org.springframework.samples.petclinic.web; package org.springframework.samples.petclinic.web;
import java.util.ArrayList; import com.sun.syndication.feed.atom.Content;
import java.util.List; import com.sun.syndication.feed.atom.Entry;
import java.util.Map; import com.sun.syndication.feed.atom.Feed;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.samples.petclinic.model.Vet; import org.springframework.samples.petclinic.model.Vet;
import org.springframework.samples.petclinic.model.Vets; import org.springframework.samples.petclinic.model.Vets;
import org.springframework.web.servlet.view.feed.AbstractAtomFeedView; import org.springframework.web.servlet.view.feed.AbstractAtomFeedView;
import com.sun.syndication.feed.atom.Content; import javax.servlet.http.HttpServletRequest;
import com.sun.syndication.feed.atom.Entry; import javax.servlet.http.HttpServletResponse;
import com.sun.syndication.feed.atom.Feed; import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/** /**
* A view creating a Atom representation from a list of Visit objects. * A view creating a Atom representation from a list of Visit objects.
* *
* @author Alef Arendsen * @author Alef Arendsen
* @author Arjen Poutsma * @author Arjen Poutsma
*/ */
public class VetsAtomView extends AbstractAtomFeedView { public class VetsAtomView 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.org"); feed.setId("tag:springsource.org");
feed.setTitle("Veterinarians"); feed.setTitle("Veterinarians");
//feed.setUpdated(date); //feed.setUpdated(date);
} }
@Override @Override
protected List<Entry> buildFeedEntries(Map<String, Object> model, protected List<Entry> buildFeedEntries(Map<String, Object> model,
HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest request, HttpServletResponse response) throws Exception {
Vets vets = (Vets) model.get("vets"); Vets vets = (Vets) model.get("vets");
List<Vet> vetList = vets.getVetList(); List<Vet> vetList = vets.getVetList();
List<Entry> entries = new ArrayList<Entry>(vetList.size()); List<Entry> entries = new ArrayList<Entry>(vetList.size());
for (Vet vet : vetList) { for (Vet vet : vetList) {
Entry entry = new Entry(); Entry entry = new Entry();
// see http://diveintomark.org/archives/2004/05/28/howto-atom-id#other // see http://diveintomark.org/archives/2004/05/28/howto-atom-id#other
entry.setId(String.format("tag:springsource.org,%s", vet.getId())); entry.setId(String.format("tag:springsource.org,%s", vet.getId()));
entry.setTitle(String.format("Vet: %s %s", vet.getFirstName(), vet.getLastName())); entry.setTitle(String.format("Vet: %s %s", vet.getFirstName(), vet.getLastName()));
//entry.setUpdated(visit.getDate().toDate()); //entry.setUpdated(visit.getDate().toDate());
Content summary = new Content(); Content summary = new Content();
summary.setValue(vet.getSpecialties().toString()); summary.setValue(vet.getSpecialties().toString());
entry.setSummary(summary); entry.setSummary(summary);
entries.add(entry); entries.add(entry);
} }
response.setContentType("blabla"); response.setContentType("blabla");
return entries; return entries;
}
}
} }

View file

@ -15,8 +15,6 @@
*/ */
package org.springframework.samples.petclinic.web; package org.springframework.samples.petclinic.web;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.samples.petclinic.model.Pet; import org.springframework.samples.petclinic.model.Pet;
import org.springframework.samples.petclinic.model.Visit; import org.springframework.samples.petclinic.model.Visit;
@ -25,16 +23,13 @@ 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;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.*;
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.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus; import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
import javax.validation.Valid;
/** /**
*
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Ken Krebs * @author Ken Krebs
* @author Arjen Poutsma * @author Arjen Poutsma
@ -44,45 +39,44 @@ import org.springframework.web.servlet.ModelAndView;
@SessionAttributes("visit") @SessionAttributes("visit")
public class VisitController { public class VisitController {
private final ClinicService clinicService; private final ClinicService clinicService;
@Autowired @Autowired
public VisitController(ClinicService clinicService) { public VisitController(ClinicService clinicService) {
this.clinicService = clinicService; this.clinicService = clinicService;
} }
@InitBinder @InitBinder
public void setAllowedFields(WebDataBinder dataBinder) { public void setAllowedFields(WebDataBinder dataBinder) {
dataBinder.setDisallowedFields("id"); dataBinder.setDisallowedFields("id");
} }
@RequestMapping(value="/owners/*/pets/{petId}/visits/new", method = RequestMethod.GET) @RequestMapping(value = "/owners/*/pets/{petId}/visits/new", method = RequestMethod.GET)
public String initNewVisitForm(@PathVariable("petId") int petId, Model model) { public String initNewVisitForm(@PathVariable("petId") int petId, Model model) {
Pet pet = this.clinicService.findPetById(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);
return "pets/createOrUpdateVisitForm"; return "pets/createOrUpdateVisitForm";
} }
@RequestMapping(value="/owners/{ownerId}/pets/{petId}/visits/new", method = RequestMethod.POST) @RequestMapping(value = "/owners/{ownerId}/pets/{petId}/visits/new", method = RequestMethod.POST)
public String processNewVisitForm(@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.clinicService.saveVisit(visit);
this.clinicService.saveVisit(visit); status.setComplete();
status.setComplete(); return "redirect:/owners/{ownerId}";
return "redirect:/owners/{ownerId}"; }
} }
}
@RequestMapping(value="/owners/*/pets/{petId}/visits", method=RequestMethod.GET) @RequestMapping(value = "/owners/*/pets/{petId}/visits", method = RequestMethod.GET)
public ModelAndView showVisits(@PathVariable int petId) { public ModelAndView showVisits(@PathVariable int petId) {
ModelAndView mav = new ModelAndView("visitList"); ModelAndView mav = new ModelAndView("visitList");
mav.addObject("visits", this.clinicService.findPetById(petId).getVisits()); mav.addObject("visits", this.clinicService.findPetById(petId).getVisits());
return mav; return mav;
} }
} }

View file

@ -1,7 +1,7 @@
<html> <html>
<body> <body>
<p> <p>
The Spring Data Binding framework, an internal library used by Spring Web Flow. The Spring Data Binding framework, an internal library used by Spring Web Flow.
</p> </p>
</body> </body>
</html> </html>

View file

@ -1,64 +1,64 @@
drop table vet_specialties if exists; DROP TABLE vet_specialties IF EXISTS;
drop table vets if exists; DROP TABLE vets IF EXISTS;
drop table specialties if exists; DROP TABLE specialties IF EXISTS;
drop table visits if exists; DROP TABLE visits IF EXISTS;
drop table pets if exists; DROP TABLE pets IF EXISTS;
drop table types if exists; DROP TABLE types IF EXISTS;
drop table owners if exists; DROP TABLE owners IF EXISTS;
CREATE TABLE vets ( CREATE TABLE vets (
id INTEGER IDENTITY PRIMARY KEY, id INTEGER IDENTITY PRIMARY KEY,
first_name VARCHAR(30), first_name VARCHAR(30),
last_name VARCHAR(30) last_name VARCHAR(30)
); );
CREATE INDEX vets_last_name ON vets(last_name); CREATE INDEX vets_last_name ON vets (last_name);
CREATE TABLE specialties ( CREATE TABLE specialties (
id INTEGER IDENTITY PRIMARY KEY, id INTEGER IDENTITY PRIMARY KEY,
name VARCHAR(80) name VARCHAR(80)
); );
CREATE INDEX specialties_name ON specialties(name); CREATE INDEX specialties_name ON specialties (name);
CREATE TABLE vet_specialties ( CREATE TABLE vet_specialties (
vet_id INTEGER NOT NULL, vet_id INTEGER NOT NULL,
specialty_id INTEGER NOT NULL specialty_id INTEGER NOT NULL
); );
alter table vet_specialties add constraint fk_vet_specialties_vets foreign key (vet_id) references vets(id); ALTER TABLE vet_specialties ADD CONSTRAINT fk_vet_specialties_vets FOREIGN KEY (vet_id) REFERENCES vets (id);
alter table vet_specialties add constraint fk_vet_specialties_specialties foreign key (specialty_id) references specialties(id); ALTER TABLE vet_specialties ADD CONSTRAINT fk_vet_specialties_specialties FOREIGN KEY (specialty_id) REFERENCES specialties (id);
CREATE TABLE types ( CREATE TABLE types (
id INTEGER IDENTITY PRIMARY KEY, id INTEGER IDENTITY PRIMARY KEY,
name VARCHAR(80) name VARCHAR(80)
); );
CREATE INDEX types_name ON types(name); CREATE INDEX types_name ON types (name);
CREATE TABLE owners ( CREATE TABLE owners (
id INTEGER IDENTITY PRIMARY KEY, id INTEGER IDENTITY PRIMARY KEY,
first_name VARCHAR(30), first_name VARCHAR(30),
last_name VARCHAR(30), last_name VARCHAR(30),
address VARCHAR(255), address VARCHAR(255),
city VARCHAR(80), city VARCHAR(80),
telephone VARCHAR(20) telephone VARCHAR(20)
); );
CREATE INDEX owners_last_name ON owners(last_name); CREATE INDEX owners_last_name ON owners (last_name);
CREATE TABLE pets ( CREATE TABLE pets (
id INTEGER IDENTITY PRIMARY KEY, id INTEGER IDENTITY PRIMARY KEY,
name VARCHAR(30), name VARCHAR(30),
birth_date DATE, birth_date DATE,
type_id INTEGER NOT NULL, type_id INTEGER NOT NULL,
owner_id INTEGER NOT NULL owner_id INTEGER NOT NULL
); );
alter table pets add constraint fk_pets_owners foreign key (owner_id) references owners(id); ALTER TABLE pets ADD CONSTRAINT fk_pets_owners FOREIGN KEY (owner_id) REFERENCES owners (id);
alter table pets add constraint fk_pets_types foreign key (type_id) references types(id); ALTER TABLE pets ADD CONSTRAINT fk_pets_types FOREIGN KEY (type_id) REFERENCES types (id);
CREATE INDEX pets_name ON pets(name); CREATE INDEX pets_name ON pets (name);
CREATE TABLE visits ( CREATE TABLE visits (
id INTEGER IDENTITY PRIMARY KEY, id INTEGER IDENTITY PRIMARY KEY,
pet_id INTEGER NOT NULL, pet_id INTEGER NOT NULL,
visit_date DATE, visit_date DATE,
description VARCHAR(255) description VARCHAR(255)
); );
alter table visits add constraint fk_visits_pets foreign key (pet_id) references pets(id); ALTER TABLE visits ADD CONSTRAINT fk_visits_pets FOREIGN KEY (pet_id) REFERENCES pets (id);
CREATE INDEX visits_pet_id ON visits(pet_id); CREATE INDEX visits_pet_id ON visits (pet_id);

View file

@ -1,17 +1,17 @@
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd" xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="false"> updateCheck="false">
<diskStore path="java.io.tmpdir"/> <diskStore path="java.io.tmpdir"/>
<!-- objects are evicted from the cache every 60 seconds --> <!-- objects are evicted from the cache every 60 seconds -->
<cache name="vets" <cache name="vets"
timeToLiveSeconds="60" timeToLiveSeconds="60"
maxElementsInMemory="100" maxElementsInMemory="100"
eternal="false" eternal="false"
overflowToDisk="false" overflowToDisk="false"
maxElementsOnDisk="10000000" maxElementsOnDisk="10000000"
diskPersistent="false" diskPersistent="false"
diskExpiryThreadIntervalSeconds="1" diskExpiryThreadIntervalSeconds="1"
memoryStoreEvictionPolicy="LRU" /> memoryStoreEvictionPolicy="LRU"/>
</ehcache> </ehcache>

View file

@ -227,13 +227,13 @@
</xs:element> </xs:element>
<xs:element name="searchable"> <xs:element name="searchable">
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="searchAttribute"/> <xs:element minOccurs="0" maxOccurs="unbounded" ref="searchAttribute"/>
</xs:sequence> </xs:sequence>
<xs:attribute name="keys" use="optional" type="xs:boolean" default="true"/> <xs:attribute name="keys" use="optional" type="xs:boolean" default="true"/>
<xs:attribute name="values" use="optional" type="xs:boolean" default="true"/> <xs:attribute name="values" use="optional" type="xs:boolean" default="true"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:element name="pinning"> <xs:element name="pinning">
@ -371,26 +371,27 @@
<xs:element name="sizeOfPolicy"> <xs:element name="sizeOfPolicy">
<xs:complexType> <xs:complexType>
<xs:attribute name="maxDepth" use="required" type="xs:integer"/> <xs:attribute name="maxDepth" use="required" type="xs:integer"/>
<xs:attribute name="maxDepthExceededBehavior" use="optional" default="continue" type="maxDepthExceededBehavior"/> <xs:attribute name="maxDepthExceededBehavior" use="optional" default="continue"
type="maxDepthExceededBehavior"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:element name="persistence"> <xs:element name="persistence">
<xs:complexType> <xs:complexType>
<xs:attribute name="strategy" use="required" type="persistenceStrategy"/> <xs:attribute name="strategy" use="required" type="persistenceStrategy"/>
<xs:attribute name="synchronousWrites" use="optional" default="false" type="xs:boolean"/> <xs:attribute name="synchronousWrites" use="optional" default="false" type="xs:boolean"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:simpleType name="persistenceStrategy"> <xs:simpleType name="persistenceStrategy">
<xs:restriction base="xs:string"> <xs:restriction base="xs:string">
<xs:enumeration value="localTempSwap"/> <xs:enumeration value="localTempSwap"/>
<xs:enumeration value="localRestartable"/> <xs:enumeration value="localRestartable"/>
<xs:enumeration value="none"/> <xs:enumeration value="none"/>
<xs:enumeration value="distributed"/> <xs:enumeration value="distributed"/>
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>
<xs:simpleType name="maxDepthExceededBehavior"> <xs:simpleType name="maxDepthExceededBehavior">
<xs:restriction base="xs:string"> <xs:restriction base="xs:string">
<xs:enumeration value="continue"/> <xs:enumeration value="continue"/>

View file

@ -1,166 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!-- Authors: Chris Taylor, Ceki Gulcu. -->
<!-- Version: 1.2 -->
<!-- A configuration element consists of optional renderer
elements,appender elements, categories and an optional root
element. -->
<!ELEMENT log4j:configuration (renderer*, appender*,(category|logger)*,root?,
categoryFactory?)>
<!-- The "threshold" attribute takes a level value such that all -->
<!-- logging statements with a level equal or below this value are -->
<!-- disabled. -->
<!-- Setting the "debug" enable the printing of internal log4j logging -->
<!-- statements. -->
<!-- By default, debug attribute is "null", meaning that we not do touch -->
<!-- internal log4j logging settings. The "null" value for the threshold -->
<!-- attribute can be misleading. The threshold field of a repository -->
<!-- cannot be set to null. The "null" value for the threshold attribute -->
<!-- simply means don't touch the threshold field, the threshold field -->
<!-- keeps its old value. -->
<!ATTLIST log4j:configuration
xmlns:log4j CDATA #FIXED "http://jakarta.apache.org/log4j/"
threshold (all|debug|info|warn|error|fatal|off|null) "null"
debug (true|false|null) "null"
>
<!-- renderer elements allow the user to customize the conversion of -->
<!-- message objects to String. -->
<!ELEMENT renderer EMPTY>
<!ATTLIST renderer
renderedClass CDATA #REQUIRED
renderingClass CDATA #REQUIRED
>
<!-- Appenders must have a name and a class. -->
<!-- Appenders may contain an error handler, a layout, optional parameters -->
<!-- and filters. They may also reference (or include) other appenders. -->
<!ELEMENT appender (errorHandler?, param*, layout?, filter*, appender-ref*)>
<!ATTLIST appender
name ID #REQUIRED
class CDATA #REQUIRED
>
<!ELEMENT layout (param*)>
<!ATTLIST layout
class CDATA #REQUIRED
>
<!ELEMENT filter (param*)>
<!ATTLIST filter
class CDATA #REQUIRED
>
<!-- ErrorHandlers can be of any class. They can admit any number of -->
<!-- parameters. -->
<!ELEMENT errorHandler (param*, root-ref?, logger-ref*, appender-ref?)>
<!ATTLIST errorHandler
class CDATA #REQUIRED
>
<!ELEMENT root-ref EMPTY>
<!ELEMENT logger-ref EMPTY>
<!ATTLIST logger-ref
ref IDREF #REQUIRED
>
<!ELEMENT param EMPTY>
<!ATTLIST param
name CDATA #REQUIRED
value CDATA #REQUIRED
>
<!-- The priority class is org.apache.log4j.Level by default -->
<!ELEMENT priority (param*)>
<!ATTLIST priority
class CDATA #IMPLIED
value CDATA #REQUIRED
>
<!-- The level class is org.apache.log4j.Level by default -->
<!ELEMENT level (param*)>
<!ATTLIST level
class CDATA #IMPLIED
value CDATA #REQUIRED
>
<!-- If no level element is specified, then the configurator MUST not -->
<!-- touch the level of the named category. -->
<!ELEMENT category (param*,(priority|level)?,appender-ref*)>
<!ATTLIST category
class CDATA #IMPLIED
name CDATA #REQUIRED
additivity (true|false) "true"
>
<!-- If no level element is specified, then the configurator MUST not -->
<!-- touch the level of the named logger. -->
<!ELEMENT logger (level?,appender-ref*)>
<!ATTLIST logger
name ID #REQUIRED
additivity (true|false) "true"
>
<!ELEMENT categoryFactory (param*)>
<!ATTLIST categoryFactory
class CDATA #REQUIRED>
<!ELEMENT appender-ref EMPTY>
<!ATTLIST appender-ref
ref IDREF #REQUIRED
>
<!-- If no priority element is specified, then the configurator MUST not -->
<!-- touch the priority of root. -->
<!-- The root category always exists and cannot be subclassed. -->
<!ELEMENT root (param*, (priority|level)?, appender-ref*)>
<!-- ==================================================================== -->
<!-- A logging event -->
<!-- ==================================================================== -->
<!ELEMENT log4j:eventSet (log4j:event*)>
<!ATTLIST log4j:eventSet
xmlns:log4j CDATA #FIXED "http://jakarta.apache.org/log4j/"
version (1.1|1.2) "1.2"
includesLocationInfo (true|false) "true"
>
<!ELEMENT log4j:event (log4j:message, log4j:NDC?, log4j:throwable?,
log4j:locationInfo?) >
<!-- The timestamp format is application dependent. -->
<!ATTLIST log4j:event
logger CDATA #REQUIRED
level CDATA #REQUIRED
thread CDATA #REQUIRED
timestamp CDATA #REQUIRED
>
<!ELEMENT log4j:message (#PCDATA)>
<!ELEMENT log4j:NDC (#PCDATA)>
<!ELEMENT log4j:throwable (#PCDATA)>
<!ELEMENT log4j:locationInfo EMPTY>
<!ATTLIST log4j:locationInfo
class CDATA #REQUIRED
method CDATA #REQUIRED
file CDATA #REQUIRED
line CDATA #REQUIRED
>

View file

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<!-- Appenders -->
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p: %c - %m%n" />
</layout>
</appender>
<logger name="org.springframework.test.web">
<level value="trace" />
</logger>
<!-- Root Logger -->
<root>
<priority value="info" /><!--
<level value="info"></level>
--><appender-ref ref="console" />
</root>
</log4j:configuration>

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
<resetJUL>true</resetJUL>
</contextListener>
<!-- To enable JMX Management -->
<jmxConfigurator/>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-5level %logger{0} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.springframework.samples.petclinic" level="debug"/>
<root level="warn">
<appender-ref ref="console"/>
</root>
</configuration>

View file

@ -1,101 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- <!--
Application context definition for PetClinic on JPA. Application context definition for PetClinic on JPA.
--> -->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd xmlns:jpa="http://www.springframework.org/schema/data/jpa"
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- ========================= RESOURCE DEFINITIONS ========================= --> <!-- ========================= RESOURCE DEFINITIONS ========================= -->
<!-- import the dataSource definition --> <!-- import the dataSource definition -->
<import resource="datasource-config.xml"/> <import resource="datasource-config.xml"/>
<!-- Configurer that replaces ${...} placeholders with values from a properties file --> <!-- Configurer that replaces ${...} placeholders with values from a properties file -->
<!-- (in this case, JDBC-related settings for the JPA EntityManager definition below) --> <!-- (in this case, JDBC-related settings for the JPA EntityManager definition below) -->
<context:property-placeholder location="classpath:spring/jdbc.properties"/> <context:property-placeholder location="classpath:spring/jdbc.properties"/>
<!-- ========================= BUSINESS OBJECT DEFINITIONS ========================= --> <!-- ========================= BUSINESS OBJECT DEFINITIONS ========================= -->
<!-- <!--
Activates various annotations to be detected in bean classes: Spring's Activates various annotations to be detected in bean classes: Spring's
@Required and @Autowired, as well as JSR 250's @PostConstruct, @Required and @Autowired, as well as JSR 250's @PostConstruct,
@PreDestroy and @Resource (if available) and JPA's @PersistenceContext @PreDestroy and @Resource (if available) and JPA's @PersistenceContext
and @PersistenceUnit (if available). and @PersistenceUnit (if available).
--> -->
<context:annotation-config/> <context:annotation-config/>
<!-- <!--
Instruct Spring to perform declarative transaction management Instruct Spring to perform declarative transaction management
automatically on annotated classes. automatically on annotated classes.
for mode="aspectj"/ see SPR-6392 for mode="aspectj"/ see SPR-6392
--> -->
<tx:annotation-driven/> <tx:annotation-driven/>
<beans profile="jpa,spring-data-jpa"> <beans profile="jpa,spring-data-jpa">
<!-- JPA EntityManagerFactory --> <!-- JPA EntityManagerFactory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource"> p:dataSource-ref="dataSource">
<property name="jpaVendorAdapter"> <property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
p:database="${jpa.database}" p:showSql="${jpa.showSql}" /> p:database="${jpa.database}" p:showSql="${jpa.showSql}"/>
</property> </property>
<property name="persistenceUnitName" value="petclinic" /> <!-- gDickens: BOTH Persistence Unit and Packages to Scan are NOT compatible, persistenceUnit will win -->
<property name="packagesToScan" value="org/springframework/samples/petclinic" /> <property name="persistenceUnitName" value="petclinic"/>
</bean> <property name="packagesToScan" value="org.springframework.samples.petclinic"/>
</bean>
<!-- Transaction manager for a single JPA EntityManagerFactory (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory"/>
<!--
Post-processor to perform exception translation on @Repository classes (from native
exceptions such as JPA PersistenceExceptions to Spring's DataAccessException hierarchy).
-->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
</beans>
<beans profile="jdbc">
<!-- Transaction manager for a single JDBC DataSource (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!-- Transaction manager for a single JPA EntityManagerFactory (alternative to JTA) -->
<constructor-arg ref="dataSource" /> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
</bean> p:entityManagerFactory-ref="entityManagerFactory"/>
<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 profile="jpa">
<!--
Will automatically be transactional due to @Transactional.
EntityManager will be auto-injected due to @PersistenceContext.
PersistenceExceptions will be auto-translated due to @Repository.
-->
<context:component-scan base-package="org.springframework.samples.petclinic.repository.jpa"/>
</beans>
<!--
<beans profile="spring-data-jpa"> Post-processor to perform exception translation on @Repository classes (from native
<jpa:repositories base-package="org.springframework.samples.petclinic.repository.springdatajpa"/> exceptions such as JPA PersistenceExceptions to Spring's DataAccessException hierarchy).
-->
<!-- Custom configuration for the custom implementation based on JPA --> <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="owerRepository" class="org.springframework.samples.petclinic.repository.springdatajpa.JpaOwnerRepositoryImpl"/>
</beans>
</beans>
<beans profile="jdbc">
<!-- Transaction manager for a single JDBC DataSource (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
<bean id="namedParameterJdbcTemplate"
class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
<context:component-scan base-package="org.springframework.samples.petclinic.repository.jdbc"/>
</beans>
<beans profile="jpa">
<!--
Will automatically be transactional due to @Transactional.
EntityManager will be auto-injected due to @PersistenceContext.
PersistenceExceptions will be auto-translated due to @Repository.
-->
<context:component-scan base-package="org.springframework.samples.petclinic.repository.jpa"/>
</beans>
<beans profile="spring-data-jpa">
<jpa:repositories base-package="org.springframework.samples.petclinic.repository.springdatajpa"/>
<!-- Custom configuration for the custom implementation based on JPA -->
<bean id="owerRepository"
class="org.springframework.samples.petclinic.repository.springdatajpa.JpaOwnerRepositoryImpl"/>
</beans>
</beans> </beans>

View file

@ -1,37 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- <!--
Application context definition for PetClinic Datasource. Application context definition for PetClinic Datasource.
--> -->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation=" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd"> http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc
<!-- ========================= DATASOURCE DEFINITION ========================= --> http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
<!-- Configurer that replaces ${...} placeholders with values from a properties file --> <!-- ========================= DATASOURCE DEFINITION ========================= -->
<!-- (in this case, JDBC-related settings for the dataSource definition below) -->
<context:property-placeholder location="classpath:spring/jdbc.properties"/>
<!-- DataSource configuration for Apache Commons DBCP. --> <!-- Configurer that replaces ${...} placeholders with values from a properties file -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" <!-- (in this case, JDBC-related settings for the dataSource definition below) -->
p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" <context:property-placeholder location="classpath:spring/jdbc.properties"/>
p:username="${jdbc.username}" p:password="${jdbc.password}"/>
<!-- JNDI DataSource for JEE environments -->
<!--
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/petclinic"/>
-->
<!-- Database initializer. If any of the script fails, the initialization stops. --> <!-- DataSource configuration for Apache Commons DBCP. -->
<!-- As an alternative, for embedded databases see <jdbc:embedded-database/>. --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
<jdbc:initialize-database data-source="dataSource"> p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}"
<jdbc:script location="${jdbc.initLocation}"/> p:username="${jdbc.username}" p:password="${jdbc.password}"/>
<jdbc:script location="${jdbc.dataLocation}"/>
</jdbc:initialize-database> <!-- JNDI DataSource for JEE environments -->
<!--
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/petclinic"/>
-->
<!-- Database initializer. If any of the script fails, the initialization stops. -->
<!-- As an alternative, for embedded databases see <jdbc:embedded-database/>. -->
<jdbc:initialize-database data-source="dataSource">
<jdbc:script location="${jdbc.initLocation}"/>
<jdbc:script location="${jdbc.dataLocation}"/>
</jdbc:initialize-database>
</beans> </beans>

View file

@ -4,9 +4,6 @@
# various application context XML files (e.g., "applicationContext-*.xml"). # various application context XML files (e.g., "applicationContext-*.xml").
# Targeted at system administrators, to avoid touching the context XML files. # Targeted at system administrators, to avoid touching the context XML files.
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# HSQL Settings # HSQL Settings

View file

@ -1,57 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- <!--
- DispatcherServlet application context for PetClinic's web tier. - DispatcherServlet application context for PetClinic's web tier.
--> -->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oxm="http://www.springframework.org/schema/oxm" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd xmlns:mvc="http://www.springframework.org/schema/mvc"
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<import resource="mvc-view-config.xml"/> <import resource="mvc-view-config.xml"/>
<!--
- POJOs labeled with the @Controller and @Service annotations are auto-detected.
-->
<context:component-scan base-package="org.springframework.samples.petclinic.web, org.springframework.samples.petclinic.service"/>
<mvc:annotation-driven conversion-service="conversionService" />
<!-- all resources inside folder src/main/webapp/resources are mapped so they can be refered to inside JSP files
(see header.jsp for more details) -->
<mvc:resources mapping="/resources/**" location="/resources/"/>
<!-- uses WebJars so Javascript and CSS libs can be declared as Maven dependencies (Bootstrap, jQuery...) -->
<mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/"/>
<mvc:view-controller path="/" view-name="welcome"/>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="org.springframework.samples.petclinic.web.PetTypeFormatter" />
</set>
</property>
</bean>
<!--
- Message source for this context, loaded from localized "messages_xx" files.
- Files are stored inside src/main/resources
-->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"
p:basename="messages/messages"/>
<!-- <!--
- This bean resolves specific types of exceptions to corresponding logical - POJOs labeled with the @Controller and @Service annotations are auto-detected.
- view names for error views. -->
--> <context:component-scan
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> base-package="org.springframework.samples.petclinic.web, org.springframework.samples.petclinic.service"/>
<!-- view name resolved using bean of type InternalResourceViewResolver (declared in mvc-view-config.xml) -->
<property name="defaultErrorView" value="exception"/> <!-- results into 'WEB-INF/jsp/exception.jsp' --> <mvc:annotation-driven conversion-service="conversionService"/>
<property name="warnLogCategory" value="warn"/> <!-- needed otherwise exceptions won't be logged anywhere -->
</bean> <!-- all resources inside folder src/main/webapp/resources are mapped so they can be refered to inside JSP files
(see header.jsp for more details) -->
<mvc:resources mapping="/resources/**" location="/resources/"/>
<!-- uses WebJars so Javascript and CSS libs can be declared as Maven dependencies (Bootstrap, jQuery...) -->
<mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars/"/>
<mvc:view-controller path="/" view-name="welcome"/>
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class="org.springframework.samples.petclinic.web.PetTypeFormatter"/>
</set>
</property>
</bean>
<!--
- Message source for this context, loaded from localized "messages_xx" files.
- Files are stored inside src/main/resources
-->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"
p:basename="messages/messages"/>
<!--
- This bean resolves specific types of exceptions to corresponding logical
- view names for error views.
-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- view name resolved using bean of type InternalResourceViewResolver (declared in mvc-view-config.xml) -->
<property name="defaultErrorView" value="exception"/>
<!-- results into 'WEB-INF/jsp/exception.jsp' -->
<property name="warnLogCategory" value="warn"/>
<!-- needed otherwise exceptions won't be logged anywhere -->
</bean>
</beans> </beans>

View file

@ -2,52 +2,50 @@
<!-- <!--
- DispatcherServlet application context for PetClinic's web tier. - DispatcherServlet application context for PetClinic's web tier.
--> -->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oxm="http://www.springframework.org/schema/oxm" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:oxm="http://www.springframework.org/schema/oxm"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd xsi:schemaLocation="http://www.springframework.org/schema/oxm
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd http://www.springframework.org/schema/oxm/spring-oxm.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/beans
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
- The ContentNegotiatingViewResolver delegates to the InternalResourceViewResolver and BeanNameViewResolver,
- and uses the requested media type (determined by the path extension) to pick a matching view.
- When the media type is 'text/html', it will delegate to the InternalResourceViewResolver's JstlView,
- otherwise to the BeanNameViewResolver.
-->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="contentNegotiationManager" ref="cnManager"/>
</bean>
<!-- Simple strategy: only path extension is taken into account -->
<bean id="cnManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="true"/>
<property name="ignoreAcceptHeader" value="true"/>
</bean>
<!-- <!-- Default viewClass: JSTL view (JSP with html output) -->
- The ContentNegotiatingViewResolver delegates to the InternalResourceViewResolver and BeanNameViewResolver, <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- and uses the requested media type (determined by the path extension) to pick a matching view. <!-- Example: a logical view name of 'vets' is mapped to '/WEB-INF/jsp/vets.jsp' -->
- When the media type is 'text/html', it will delegate to the InternalResourceViewResolver's JstlView, <property name="prefix" value="/WEB-INF/jsp/"/>
- otherwise to the BeanNameViewResolver. <property name="suffix" value=".jsp"/>
--> </bean>
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="contentNegotiationManager" ref="cnManager"/>
</bean>
<!-- Simple strategy: only path extension is taken into account --> <!-- Used here for 'xml' and 'atom' views -->
<bean id="cnManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"> <bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
<property name="favorPathExtension" value="true"/>
<property name="ignoreAcceptHeader" value="true"/>
</bean>
<!-- Default viewClass: JSTL view (JSP with html output) --> <!-- Renders an Atom feed of the visits. Used by the BeanNameViewResolver -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <bean id="vets/vetList.atom" class="org.springframework.samples.petclinic.web.VetsAtomView"/>
<!-- Example: a logical view name of 'vets' is mapped to '/WEB-INF/jsp/vets.jsp' -->
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- Used here for 'xml' and 'atom' views -->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
<!-- Renders an Atom feed of the visits. Used by the BeanNameViewResolver --> <!-- Renders an XML view. Used by the BeanNameViewResolver -->
<bean id="vets/vetList.atom" class="org.springframework.samples.petclinic.web.VetsAtomView"/> <bean id="vets/vetList.xml" class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="marshaller" ref="marshaller"/>
</bean>
<!-- Renders an XML view. Used by the BeanNameViewResolver --> <oxm:jaxb2-marshaller id="marshaller">
<bean id="vets/vetList.xml" class="org.springframework.web.servlet.view.xml.MarshallingView"> <!-- Object-XML mapping declared using annotations inside 'Vets' -->
<property name="marshaller" ref="marshaller"/> <oxm:class-to-be-bound name="org.springframework.samples.petclinic.model.Vets"/>
</bean> </oxm:jaxb2-marshaller>
<oxm:jaxb2-marshaller id="marshaller">
<!-- Object-XML mapping declared using annotations inside 'Vets' -->
<oxm:class-to-be-bound name="org.springframework.samples.petclinic.model.Vets"/>
</oxm:jaxb2-marshaller>
</beans> </beans>

View file

@ -2,44 +2,48 @@
<!-- <!--
Application context definition for PetClinic on JPA. Application context definition for PetClinic on JPA.
--> -->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cache="http://www.springframework.org/schema/cache" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd xmlns:cache="http://www.springframework.org/schema/cache"
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- <!--
Simply defining this bean will cause requests to owner names to be saved. Simply defining this bean will cause requests to owner names to be saved.
This aspect is defined in petclinic.jar's META-INF/aop.xml file. This aspect is defined in petclinic.jar's META-INF/aop.xml file.
Note that we can dependency inject this bean like any other bean. Note that we can dependency inject this bean like any other bean.
--> -->
<aop:aspectj-autoproxy> <aop:aspectj-autoproxy>
<aop:include name="callMonitor"/> <aop:include name="callMonitor"/>
</aop:aspectj-autoproxy> </aop:aspectj-autoproxy>
<!-- Call monitoring aspect that monitors call count and call invocation time --> <!-- Call monitoring aspect that monitors call count and call invocation time -->
<bean id="callMonitor" class="org.springframework.samples.petclinic.util.CallMonitoringAspect"/> <bean id="callMonitor" class="org.springframework.samples.petclinic.util.CallMonitoringAspect"/>
<!-- <!--
Exporter that exposes the CallMonitoringAspect via JMX, Exporter that exposes the CallMonitoringAspect via JMX,
based on the @ManagedResource, @ManagedAttribute, and @ManagedOperation annotations. based on the @ManagedResource, @ManagedAttribute, and @ManagedOperation annotations.
--> -->
<context:mbean-export /> <context:mbean-export/>
<!-- enables scanning for @Cacheable annotation --> <!-- enables scanning for @Cacheable annotation -->
<cache:annotation-driven /> <cache:annotation-driven/>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcache"/> <property name="cacheManager" ref="ehcache"/>
</bean>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"/>
</bean> </bean>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"/>
</bean>
</beans> </beans>

View file

@ -1,27 +1,29 @@
<html lang="en"> <html lang="en">
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<jsp:include page="fragments/headTag.jsp"/> <jsp:include page="fragments/headTag.jsp"/>
<body> <body>
<div class="container"> <div class="container">
<jsp:include page="fragments/bodyHeader.jsp"/> <jsp:include page="fragments/bodyHeader.jsp"/>
<spring:url value="/resources/images/pets.png" var="petsImage"/> <spring:url value="/resources/images/pets.png" var="petsImage"/>
<img src="${petsImage}" /> <img src="${petsImage}"/>
<h2>Something happened...</h2>
<p>${exception.message}</p> <h2>Something happened...</h2>
<!-- Exception: ${exception.message}. <p>${exception.message}</p>
<!-- Exception: ${exception.message}.
<c:forEach items="${exception.stackTrace}" var="stackTrace"> <c:forEach items="${exception.stackTrace}" var="stackTrace">
${stackTrace} ${stackTrace}
</c:forEach> </c:forEach>
--> -->
<jsp:include page="fragments/footer.jsp"/>
</div>
<jsp:include page="fragments/footer.jsp"/>
</div>
</body> </body>
</html> </html>

View file

@ -2,16 +2,23 @@
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<spring:url value="/resources/images/banner-graphic.png" var="banner"/> <spring:url value="/resources/images/banner-graphic.png" var="banner"/>
<img src="${banner}" /> <img src="${banner}"/>
<div class="navbar" style="width: 601px;">
<div class="navbar-inner"> <div class="navbar" style="width: 601px;">
<ul class="nav"> <div class="navbar-inner">
<li style="width: 100px;"><a href="<spring:url value="/" htmlEscape="true" />"><i class="icon-home"></i> Home</a></li> <ul class="nav">
<li style="width: 130px;"><a href="<spring:url value="/owners/find.html" htmlEscape="true" />"><i class="icon-search"></i> Find owners</a></li> <li style="width: 100px;"><a href="<spring:url value="/" htmlEscape="true" />"><i class="icon-home"></i>
<li style="width: 140px;"><a href="<spring:url value="/vets.html" htmlEscape="true" />"><i class="icon-th-list"></i> Veterinarians</a></li> Home</a></li>
<li style="width: 90px;"><a href="<spring:url value="/oups.html" htmlEscape="true" />" title="trigger a RuntimeException to see how it is handled"><i class="icon-warning-sign"></i> Error</a></li> <li style="width: 130px;"><a href="<spring:url value="/owners/find.html" htmlEscape="true" />"><i
<li style="width: 80px;"><a href="#" title="not available yet. Work in progress!!"><i class=" icon-question-sign"></i> Help</a></li> class="icon-search"></i> Find owners</a></li>
</ul> <li style="width: 140px;"><a href="<spring:url value="/vets.html" htmlEscape="true" />"><i
</div> class="icon-th-list"></i> Veterinarians</a></li>
<li style="width: 90px;"><a href="<spring:url value="/oups.html" htmlEscape="true" />"
title="trigger a RuntimeException to see how it is handled"><i
class="icon-warning-sign"></i> Error</a></li>
<li style="width: 80px;"><a href="#" title="not available yet. Work in progress!!"><i
class=" icon-question-sign"></i> Help</a></li>
</ul>
</div>
</div> </div>

View file

@ -1,10 +1,11 @@
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<table class="footer"> <table class="footer">
<tr> <tr>
<td></td> <td></td>
<td align="right"><img src="<spring:url value="/resources/images/springsource-logo.png" htmlEscape="true" />" alt="Sponsored by SpringSource"/></td> <td align="right"><img src="<spring:url value="/resources/images/springsource-logo.png" htmlEscape="true" />"
alt="Sponsored by SpringSource"/></td>
</tr> </tr>
</table> </table>

View file

@ -1,28 +1,28 @@
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<!-- <!--
PetClinic :: a Spring Framework demonstration PetClinic :: a Spring Framework demonstration
--> -->
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>PetClinic :: a Spring Framework demonstration</title> <title>PetClinic :: a Spring Framework demonstration</title>
<spring:url value="/webjars/bootstrap/2.2.1/css/bootstrap.min.css" var="bootstrapCss" />
<link href="${bootstrapCss}" rel="stylesheet"/> <spring:url value="/webjars/bootstrap/2.2.1/css/bootstrap.min.css" var="bootstrapCss"/>
<link href="${bootstrapCss}" rel="stylesheet"/>
<spring:url value="/resources/css/petclinic.css" var="petclinicCss" />
<link href="${petclinicCss}" rel="stylesheet"/> <spring:url value="/resources/css/petclinic.css" var="petclinicCss"/>
<link href="${petclinicCss}" rel="stylesheet"/>
<spring:url value="/webjars/jquery/1.8.2/jquery.js" var="jQuery" />
<script src="${jQuery}"></script> <spring:url value="/webjars/jquery/1.8.2/jquery.js" var="jQuery"/>
<script src="${jQuery}"></script>
<spring:url value="/webjars/jquery-ui/1.9.1/js/jquery-ui-1.9.1.custom.js" var="jQueryUi" />
<script src="${jQueryUi}"></script> <spring:url value="/webjars/jquery-ui/1.9.1/js/jquery-ui-1.9.1.custom.js" var="jQueryUi"/>
<script src="${jQueryUi}"></script>
<spring:url value="/webjars/jquery-ui/1.9.1/css/smoothness/jquery-ui-1.9.1.custom.css" var="jQueryUiCss" />
<link href="${jQueryUiCss}" rel="stylesheet"></link> <spring:url value="/webjars/jquery-ui/1.9.1/css/smoothness/jquery-ui-1.9.1.custom.css" var="jQueryUiCss"/>
<link href="${jQueryUiCss}" rel="stylesheet"></link>
</head> </head>

View file

@ -11,36 +11,36 @@
<jsp:include page="../fragments/headTag.jsp"/> <jsp:include page="../fragments/headTag.jsp"/>
<body> <body>
<div class="container"> <div class="container">
<jsp:include page="../fragments/bodyHeader.jsp"/> <jsp:include page="../fragments/bodyHeader.jsp"/>
<c:choose> <c:choose>
<c:when test="${owner['new']}"><c:set var="method" value="post"/></c:when> <c:when test="${owner['new']}"><c:set var="method" value="post"/></c:when>
<c:otherwise><c:set var="method" value="put"/></c:otherwise> <c:otherwise><c:set var="method" value="put"/></c:otherwise>
</c:choose> </c:choose>
<h2>
<c:if test="${owner['new']}">New </c:if> Owner
</h2>
<form:form modelAttribute="owner" method="${method}" class="form-horizontal" id="add-owner-form">
<petclinic:inputField label="First Name" name="firstName" />
<petclinic:inputField label="Last Name" name="lastName" />
<petclinic:inputField label="Address" name="address" />
<petclinic:inputField label="City" name="city" />
<petclinic:inputField label="Telephone" name="telephone" />
<div class="form-actions"> <h2>
<c:choose> <c:if test="${owner['new']}">New </c:if> Owner
<c:when test="${owner['new']}"> </h2>
<button type="submit">Add Owner</button> <form:form modelAttribute="owner" method="${method}" class="form-horizontal" id="add-owner-form">
</c:when> <petclinic:inputField label="First Name" name="firstName"/>
<c:otherwise> <petclinic:inputField label="Last Name" name="lastName"/>
<button type="submit">Update Owner</button> <petclinic:inputField label="Address" name="address"/>
</c:otherwise> <petclinic:inputField label="City" name="city"/>
</c:choose> <petclinic:inputField label="Telephone" name="telephone"/>
</div>
</form:form> <div class="form-actions">
</div> <c:choose>
<jsp:include page="../fragments/footer.jsp"/> <c:when test="${owner['new']}">
<button type="submit">Add Owner</button>
</c:when>
<c:otherwise>
<button type="submit">Update Owner</button>
</c:otherwise>
</c:choose>
</div>
</form:form>
</div>
<jsp:include page="../fragments/footer.jsp"/>
</body> </body>
</html> </html>

View file

@ -8,31 +8,32 @@
<jsp:include page="../fragments/headTag.jsp"/> <jsp:include page="../fragments/headTag.jsp"/>
<body> <body>
<div class="container"> <div class="container">
<jsp:include page="../fragments/bodyHeader.jsp"/> <jsp:include page="../fragments/bodyHeader.jsp"/>
<h2>Find Owners</h2> <h2>Find Owners</h2>
<spring:url value="/owners.html" var="formUrl"/>
<form:form modelAttribute="owner" action="${fn:escapeXml(formUrl)}" method="get" class="form-horizontal" id="search-owner-form">
<fieldset>
<div class="control-group" id="lastName">
<label class="control-label">Last name </label>
<form:input path="lastName" size="30" maxlength="80"/>
<span class="help-inline"><form:errors path="*" /></span>
</div>
<div class="form-actions">
<button type="submit">Find Owner</button>
</div>
</fieldset>
</form:form>
<br/>
<a href='<spring:url value="/owners/new" htmlEscape="true"/>'>Add Owner</a>
<jsp:include page="../fragments/footer.jsp"/>
</div> <spring:url value="/owners.html" var="formUrl"/>
<form:form modelAttribute="owner" action="${fn:escapeXml(formUrl)}" method="get" class="form-horizontal"
id="search-owner-form">
<fieldset>
<div class="control-group" id="lastName">
<label class="control-label">Last name </label>
<form:input path="lastName" size="30" maxlength="80"/>
<span class="help-inline"><form:errors path="*"/></span>
</div>
<div class="form-actions">
<button type="submit">Find Owner</button>
</div>
</fieldset>
</form:form>
<br/>
<a href='<spring:url value="/owners/new" htmlEscape="true"/>'>Add Owner</a>
<jsp:include page="../fragments/footer.jsp"/>
</div>
</body> </body>
</html> </html>

View file

@ -9,111 +9,111 @@
<jsp:include page="../fragments/headTag.jsp"/> <jsp:include page="../fragments/headTag.jsp"/>
<body> <body>
<div class="container"> <div class="container">
<jsp:include page="../fragments/bodyHeader.jsp"/> <jsp:include page="../fragments/bodyHeader.jsp"/>
<h2>Owner Information</h2> <h2>Owner Information</h2>
<table class="table table-striped" style="width:600px;"> <table class="table table-striped" style="width:600px;">
<tr> <tr>
<th>Name</th> <th>Name</th>
<td><b><c:out value="${owner.firstName} ${owner.lastName}"/></b></td> <td><b><c:out value="${owner.firstName} ${owner.lastName}"/></b></td>
</tr> </tr>
<tr> <tr>
<th>Address</th> <th>Address</th>
<td><c:out value="${owner.address}"/></td> <td><c:out value="${owner.address}"/></td>
</tr> </tr>
<tr> <tr>
<th>City</th> <th>City</th>
<td><c:out value="${owner.city}"/></td> <td><c:out value="${owner.city}"/></td>
</tr> </tr>
<tr> <tr>
<th>Telephone </th> <th>Telephone</th>
<td><c:out value="${owner.telephone}"/></td> <td><c:out value="${owner.telephone}"/></td>
</tr> </tr>
</table> </table>
<table class="table-buttons"> <table class="table-buttons">
<tr> <tr>
<td colspan="2" align="center"> <td colspan="2" align="center">
<spring:url value="{ownerId}/edit.html" var="editUrl"> <spring:url value="{ownerId}/edit.html" var="editUrl">
<spring:param name="ownerId" value="${owner.id}" /> <spring:param name="ownerId" value="${owner.id}"/>
</spring:url> </spring:url>
<a href="${fn:escapeXml(editUrl)}">Edit Owner</a> <a href="${fn:escapeXml(editUrl)}">Edit Owner</a>
</td> </td>
<td> <td>
<spring:url value="{ownerId}/pets/new.html" var="addUrl"> <spring:url value="{ownerId}/pets/new.html" var="addUrl">
<spring:param name="ownerId" value="${owner.id}" /> <spring:param name="ownerId" value="${owner.id}"/>
</spring:url> </spring:url>
<a href="${fn:escapeXml(addUrl)}">Add New Pet</a> <a href="${fn:escapeXml(addUrl)}">Add New Pet</a>
</td> </td>
</tr> </tr>
</table> </table>
<h2>Pets and Visits</h2> <h2>Pets and Visits</h2>
<c:forEach var="pet" items="${owner.pets}"> <c:forEach var="pet" items="${owner.pets}">
<table class="table" style="width:600px;"> <table class="table" style="width:600px;">
<tr> <tr>
<td valign="top" style="width: 120px;"> <td valign="top" style="width: 120px;">
<dl class="dl-horizontal"> <dl class="dl-horizontal">
<dt>Name</dt> <dt>Name</dt>
<dd><c:out value="${pet.name}"/></dd> <dd><c:out value="${pet.name}"/></dd>
<dt>Birth Date</dt> <dt>Birth Date</dt>
<dd><joda:format value="${pet.birthDate}" pattern="yyyy-MM-dd" /></dd> <dd><joda:format value="${pet.birthDate}" pattern="yyyy-MM-dd"/></dd>
<dt>Type</dt> <dt>Type</dt>
<dd><c:out value="${pet.type.name}"/></dd> <dd><c:out value="${pet.type.name}"/></dd>
</dl> </dl>
</td> </td>
<td valign="top"> <td valign="top">
<table class="table-condensed"> <table class="table-condensed">
<thead> <thead>
<tr> <tr>
<th>Visit Date</th> <th>Visit Date</th>
<th>Description</th> <th>Description</th>
</tr> </tr>
</thead> </thead>
<c:forEach var="visit" items="${pet.visits}"> <c:forEach var="visit" items="${pet.visits}">
<tr> <tr>
<td><joda:format value="${visit.date}" pattern="yyyy-MM-dd"/></td> <td><joda:format value="${visit.date}" pattern="yyyy-MM-dd"/></td>
<td><c:out value="${visit.description}"/></td> <td><c:out value="${visit.description}"/></td>
</tr> </tr>
</c:forEach> </c:forEach>
</table> </table>
</td> </td>
</tr> </tr>
</table> </table>
<table class="table-buttons"> <table class="table-buttons">
<tr> <tr>
<td> <td>
<spring:url value="/owners/{ownerId}/pets/{petId}/edit" var="petUrl"> <spring:url value="/owners/{ownerId}/pets/{petId}/edit" var="petUrl">
<spring:param name="ownerId" value="${owner.id}"/> <spring:param name="ownerId" value="${owner.id}"/>
<spring:param name="petId" value="${pet.id}"/> <spring:param name="petId" value="${pet.id}"/>
</spring:url> </spring:url>
<a href="${fn:escapeXml(petUrl)}">Edit Pet</a> <a href="${fn:escapeXml(petUrl)}">Edit Pet</a>
</td> </td>
<td></td> <td></td>
<td> <td>
<spring:url value="/owners/{ownerId}/pets/{petId}/visits/new" var="visitUrl"> <spring:url value="/owners/{ownerId}/pets/{petId}/visits/new" var="visitUrl">
<spring:param name="ownerId" value="${owner.id}"/> <spring:param name="ownerId" value="${owner.id}"/>
<spring:param name="petId" value="${pet.id}"/> <spring:param name="petId" value="${pet.id}"/>
</spring:url> </spring:url>
<a href="${fn:escapeXml(visitUrl)}">Add Visit</a> <a href="${fn:escapeXml(visitUrl)}">Add Visit</a>
</td> </td>
<td></td> <td></td>
<td> <td>
<spring:url value="/owners/{ownerId}/pets/{petId}/visits.atom" var="feedUrl"> <spring:url value="/owners/{ownerId}/pets/{petId}/visits.atom" var="feedUrl">
<spring:param name="ownerId" value="${owner.id}"/> <spring:param name="ownerId" value="${owner.id}"/>
<spring:param name="petId" value="${pet.id}"/> <spring:param name="petId" value="${pet.id}"/>
</spring:url> </spring:url>
<a href="${fn:escapeXml(feedUrl)}" rel="alternate" type="application/atom+xml">Atom Feed</a> <a href="${fn:escapeXml(feedUrl)}" rel="alternate" type="application/atom+xml">Atom Feed</a>
</td> </td>
</tr> </tr>
</table> </table>
</c:forEach> </c:forEach>
<jsp:include page="../fragments/footer.jsp"/> <jsp:include page="../fragments/footer.jsp"/>
</div> </div>
</body> </body>

View file

@ -9,42 +9,42 @@
<jsp:include page="../fragments/headTag.jsp"/> <jsp:include page="../fragments/headTag.jsp"/>
<body> <body>
<div class="container"> <div class="container">
<jsp:include page="../fragments/bodyHeader.jsp"/> <jsp:include page="../fragments/bodyHeader.jsp"/>
<h2>Owners</h2> <h2>Owners</h2>
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
<tr> <tr>
<th style="width: 150px;">Name</th> <th style="width: 150px;">Name</th>
<th style="width: 200px;">Address</th> <th style="width: 200px;">Address</th>
<th>City</th> <th>City</th>
<th>Telephone</th> <th>Telephone</th>
<th style="width: 100px;">Pets</th> <th style="width: 100px;">Pets</th>
</tr> </tr>
</thead> </thead>
<c:forEach var="owner" items="${selections}"> <c:forEach var="owner" items="${selections}">
<tr> <tr>
<td> <td>
<spring:url value="owners/{ownerId}.html" var="ownerUrl"> <spring:url value="owners/{ownerId}.html" var="ownerUrl">
<spring:param name="ownerId" value="${owner.id}"/> <spring:param name="ownerId" value="${owner.id}"/>
</spring:url> </spring:url>
<a href="${fn:escapeXml(ownerUrl)}"><c:out value="${owner.firstName} ${owner.lastName}" /></a> <a href="${fn:escapeXml(ownerUrl)}"><c:out value="${owner.firstName} ${owner.lastName}"/></a>
</td> </td>
<td><c:out value="${owner.address}"/></td> <td><c:out value="${owner.address}"/></td>
<td><c:out value="${owner.city}"/></td> <td><c:out value="${owner.city}"/></td>
<td><c:out value="${owner.telephone}"/></td> <td><c:out value="${owner.telephone}"/></td>
<td> <td>
<c:forEach var="pet" items="${owner.pets}"> <c:forEach var="pet" items="${owner.pets}">
<c:out value="${pet.name}"/> <c:out value="${pet.name}"/>
</c:forEach> </c:forEach>
</td> </td>
</tr> </tr>
</c:forEach> </c:forEach>
</table> </table>
<jsp:include page="../fragments/footer.jsp"/> <jsp:include page="../fragments/footer.jsp"/>
</div> </div>
</body> </body>
</html> </html>

View file

@ -1,6 +1,6 @@
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="petclinic" tagdir="/WEB-INF/tags" %> <%@ taglib prefix="petclinic" tagdir="/WEB-INF/tags" %>
@ -10,54 +10,54 @@
<body> <body>
<script> <script>
$(function() { $(function () {
$("#birthDate").datepicker({ dateFormat: 'yy/mm/dd'}); $("#birthDate").datepicker({ dateFormat: 'yy/mm/dd'});
}); });
</script> </script>
<div class="container"> <div class="container">
<jsp:include page="../fragments/bodyHeader.jsp" /> <jsp:include page="../fragments/bodyHeader.jsp"/>
<c:choose> <c:choose>
<c:when test="${pet['new']}"> <c:when test="${pet['new']}">
<c:set var="method" value="post" /> <c:set var="method" value="post"/>
</c:when> </c:when>
<c:otherwise> <c:otherwise>
<c:set var="method" value="put" /> <c:set var="method" value="put"/>
</c:otherwise> </c:otherwise>
</c:choose> </c:choose>
<h2> <h2>
<c:if test="${pet['new']}">New </c:if> <c:if test="${pet['new']}">New </c:if>
Pet Pet
</h2> </h2>
<form:form modelAttribute="pet" method="${method}" <form:form modelAttribute="pet" method="${method}"
class="form-horizontal"> class="form-horizontal">
<div class="control-group" id="owner"> <div class="control-group" id="owner">
<label class="control-label">Owner </label> <label class="control-label">Owner </label>
<c:out value="${pet.owner.firstName} ${pet.owner.lastName}"/> <c:out value="${pet.owner.firstName} ${pet.owner.lastName}"/>
</div> </div>
<petclinic:inputField label="Name" name="name" /> <petclinic:inputField label="Name" name="name"/>
<petclinic:inputField label="Birth Date" name="birthDate" /> <petclinic:inputField label="Birth Date" name="birthDate"/>
<div class="control-group"> <div class="control-group">
<label class="control-label">Type </label> <label class="control-label">Type </label>
<form:select path="type" items="${types}" size="5"/> <form:select path="type" items="${types}" size="5"/>
</div> </div>
<div class="form-actions"> <div class="form-actions">
<c:choose> <c:choose>
<c:when test="${pet['new']}"> <c:when test="${pet['new']}">
<button type="submit">Add Pet</button> <button type="submit">Add Pet</button>
</c:when> </c:when>
<c:otherwise> <c:otherwise>
<button type="submit">Update Pet</button> <button type="submit">Update Pet</button>
</c:otherwise> </c:otherwise>
</c:choose> </c:choose>
</div> </div>
</form:form> </form:form>
<c:if test="${!pet['new']}"> <c:if test="${!pet['new']}">
</c:if> </c:if>
<jsp:include page="../fragments/footer.jsp" /> <jsp:include page="../fragments/footer.jsp"/>
</div> </div>
</body> </body>
</html> </html>

View file

@ -10,73 +10,75 @@
<body> <body>
<script> <script>
$(function() { $(function () {
$("#date").datepicker({ dateFormat: 'yy/mm/dd'}); $("#date").datepicker({ dateFormat: 'yy/mm/dd'});
}); });
</script> </script>
<div class="container"> <div class="container">
<jsp:include page="../fragments/bodyHeader.jsp"/> <jsp:include page="../fragments/bodyHeader.jsp"/>
<h2><c:if test="${visit['new']}">New </c:if>Visit</h2> <h2><c:if test="${visit['new']}">New </c:if>Visit</h2>
<b>Pet</b>
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Birth Date</th>
<th>Type</th>
<th>Owner</th>
</tr>
</thead>
<tr>
<td><c:out value="${visit.pet.name}" /></td>
<td><joda:format value="${visit.pet.birthDate}" pattern="yyyy/MM/dd"/></td>
<td><c:out value="${visit.pet.type.name}" /></td>
<td><c:out value="${visit.pet.owner.firstName} ${visit.pet.owner.lastName}" /></td>
</tr>
</table>
<form:form modelAttribute="visit">
<div class="control-group">
<label class="control-label">Date </label>
<div class="controls">
<form:input path="date" />
<span class="help-inline"><form:errors path="date" /></span>
</div>
</div>
<div class="control-group">
<label class="control-label">Description </label>
<div class="controls">
<form:input path="description" />
<span class="help-inline"><form:errors path="description" /></span>
</div>
</div>
<div class="form-actions">
<input type="hidden" name="petId" value="${visit.pet.id}"/>
<button type="submit">Add Visit</button>
</div>
</form:form>
<br/>
<b>Previous Visits</b>
<table style="width: 333px;">
<tr>
<th>Date</th>
<th>Description</th>
</tr>
<c:forEach var="visit" items="${visit.pet.visits}">
<c:if test="${!visit['new']}">
<tr>
<td><joda:format value="${visit.date}" pattern="yyyy/MM/dd"/></td>
<td><c:out value="${visit.description}" /></td>
</tr>
</c:if>
</c:forEach>
</table>
</div> <b>Pet</b>
<jsp:include page="../fragments/footer.jsp"/> <table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Birth Date</th>
<th>Type</th>
<th>Owner</th>
</tr>
</thead>
<tr>
<td><c:out value="${visit.pet.name}"/></td>
<td><joda:format value="${visit.pet.birthDate}" pattern="yyyy/MM/dd"/></td>
<td><c:out value="${visit.pet.type.name}"/></td>
<td><c:out value="${visit.pet.owner.firstName} ${visit.pet.owner.lastName}"/></td>
</tr>
</table>
<form:form modelAttribute="visit">
<div class="control-group">
<label class="control-label">Date </label>
<div class="controls">
<form:input path="date"/>
<span class="help-inline"><form:errors path="date"/></span>
</div>
</div>
<div class="control-group">
<label class="control-label">Description </label>
<div class="controls">
<form:input path="description"/>
<span class="help-inline"><form:errors path="description"/></span>
</div>
</div>
<div class="form-actions">
<input type="hidden" name="petId" value="${visit.pet.id}"/>
<button type="submit">Add Visit</button>
</div>
</form:form>
<br/>
<b>Previous Visits</b>
<table style="width: 333px;">
<tr>
<th>Date</th>
<th>Description</th>
</tr>
<c:forEach var="visit" items="${visit.pet.visits}">
<c:if test="${!visit['new']}">
<tr>
<td><joda:format value="${visit.date}" pattern="yyyy/MM/dd"/></td>
<td><c:out value="${visit.description}"/></td>
</tr>
</c:if>
</c:forEach>
</table>
</div>
<jsp:include page="../fragments/footer.jsp"/>
</body> </body>
</html> </html>

View file

@ -9,45 +9,45 @@
<jsp:include page="../fragments/headTag.jsp"/> <jsp:include page="../fragments/headTag.jsp"/>
<body> <body>
<div class="container"> <div class="container">
<jsp:include page="../fragments/bodyHeader.jsp"/> <jsp:include page="../fragments/bodyHeader.jsp"/>
<h2>Veterinarians</h2> <h2>Veterinarians</h2>
<table class="table table-stripped" style="width:600px;"> <table class="table table-stripped" style="width:600px;">
<thead> <thead>
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Specialties</th> <th>Specialties</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<c:forEach var="vet" items="${vets.vetList}"> <c:forEach var="vet" items="${vets.vetList}">
<tr> <tr>
<td><c:out value="${vet.firstName} ${vet.lastName}" /></td> <td><c:out value="${vet.firstName} ${vet.lastName}"/></td>
<td> <td>
<c:forEach var="specialty" items="${vet.specialties}"> <c:forEach var="specialty" items="${vet.specialties}">
<c:out value="${specialty.name}" /> <c:out value="${specialty.name}"/>
</c:forEach> </c:forEach>
<c:if test="${vet.nrOfSpecialties == 0}">none</c:if> <c:if test="${vet.nrOfSpecialties == 0}">none</c:if>
</td> </td>
</tr> </tr>
</c:forEach> </c:forEach>
</tbody> </tbody>
</table> </table>
<table class="table-buttons"> <table class="table-buttons">
<tr> <tr>
<td> <td>
<a href="<spring:url value="/vets.xml" htmlEscape="true" />">View as XML</a> <a href="<spring:url value="/vets.xml" htmlEscape="true" />">View as XML</a>
</td> </td>
<td> <td>
<a href="<spring:url value="/vets.atom" htmlEscape="true" />">Subscribe to Atom feed</a> <a href="<spring:url value="/vets.atom" htmlEscape="true" />">Subscribe to Atom feed</a>
</td> </td>
</tr> </tr>
</table> </table>
<jsp:include page="../fragments/footer.jsp"/> <jsp:include page="../fragments/footer.jsp"/>
</div> </div>
</body> </body>
</html> </html>

View file

@ -7,15 +7,15 @@
<jsp:include page="fragments/headTag.jsp"/> <jsp:include page="fragments/headTag.jsp"/>
<body> <body>
<div class="container"> <div class="container">
<jsp:include page="fragments/bodyHeader.jsp"/> <jsp:include page="fragments/bodyHeader.jsp"/>
<h2><fmt:message key="welcome"/></h2> <h2><fmt:message key="welcome"/></h2>
<spring:url value="/resources/images/pets.png" htmlEscape="true" var="petsImage"/> <spring:url value="/resources/images/pets.png" htmlEscape="true" var="petsImage"/>
<img src="${petsImage}" /> <img src="${petsImage}"/>
<jsp:include page="fragments/footer.jsp"/>
</div> <jsp:include page="fragments/footer.jsp"/>
</div>
</body> </body>
</html> </html>

View file

@ -1,16 +1,19 @@
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ attribute name="name" required="true" rtexprvalue="true" description="Name of corresponding property in bean object"%> <%@ attribute name="name" required="true" rtexprvalue="true"
<%@ attribute name="label" required="true" rtexprvalue="true" description="Label appears in red color if input is considered as invalid after submission"%> description="Name of corresponding property in bean object" %>
<%@ attribute name="label" required="true" rtexprvalue="true"
description="Label appears in red color if input is considered as invalid after submission" %>
<spring:bind path="${name}"> <spring:bind path="${name}">
<c:set var="cssGroup" value="control-group ${status.error ? 'error' : '' }"/> <c:set var="cssGroup" value="control-group ${status.error ? 'error' : '' }"/>
<div class="${cssGroup}"> <div class="${cssGroup}">
<label class="control-label">${label}</label> <label class="control-label">${label}</label>
<div class="controls">
<form:input path="${name}"/> <div class="controls">
<span class="help-inline">${status.errorMessage}</span> <form:input path="${name}"/>
</div> <span class="help-inline">${status.errorMessage}</span>
</div> </div>
</div>
</spring:bind> </spring:bind>

View file

@ -1,64 +1,65 @@
<?xml version="1.0" encoding="ISO-8859-1"?> <?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
id="WebApp_ID" version="2.5"> http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>Spring PetClinic</display-name> <display-name>Spring PetClinic</display-name>
<description>Spring PetClinic sample application</description> <description>Spring PetClinic sample application</description>
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>jdbc</param-value>
<!-- Available profiles:
<param-value>jdbc</param-value>
<param-value>jpa</param-value> (in the case of plain JPA)
<param-value>spring-data-jpa</param-value> (in the case of Spring Data JPA)
-->
</context-param>
<!-- <context-param>
- Location of the XML file that defines the root application context. <param-name>spring.profiles.active</param-name>
- Applied by ContextLoaderServlet. <param-value>jdbc</param-value>
--> <!-- Available profiles:
<context-param> <param-value>jdbc</param-value>
<param-name>contextConfigLocation</param-name> <param-value>jpa</param-value> (in the case of plain JPA)
<param-value>classpath:spring/dao-config.xml, classpath:spring/tools-config.xml</param-value> <param-value>spring-data-jpa</param-value> (in the case of Spring Data JPA)
</context-param> -->
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--
- Servlet that dispatches request to registered handlers (Controller implementations).
-->
<servlet>
<servlet-name>petclinic</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/mvc-core-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping> <!--
<servlet-name>petclinic</servlet-name> - Location of the XML file that defines the root application context.
<url-pattern>/</url-pattern> - Applied by ContextLoaderServlet.
</servlet-mapping> -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/dao-config.xml, classpath:spring/tools-config.xml</param-value>
</context-param>
<!-- used so we can use forms of method type 'PUT' and 'DELETE' <listener>
see here: http://static.springsource.org/spring/docs/current/spring-framework-reference/html/view.html#rest-method-conversion <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
--> </listener>
<filter>
<filter-name>httpMethodFilter</filter-name> <!--
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> - Servlet that dispatches request to registered handlers (Controller implementations).
</filter> -->
<servlet>
<servlet-name>petclinic</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/mvc-core-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>petclinic</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- used so we can use forms of method type 'PUT' and 'DELETE'
see here: http://static.springsource.org/spring/docs/current/spring-framework-reference/html/view.html#rest-method-conversion
-->
<filter>
<filter-name>httpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>httpMethodFilter</filter-name>
<servlet-name>petclinic</servlet-name>
</filter-mapping>
<filter-mapping>
<filter-name>httpMethodFilter</filter-name>
<servlet-name>petclinic</servlet-name>
</filter-mapping>
</web-app> </web-app>

View file

@ -1,21 +1,21 @@
.container { .container {
padding-top: 10px; padding-top: 10px;
margin-left: 50px; margin-left: 50px;
width: 700px; width: 700px;
} }
.form-horizontal { .form-horizontal {
width: 100%; width: 100%;
} }
input[type="text"] { input[type="text"] {
height: 25px; height: 25px;
} }
.navbar .nav > li > a { .navbar .nav > li > a {
color: #000000; color: #000000;
} }
.form-horizontal .control-label { .form-horizontal .control-label {
text-align: left; text-align: left;
} }

View file

@ -15,14 +15,12 @@
*/ */
package org.springframework.samples.petclinic.model; package org.springframework.samples.petclinic.model;
import org.junit.Test;
import org.springframework.transaction.annotation.Transactional;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import org.junit.Test;
import org.springframework.samples.petclinic.model.Owner;
import org.springframework.samples.petclinic.model.Pet;
import org.springframework.transaction.annotation.Transactional;
/** /**
* JUnit test for the {@link Owner} class. * JUnit test for the {@link Owner} class.
* *
@ -30,16 +28,17 @@ import org.springframework.transaction.annotation.Transactional;
*/ */
public class OwnerTests { public class OwnerTests {
@Test @Transactional @Test
public void testHasPet() { @Transactional
Owner owner = new Owner(); public void testHasPet() {
Pet fido = new Pet(); Owner owner = new Owner();
fido.setName("Fido"); Pet fido = new Pet();
assertNull(owner.getPet("Fido")); fido.setName("Fido");
assertNull(owner.getPet("fido")); assertNull(owner.getPet("Fido"));
owner.addPet(fido); assertNull(owner.getPet("fido"));
assertEquals(fido, owner.getPet("Fido")); owner.addPet(fido);
assertEquals(fido, owner.getPet("fido")); assertEquals(fido, owner.getPet("Fido"));
} assertEquals(fido, owner.getPet("fido"));
}
} }

View file

@ -15,44 +15,29 @@
*/ */
package org.springframework.samples.petclinic.repository; package org.springframework.samples.petclinic.repository;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Collection;
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.model.Owner; import org.springframework.samples.petclinic.model.Owner;
import org.springframework.samples.petclinic.repository.OwnerRepository;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/** /**
* <p> * <p> Base class for {@link OwnerRepository} integration tests. </p> <p> Subclasses should specify Spring context
* Base class for {@link OwnerRepository} integration tests. * configuration using {@link ContextConfiguration @ContextConfiguration} annotation </p> <p>
* </p> * AbstractOwnerRepositoryTests and its subclasses benefit from the following services provided by the Spring
* <p> * TestContext Framework: </p> <ul> <li><strong>Spring IoC container caching</strong> which spares us unnecessary set up
* Subclasses should specify Spring context configuration using {@link ContextConfiguration @ContextConfiguration} annotation * time between test execution.</li> <li><strong>Dependency Injection</strong> of test fixture instances, meaning that
* </p> * we don't need to perform application context lookups. See the use of {@link Autowired @Autowired} on the <code>{@link
* <p> * AbstractOwnerRepositoryTests#ownerRepository ownerRepository}</code> instance variable, which uses autowiring <em>by
* AbstractOwnerRepositoryTests and its subclasses benefit from the following services * type</em>. <li><strong>Transaction management</strong>, meaning each test method is executed in its own transaction,
* provided by the Spring TestContext Framework: * which is automatically rolled back by default. Thus, even if tests insert or otherwise change database state, there
* </p> * is no need for a teardown or cleanup script. <li> An {@link org.springframework.context.ApplicationContext
* <ul> * ApplicationContext} is also inherited and can be used for explicit bean lookup if necessary. </li> </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>{@link AbstractOwnerRepositoryTests#ownerRepository ownerRepository}</code> instance
* variable, which uses autowiring <em>by type</em>.
* <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.
* <li> An {@link org.springframework.context.ApplicationContext ApplicationContext} is
* also inherited and can be used for explicit bean lookup if necessary.
* </li>
* </ul>
* *
* @author Ken Krebs * @author Ken Krebs
* @author Rod Johnson * @author Rod Johnson
@ -62,52 +47,55 @@ import org.springframework.transaction.annotation.Transactional;
*/ */
public abstract class AbstractOwnerRepositoryTests { public abstract class AbstractOwnerRepositoryTests {
@Autowired @Autowired
protected OwnerRepository ownerRepository; protected OwnerRepository ownerRepository;
@Test @Transactional @Test
public void findOwners() { @Transactional
Collection<Owner> owners = this.ownerRepository.findByLastName("Davis"); public void findOwners() {
assertEquals(2, owners.size()); Collection<Owner> owners = this.ownerRepository.findByLastName("Davis");
owners = this.ownerRepository.findByLastName("Daviss"); assertEquals(2, owners.size());
assertEquals(0, owners.size()); owners = this.ownerRepository.findByLastName("Daviss");
} assertEquals(0, owners.size());
}
@Test @Transactional @Test
public void findSingleOwner() { @Transactional
Owner owner1 = this.ownerRepository.findById(1); public void findSingleOwner() {
assertTrue(owner1.getLastName().startsWith("Franklin")); Owner owner1 = this.ownerRepository.findById(1);
Owner owner10 = this.ownerRepository.findById(10); assertTrue(owner1.getLastName().startsWith("Franklin"));
assertEquals("Carlos", owner10.getFirstName()); Owner owner10 = this.ownerRepository.findById(10);
assertEquals("Carlos", owner10.getFirstName());
assertEquals(owner1.getPets().size(), 1); assertEquals(owner1.getPets().size(), 1);
} }
@Test @Transactional @Test
public void insertOwner() { @Transactional
Collection<Owner> owners = this.ownerRepository.findByLastName("Schultz"); public void insertOwner() {
int found = owners.size(); Collection<Owner> owners = this.ownerRepository.findByLastName("Schultz");
Owner owner = new Owner(); int found = owners.size();
owner.setFirstName("Sam"); Owner owner = new Owner();
owner.setLastName("Schultz"); owner.setFirstName("Sam");
owner.setAddress("4, Evans Street"); owner.setLastName("Schultz");
owner.setCity("Wollongong"); owner.setAddress("4, Evans Street");
owner.setTelephone("4444444444"); owner.setCity("Wollongong");
this.ownerRepository.save(owner); owner.setTelephone("4444444444");
owners = this.ownerRepository.findByLastName("Schultz"); this.ownerRepository.save(owner);
assertEquals("Verifying number of owners after inserting a new one.", found + 1, owners.size()); owners = this.ownerRepository.findByLastName("Schultz");
} assertEquals("Verifying number of owners after inserting a new one.", found + 1, owners.size());
}
@Test @Transactional
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());
}
@Test
@Transactional
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

@ -15,27 +15,23 @@
*/ */
package org.springframework.samples.petclinic.repository; package org.springframework.samples.petclinic.repository;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.Collection;
import org.joda.time.DateTime; import org.joda.time.DateTime;
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.model.Owner; import org.springframework.samples.petclinic.model.Owner;
import org.springframework.samples.petclinic.model.Pet; import org.springframework.samples.petclinic.model.Pet;
import org.springframework.samples.petclinic.model.PetType; import org.springframework.samples.petclinic.model.PetType;
import org.springframework.samples.petclinic.repository.OwnerRepository;
import org.springframework.samples.petclinic.repository.PetRepository;
import org.springframework.samples.petclinic.util.EntityUtils; import org.springframework.samples.petclinic.util.EntityUtils;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/** /**
* <p> * <p> Base class for {@link OwnerRepository} integration tests. </p>
* Base class for {@link OwnerRepository} integration tests. * <p/>
* </p>
* <p>
* see javadoc inside {@link AbstractOwnerRepositoryTests} for more details * see javadoc inside {@link AbstractOwnerRepositoryTests} for more details
* *
* @author Ken Krebs * @author Ken Krebs
@ -46,62 +42,66 @@ import org.springframework.transaction.annotation.Transactional;
*/ */
public abstract class AbstractPetRepositoryTests { public abstract class AbstractPetRepositoryTests {
@Autowired @Autowired
protected PetRepository petRepository; protected PetRepository petRepository;
@Autowired @Autowired
protected OwnerRepository ownerRepository; protected OwnerRepository ownerRepository;
@Test @Transactional @Test
public void getPetTypes() { @Transactional
Collection<PetType> petTypes = this.petRepository.findPetTypes(); public void getPetTypes() {
Collection<PetType> petTypes = this.petRepository.findPetTypes();
PetType petType1 = EntityUtils.getById(petTypes, PetType.class, 1);
assertEquals("cat", petType1.getName());
PetType petType4 = EntityUtils.getById(petTypes, PetType.class, 4);
assertEquals("snake", petType4.getName());
}
@Test @Transactional PetType petType1 = EntityUtils.getById(petTypes, PetType.class, 1);
public void findPet() { assertEquals("cat", petType1.getName());
Collection<PetType> types = this.petRepository.findPetTypes(); PetType petType4 = EntityUtils.getById(petTypes, PetType.class, 4);
Pet pet7 = this.petRepository.findById(7); assertEquals("snake", petType4.getName());
assertTrue(pet7.getName().startsWith("Samantha")); }
assertEquals(EntityUtils.getById(types, PetType.class, 1).getId(), pet7.getType().getId());
assertEquals("Jean", pet7.getOwner().getFirstName());
Pet pet6 = this.petRepository.findById(6);
assertEquals("George", pet6.getName());
assertEquals(EntityUtils.getById(types, PetType.class, 4).getId(), pet6.getType().getId());
assertEquals("Peter", pet6.getOwner().getFirstName());
}
@Test @Transactional @Test
public void insertPet() { @Transactional
Owner owner6 = this.ownerRepository.findById(6); public void findPet() {
int found = owner6.getPets().size(); Collection<PetType> types = this.petRepository.findPetTypes();
Pet pet = new Pet(); Pet pet7 = this.petRepository.findById(7);
pet.setName("bowser"); assertTrue(pet7.getName().startsWith("Samantha"));
Collection<PetType> types = this.petRepository.findPetTypes(); assertEquals(EntityUtils.getById(types, PetType.class, 1).getId(), pet7.getType().getId());
pet.setType(EntityUtils.getById(types, PetType.class, 2)); assertEquals("Jean", pet7.getOwner().getFirstName());
pet.setBirthDate(new DateTime()); Pet pet6 = this.petRepository.findById(6);
owner6.addPet(pet); assertEquals("George", pet6.getName());
assertEquals(found + 1, owner6.getPets().size()); assertEquals(EntityUtils.getById(types, PetType.class, 4).getId(), pet6.getType().getId());
// both storePet and storeOwner are necessary to cover all ORM tools assertEquals("Peter", pet6.getOwner().getFirstName());
this.petRepository.save(pet); }
this.ownerRepository.save(owner6);
owner6 = this.ownerRepository.findById(6);
assertEquals(found + 1, owner6.getPets().size());
}
@Test @Transactional @Test
public void updatePet() throws Exception { @Transactional
Pet pet7 = this.petRepository.findById(7); public void insertPet() {
String old = pet7.getName(); Owner owner6 = this.ownerRepository.findById(6);
pet7.setName(old + "X"); int found = owner6.getPets().size();
this.petRepository.save(pet7); Pet pet = new Pet();
pet7 = this.petRepository.findById(7); pet.setName("bowser");
assertEquals(old + "X", pet7.getName()); Collection<PetType> types = this.petRepository.findPetTypes();
} pet.setType(EntityUtils.getById(types, PetType.class, 2));
pet.setBirthDate(new DateTime());
owner6.addPet(pet);
assertEquals(found + 1, owner6.getPets().size());
// both storePet and storeOwner are necessary to cover all ORM tools
this.petRepository.save(pet);
this.ownerRepository.save(owner6);
owner6 = this.ownerRepository.findById(6);
assertEquals(found + 1, owner6.getPets().size());
}
@Test
@Transactional
public void updatePet() throws Exception {
Pet pet7 = this.petRepository.findById(7);
String old = pet7.getName();
pet7.setName(old + "X");
this.petRepository.save(pet7);
pet7 = this.petRepository.findById(7);
assertEquals(old + "X", pet7.getName());
}
} }

View file

@ -15,23 +15,19 @@
*/ */
package org.springframework.samples.petclinic.repository; package org.springframework.samples.petclinic.repository;
import static org.junit.Assert.assertEquals;
import java.util.Collection;
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.model.Vet; import org.springframework.samples.petclinic.model.Vet;
import org.springframework.samples.petclinic.repository.OwnerRepository;
import org.springframework.samples.petclinic.repository.VetRepository;
import org.springframework.samples.petclinic.util.EntityUtils; import org.springframework.samples.petclinic.util.EntityUtils;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import static org.junit.Assert.assertEquals;
/** /**
* <p> * <p> Base class for {@link OwnerRepository} integration tests. </p>
* Base class for {@link OwnerRepository} integration tests. * <p/>
* </p>
* <p>
* see javadoc inside {@link AbstractVetRepositoryTests} for more details * see javadoc inside {@link AbstractVetRepositoryTests} for more details
* *
* @author Ken Krebs * @author Ken Krebs
@ -42,23 +38,24 @@ import org.springframework.transaction.annotation.Transactional;
*/ */
public abstract class AbstractVetRepositoryTests { public abstract class AbstractVetRepositoryTests {
@Autowired @Autowired
protected VetRepository vetRepository; protected VetRepository vetRepository;
@Test @Transactional @Test
public void findVets() { @Transactional
Collection<Vet> vets = this.vetRepository.findAll(); public void findVets() {
Collection<Vet> vets = this.vetRepository.findAll();
Vet v1 = EntityUtils.getById(vets, Vet.class, 2);
assertEquals("Leary", v1.getLastName()); Vet v1 = EntityUtils.getById(vets, Vet.class, 2);
assertEquals(1, v1.getNrOfSpecialties()); assertEquals("Leary", v1.getLastName());
assertEquals("radiology", (v1.getSpecialties().get(0)).getName()); assertEquals(1, v1.getNrOfSpecialties());
Vet v2 = EntityUtils.getById(vets, Vet.class, 3); assertEquals("radiology", (v1.getSpecialties().get(0)).getName());
assertEquals("Douglas", v2.getLastName()); Vet v2 = EntityUtils.getById(vets, Vet.class, 3);
assertEquals(2, v2.getNrOfSpecialties()); assertEquals("Douglas", v2.getLastName());
assertEquals("dentistry", (v2.getSpecialties().get(0)).getName()); assertEquals(2, v2.getNrOfSpecialties());
assertEquals("surgery", (v2.getSpecialties().get(1)).getName()); assertEquals("dentistry", (v2.getSpecialties().get(0)).getName());
} assertEquals("surgery", (v2.getSpecialties().get(1)).getName());
}
} }

View file

@ -15,22 +15,17 @@
*/ */
package org.springframework.samples.petclinic.repository; package org.springframework.samples.petclinic.repository;
import static org.junit.Assert.assertEquals;
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.model.Pet; import org.springframework.samples.petclinic.model.Pet;
import org.springframework.samples.petclinic.model.Visit; import org.springframework.samples.petclinic.model.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.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import static org.junit.Assert.assertEquals;
/** /**
* <p> * <p> Base class for {@link OwnerRepository} integration tests. </p>
* Base class for {@link OwnerRepository} integration tests. * <p/>
* </p>
* <p>
* see javadoc inside {@link AbstractVetRepositoryTests} for more details * see javadoc inside {@link AbstractVetRepositoryTests} for more details
* *
* @author Ken Krebs * @author Ken Krebs
@ -41,25 +36,26 @@ import org.springframework.transaction.annotation.Transactional;
*/ */
public abstract class AbstractVisitRepositoryTests { public abstract class AbstractVisitRepositoryTests {
@Autowired @Autowired
protected VisitRepository visitRepository; protected VisitRepository visitRepository;
@Autowired @Autowired
protected PetRepository petRepository; protected PetRepository petRepository;
@Test @Transactional @Test
public void insertVisit() { @Transactional
Pet pet7 = this.petRepository.findById(7); public void insertVisit() {
int found = pet7.getVisits().size(); Pet pet7 = this.petRepository.findById(7);
Visit visit = new Visit(); int found = pet7.getVisits().size();
pet7.addVisit(visit); Visit visit = new Visit();
visit.setDescription("test"); pet7.addVisit(visit);
// both storeVisit and storePet are necessary to cover all ORM tools visit.setDescription("test");
this.visitRepository.save(visit); // both storeVisit and storePet are necessary to cover all ORM tools
this.petRepository.save(pet7); this.visitRepository.save(visit);
pet7 = this.petRepository.findById(7); this.petRepository.save(pet7);
assertEquals(found + 1, pet7.getVisits().size()); pet7 = this.petRepository.findById(7);
} assertEquals(found + 1, pet7.getVisits().size());
}
} }

View file

@ -22,20 +22,15 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/** /**
* <p> * <p> Integration tests for the {@link JdbcClinicImpl} implementation. </p> <p> </p>
* Integration tests for the {@link JdbcClinicImpl} implementation.
* </p>
* <p>
* </p>
* *
* @author Thomas Risberg * @author Thomas Risberg
* @author Michael Isvy * @author Michael Isvy
*/ */
@ContextConfiguration(locations={"classpath:spring/dao-config.xml"}) @ContextConfiguration(locations = {"classpath:spring/dao-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("jdbc") @ActiveProfiles("jdbc")
public class JdbcOwnerRepositoryImplTests extends AbstractOwnerRepositoryTests { public class JdbcOwnerRepositoryImplTests extends AbstractOwnerRepositoryTests {
} }

View file

@ -7,20 +7,15 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/** /**
* <p> * <p> Integration tests for the {@link JdbcClinicImpl} implementation. </p> <p> </p>
* Integration tests for the {@link JdbcClinicImpl} implementation.
* </p>
* <p>
* </p>
* *
* @author Thomas Risberg * @author Thomas Risberg
* @author Michael Isvy * @author Michael Isvy
*/ */
@ContextConfiguration(locations={"classpath:spring/dao-config.xml"}) @ContextConfiguration(locations = {"classpath:spring/dao-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("jdbc") @ActiveProfiles("jdbc")
public class JdbcPetRepositoryImplTests extends AbstractPetRepositoryTests { public class JdbcPetRepositoryImplTests extends AbstractPetRepositoryTests {
} }

View file

@ -7,20 +7,15 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/** /**
* <p> * <p> Integration tests for the {@link JdbcClinicImpl} implementation. </p> <p> </p>
* Integration tests for the {@link JdbcClinicImpl} implementation.
* </p>
* <p>
* </p>
* *
* @author Thomas Risberg * @author Thomas Risberg
* @author Michael Isvy * @author Michael Isvy
*/ */
@ContextConfiguration(locations={"classpath:spring/dao-config.xml"}) @ContextConfiguration(locations = {"classpath:spring/dao-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("jdbc") @ActiveProfiles("jdbc")
public class JdbcVetRepositoryImplTests extends AbstractVetRepositoryTests { public class JdbcVetRepositoryImplTests extends AbstractVetRepositoryTests {
} }

View file

@ -7,20 +7,15 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/** /**
* <p> * <p> Integration tests for the {@link JdbcClinicImpl} implementation. </p> <p> </p>
* Integration tests for the {@link JdbcClinicImpl} implementation.
* </p>
* <p>
* </p>
* *
* @author Thomas Risberg * @author Thomas Risberg
* @author Michael Isvy * @author Michael Isvy
*/ */
@ContextConfiguration(locations={"classpath:spring/dao-config.xml"}) @ContextConfiguration(locations = {"classpath:spring/dao-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("jdbc") @ActiveProfiles("jdbc")
public class JdbcVisitRepositoryImplTests extends AbstractVisitRepositoryTests { public class JdbcVisitRepositoryImplTests extends AbstractVisitRepositoryTests {
} }

View file

@ -8,27 +8,19 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/** /**
* <p> * <p> Provides the following services: <ul> <li>Injects test dependencies, meaning that we don't need to perform
* Provides the following services: * application context lookups. See the setClinic() method. Injection uses autowiring by type.</li> <li>Executes each
* <ul> * test method in its own transaction, which is automatically rolled back by default. This means that even if tests
* <li>Injects test dependencies, meaning that we don't need to perform * insert or otherwise change database state, there is no need for a teardown or cleanup script.</li> </ul> <p> </p>
* application context lookups. See the setClinic() method. Injection uses
* autowiring by type.</li>
* <li>Executes each test method in its own transaction, which is automatically
* rolled back by default. This means that even if tests insert or otherwise
* change database state, there is no need for a teardown or cleanup script.</li>
* </ul>
* <p>
* </p>
* *
* @author Rod Johnson * @author Rod Johnson
* @author Sam Brannen * @author Sam Brannen
* @author Michael Isvy * @author Michael Isvy
*/ */
@ContextConfiguration(locations={"classpath:spring/dao-config.xml"}) @ContextConfiguration(locations = {"classpath:spring/dao-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("jpa") @ActiveProfiles("jpa")
public class JpaOwnerRepositoryImplTests extends AbstractOwnerRepositoryTests { public class JpaOwnerRepositoryImplTests extends AbstractOwnerRepositoryTests {
} }

View file

@ -7,20 +7,15 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/** /**
* <p> * <p> Integration tests for the {@link JdbcClinicImpl} implementation. </p> <p> </p>
* Integration tests for the {@link JdbcClinicImpl} implementation.
* </p>
* <p>
* </p>
* *
* @author Thomas Risberg * @author Thomas Risberg
* @author Michael Isvy * @author Michael Isvy
*/ */
@ContextConfiguration(locations={"classpath:spring/dao-config.xml"}) @ContextConfiguration(locations = {"classpath:spring/dao-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("jpa") @ActiveProfiles("jpa")
public class JpaPetRepositoryImplTests extends AbstractPetRepositoryTests { public class JpaPetRepositoryImplTests extends AbstractPetRepositoryTests {
} }

View file

@ -7,20 +7,15 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/** /**
* <p> * <p> Integration tests for the {@link JdbcClinicImpl} implementation. </p> <p> </p>
* Integration tests for the {@link JdbcClinicImpl} implementation.
* </p>
* <p>
* </p>
* *
* @author Thomas Risberg * @author Thomas Risberg
* @author Michael Isvy * @author Michael Isvy
*/ */
@ContextConfiguration(locations={"classpath:spring/dao-config.xml"}) @ContextConfiguration(locations = {"classpath:spring/dao-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("jpa") @ActiveProfiles("jpa")
public class JpaVetRepositoryImplTests extends AbstractVetRepositoryTests { public class JpaVetRepositoryImplTests extends AbstractVetRepositoryTests {
} }

View file

@ -7,20 +7,15 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/** /**
* <p> * <p> Integration tests for the {@link JdbcClinicImpl} implementation. </p> <p> </p>
* Integration tests for the {@link JdbcClinicImpl} implementation.
* </p>
* <p>
* </p>
* *
* @author Thomas Risberg * @author Thomas Risberg
* @author Michael Isvy * @author Michael Isvy
*/ */
@ContextConfiguration(locations={"classpath:spring/dao-config.xml"}) @ContextConfiguration(locations = {"classpath:spring/dao-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("jpa") @ActiveProfiles("jpa")
public class JpaVisitRepositoryImplTests extends AbstractVisitRepositoryTests { public class JpaVisitRepositoryImplTests extends AbstractVisitRepositoryTests {
} }

View file

@ -8,27 +8,19 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/** /**
* <p> * <p> Provides the following services: <ul> <li>Injects test dependencies, meaning that we don't need to perform
* Provides the following services: * application context lookups. See the setClinic() method. Injection uses autowiring by type.</li> <li>Executes each
* <ul> * test method in its own transaction, which is automatically rolled back by default. This means that even if tests
* <li>Injects test dependencies, meaning that we don't need to perform * insert or otherwise change database state, there is no need for a teardown or cleanup script.</li> </ul> <p> </p>
* application context lookups. See the setClinic() method. Injection uses
* autowiring by type.</li>
* <li>Executes each test method in its own transaction, which is automatically
* rolled back by default. This means that even if tests insert or otherwise
* change database state, there is no need for a teardown or cleanup script.</li>
* </ul>
* <p>
* </p>
* *
* @author Rod Johnson * @author Rod Johnson
* @author Sam Brannen * @author Sam Brannen
* @author Michael Isvy * @author Michael Isvy
*/ */
@ContextConfiguration(locations={"classpath:spring/dao-config.xml"}) @ContextConfiguration(locations = {"classpath:spring/dao-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("spring-data-jpa") @ActiveProfiles("spring-data-jpa")
public class JpaOwnerRepositoryImplTests extends AbstractOwnerRepositoryTests { public class JpaOwnerRepositoryImplTests extends AbstractOwnerRepositoryTests {
} }

View file

@ -7,20 +7,15 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/** /**
* <p> * <p> Integration tests for the {@link JdbcClinicImpl} implementation. </p> <p> </p>
* Integration tests for the {@link JdbcClinicImpl} implementation.
* </p>
* <p>
* </p>
* *
* @author Thomas Risberg * @author Thomas Risberg
* @author Michael Isvy * @author Michael Isvy
*/ */
@ContextConfiguration(locations={"classpath:spring/dao-config.xml"}) @ContextConfiguration(locations = {"classpath:spring/dao-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("spring-data-jpa") @ActiveProfiles("spring-data-jpa")
public class JpaPetRepositoryImplTests extends AbstractPetRepositoryTests { public class JpaPetRepositoryImplTests extends AbstractPetRepositoryTests {
} }

View file

@ -7,20 +7,15 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/** /**
* <p> * <p> Integration tests for the {@link JdbcClinicImpl} implementation. </p> <p> </p>
* Integration tests for the {@link JdbcClinicImpl} implementation.
* </p>
* <p>
* </p>
* *
* @author Thomas Risberg * @author Thomas Risberg
* @author Michael Isvy * @author Michael Isvy
*/ */
@ContextConfiguration(locations={"classpath:spring/dao-config.xml"}) @ContextConfiguration(locations = {"classpath:spring/dao-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("spring-data-jpa") @ActiveProfiles("spring-data-jpa")
public class JpaVetRepositoryImplTests extends AbstractVetRepositoryTests { public class JpaVetRepositoryImplTests extends AbstractVetRepositoryTests {
} }

View file

@ -7,20 +7,15 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/** /**
* <p> * <p> Integration tests for the {@link JdbcClinicImpl} implementation. </p> <p> </p>
* Integration tests for the {@link JdbcClinicImpl} implementation.
* </p>
* <p>
* </p>
* *
* @author Thomas Risberg * @author Thomas Risberg
* @author Michael Isvy * @author Michael Isvy
*/ */
@ContextConfiguration(locations={"classpath:spring/dao-config.xml"}) @ContextConfiguration(locations = {"classpath:spring/dao-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("spring-data-jpa") @ActiveProfiles("spring-data-jpa")
public class JpaVisitRepositoryImplTests extends AbstractVisitRepositoryTests { public class JpaVisitRepositoryImplTests extends AbstractVisitRepositoryTests {
} }

View file

@ -11,9 +11,9 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
* @author Michael Isvy * @author Michael Isvy
*/ */
@ContextConfiguration(locations={"classpath:spring/dao-config.xml"}) @ContextConfiguration(locations = {"classpath:spring/dao-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("spring-data-jpa") @ActiveProfiles("spring-data-jpa")
public class SpringDataOwnerRepositoryTests extends AbstractOwnerRepositoryTests { public class SpringDataOwnerRepositoryTests extends AbstractOwnerRepositoryTests {
} }

View file

@ -16,14 +16,8 @@
package org.springframework.samples.petclinic.web; package org.springframework.samples.petclinic.web;
import static org.junit.Assert.assertEquals; import com.sun.syndication.feed.atom.Entry;
import static org.junit.Assert.assertNotNull; import com.sun.syndication.feed.atom.Feed;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -31,63 +25,68 @@ import org.springframework.samples.petclinic.model.Pet;
import org.springframework.samples.petclinic.model.PetType; import org.springframework.samples.petclinic.model.PetType;
import org.springframework.samples.petclinic.model.Visit; import org.springframework.samples.petclinic.model.Visit;
import com.sun.syndication.feed.atom.Entry; import java.util.ArrayList;
import com.sun.syndication.feed.atom.Feed; import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/** /**
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Michael Isvy * @author Michael Isvy
*/ */
public class VisitsAtomViewTest { public class VisitsAtomViewTest {
private VetsAtomView visitView; private VetsAtomView visitView;
private Map<String, Object> model; private Map<String, Object> model;
private Feed feed; private Feed feed;
@Before @Before
public void setUp() { public void setUp() {
visitView = new VetsAtomView(); visitView = new VetsAtomView();
PetType dog = new PetType(); PetType dog = new PetType();
dog.setName("dog"); dog.setName("dog");
Pet bello = new Pet(); Pet bello = new Pet();
bello.setName("Bello"); bello.setName("Bello");
bello.setType(dog); bello.setType(dog);
Visit belloVisit = new Visit(); Visit belloVisit = new Visit();
belloVisit.setPet(bello); belloVisit.setPet(bello);
belloVisit.setDate(new DateTime(2009, 1, 1, 1, 1)); belloVisit.setDate(new DateTime(2009, 1, 1, 1, 1));
belloVisit.setDescription("Bello visit"); belloVisit.setDescription("Bello visit");
Pet wodan = new Pet(); Pet wodan = new Pet();
wodan.setName("Wodan"); wodan.setName("Wodan");
wodan.setType(dog); wodan.setType(dog);
Visit wodanVisit = new Visit(); Visit wodanVisit = new Visit();
wodanVisit.setPet(wodan); wodanVisit.setPet(wodan);
wodanVisit.setDate(new DateTime(2009, 1, 2, 1, 1)); wodanVisit.setDate(new DateTime(2009, 1, 2, 1, 1));
wodanVisit.setDescription("Wodan visit"); wodanVisit.setDescription("Wodan visit");
List<Visit> visits = new ArrayList<Visit>(); List<Visit> visits = new ArrayList<Visit>();
visits.add(belloVisit); visits.add(belloVisit);
visits.add(wodanVisit); visits.add(wodanVisit);
model = new HashMap<String, Object>(); model = new HashMap<String, Object>();
model.put("visits", visits); model.put("visits", visits);
feed = new Feed(); feed = new Feed();
} }
@Test @Test
public void buildFeedMetadata() { public void buildFeedMetadata() {
visitView.buildFeedMetadata(model, feed, null); visitView.buildFeedMetadata(model, feed, null);
assertNotNull("No id set", feed.getId()); assertNotNull("No id set", feed.getId());
assertNotNull("No title set", feed.getTitle()); assertNotNull("No title set", feed.getTitle());
assertEquals("Invalid update set", new DateTime(2009, 1, 2, 1, 1).toDate(), feed.getUpdated()); assertEquals("Invalid update set", new DateTime(2009, 1, 2, 1, 1).toDate(), feed.getUpdated());
} }
@Test @Test
public void buildFeedEntries() throws Exception { public void buildFeedEntries() throws Exception {
List<Entry> entries = visitView.buildFeedEntries(model, null, null); List<Entry> entries = visitView.buildFeedEntries(model, null, null);
assertEquals("Invalid amount of entries", 2, entries.size()); assertEquals("Invalid amount of entries", 2, entries.size());
} }
} }

View file

@ -2,10 +2,12 @@
<!-- <!--
- DispatcherServlet application context for PetClinic's web tier. - DispatcherServlet application context for PetClinic's web tier.
--> -->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <beans xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
<import resource="classpath:spring/dao-config.xml"/> http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="classpath:spring/mvc-core-config.xml"/>
<import resource="classpath:spring/dao-config.xml"/>
<import resource="classpath:spring/mvc-core-config.xml"/>
</beans> </beans>

View file

@ -16,12 +16,6 @@
package org.springframework.samples.petclinic.web; package org.springframework.samples.petclinic.web;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -36,8 +30,12 @@ import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
/** /**
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Michael Isvy * @author Michael Isvy
*/ */
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ -48,23 +46,24 @@ import org.springframework.web.context.WebApplicationContext;
@ActiveProfiles("jdbc") @ActiveProfiles("jdbc")
public class VisitsAtomViewWithContainerTest { public class VisitsAtomViewWithContainerTest {
@Autowired @Autowired
private WebApplicationContext webApplicationContext; private WebApplicationContext webApplicationContext;
private MockMvc mockMvc; private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();
}
@Test @Before
public void getVisits() throws Exception { public void setup() {
MediaType mediaType = MediaType.APPLICATION_ATOM_XML; this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).build();
ResultActions actions = this.mockMvc.perform(get("/vets.atom")); }
actions.andExpect(status().isOk());
actions.andExpect(xpath("//*").string(containsString("Pet ClinicService Visits"))); @Test
actions.andExpect(content().contentType("application/atom+xml")); public void getVisits() throws Exception {
//gDickens: MediaType is not used
} MediaType mediaType = MediaType.APPLICATION_ATOM_XML;
ResultActions actions = this.mockMvc.perform(get("/vets.atom"));
actions.andExpect(status().isOk());
actions.andExpect(xpath("//*").string(containsString("Pet ClinicService Visits")));
actions.andExpect(content().contentType("application/atom+xml"));
}
} }

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
<resetJUL>true</resetJUL>
</contextListener>
<!-- To enable JMX Management -->
<jmxConfigurator/>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-5level %logger{0} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.springframework.samples.petclinic" level="debug"/>
<logger name="org.springframework.test.web" level="trace"/>
<root level="warn">
<appender-ref ref="console"/>
</root>
</configuration>