├── .classpath
├── .gitignore
├── .project
├── .settings
├── .jsdtscope
├── com.springsource.server.ide.jdt.core.xml
├── org.eclipse.jdt.core.prefs
├── org.eclipse.jst.common.project.facet.core.prefs
├── org.eclipse.wst.common.component
├── org.eclipse.wst.common.project.facet.core.xml
├── org.eclipse.wst.jsdt.ui.superType.container
├── org.eclipse.wst.jsdt.ui.superType.name
├── org.eclipse.wst.validation.prefs
├── org.maven.ide.eclipse.prefs
├── org.springframework.ide.eclipse.beans.core.prefs
└── org.springframework.ide.eclipse.core.prefs
├── .springBeans
├── Gemfile
├── Gemfile.lock
├── README.markdown
├── Rakefile
├── app
├── controllers
│ ├── application_controller.rb
│ ├── owners_controller.rb
│ ├── pets_controller.rb
│ ├── vets_controller.rb
│ ├── visits_controller.rb
│ └── welcome_controller.rb
├── helpers
│ └── application_helper.rb
├── models
│ ├── owner.rb
│ ├── pet.rb
│ ├── pet_type.rb
│ ├── vet.rb
│ └── visit.rb
└── views
│ ├── layouts
│ └── application.html.erb
│ ├── owners
│ ├── _form.html.erb
│ ├── edit.html.erb
│ ├── index.html.erb
│ ├── new.html.erb
│ ├── search.html.erb
│ └── show.html.erb
│ ├── pets
│ ├── _form.html.erb
│ ├── edit.html.erb
│ └── new.html.erb
│ ├── shared
│ └── _errors.html.erb
│ ├── vets
│ └── index.html.erb
│ ├── visits
│ ├── _form.html.erb
│ ├── edit.html.erb
│ ├── index.atom.builder
│ └── new.html.erb
│ └── welcome
│ └── index.html.erb
├── commits.html
├── config.ru
├── config
├── application.rb
├── applicationContext-dataSource.xml
├── applicationContext-hibernate.xml
├── boot.rb
├── cucumber.yml
├── environment.rb
├── environments
│ ├── development.rb
│ ├── production.rb
│ └── test.rb
├── initializers
│ ├── backtrace_silencers.rb
│ ├── classpath.rb
│ ├── inflections.rb
│ ├── load_classpath.rb
│ ├── mime_types.rb
│ ├── secret_token.rb
│ ├── session_store.rb
│ └── spring.rb
├── locales
│ ├── de.yml
│ └── en.yml
├── log4j.properties
├── routes.rb
└── warble.rb
├── features
├── owners.feature
├── pets.feature
├── smoke_test.feature
├── step_definitions
│ ├── custom_web_steps.rb
│ ├── web_steps.rb
│ └── xml_json_steps.rb
├── support
│ ├── env.rb
│ ├── paths.rb
│ └── traverse.rb
├── vets.feature
└── visits.feature
├── lib
├── java_ext.rb
├── spring_helpers.rb
└── tasks
│ ├── classpath.rake
│ ├── cucumber.rake
│ ├── database.rake
│ └── docs.rake
├── petclinic-readme.txt
├── petclinic.iml
├── pom.xml
├── public
├── 404.html
├── 422.html
├── 500.html
├── favicon.ico
├── html
│ └── tutorial.html
├── images
│ ├── banner-graphic.png
│ ├── bullet-arrow.png
│ ├── pets.png
│ ├── rails-banner-graphic.png
│ ├── rails.png
│ ├── springsource-logo.png
│ └── submit-bg.png
├── javascripts
│ ├── application.js
│ ├── controls.js
│ ├── dragdrop.js
│ ├── effects.js
│ ├── prototype.js
│ └── rails.js
├── robots.txt
└── stylesheets
│ ├── .gitkeep
│ └── petclinic.css
├── script
├── cucumber
└── rails
├── src
├── main
│ ├── java
│ │ ├── com
│ │ │ └── strobecorp
│ │ │ │ └── kirk
│ │ │ │ └── RewindableInputStream.java
│ │ ├── org
│ │ │ ├── jruby
│ │ │ │ └── rack
│ │ │ │ │ └── RubyFirstRackFilter.java
│ │ │ └── springframework
│ │ │ │ └── samples
│ │ │ │ └── petclinic
│ │ │ │ ├── BaseEntity.java
│ │ │ │ ├── Clinic.java
│ │ │ │ ├── NamedEntity.java
│ │ │ │ ├── Owner.java
│ │ │ │ ├── Person.java
│ │ │ │ ├── Pet.java
│ │ │ │ ├── PetType.java
│ │ │ │ ├── Specialty.java
│ │ │ │ ├── Vet.java
│ │ │ │ ├── Vets.java
│ │ │ │ ├── Visit.java
│ │ │ │ ├── aspects
│ │ │ │ ├── AbstractTraceAspect.java
│ │ │ │ ├── CallMonitoringAspect.java
│ │ │ │ └── UsageLogAspect.java
│ │ │ │ ├── hibernate
│ │ │ │ ├── HibernateClinic.java
│ │ │ │ └── package-info.java
│ │ │ │ ├── jdbc
│ │ │ │ ├── JdbcPet.java
│ │ │ │ ├── SimpleJdbcClinic.java
│ │ │ │ ├── SimpleJdbcClinicMBean.java
│ │ │ │ └── package-info.java
│ │ │ │ ├── jpa
│ │ │ │ ├── EntityManagerClinic.java
│ │ │ │ └── package-info.java
│ │ │ │ ├── package-info.java
│ │ │ │ ├── toplink
│ │ │ │ ├── EssentialsHSQLPlatformWithNativeSequence.java
│ │ │ │ └── package-info.java
│ │ │ │ ├── util
│ │ │ │ └── EntityUtils.java
│ │ │ │ ├── validation
│ │ │ │ ├── OwnerValidator.java
│ │ │ │ ├── PetValidator.java
│ │ │ │ ├── VisitValidator.java
│ │ │ │ └── package-info.java
│ │ │ │ └── web
│ │ │ │ ├── AddOwnerForm.java
│ │ │ │ ├── AddPetForm.java
│ │ │ │ ├── AddVisitForm.java
│ │ │ │ ├── ClinicBindingInitializer.java
│ │ │ │ ├── ClinicController.java
│ │ │ │ ├── EditOwnerForm.java
│ │ │ │ ├── EditPetForm.java
│ │ │ │ ├── FindOwnersForm.java
│ │ │ │ ├── PetTypeEditor.java
│ │ │ │ ├── VisitsAtomView.java
│ │ │ │ └── package-info.java
│ │ └── overview.html
│ └── resources
│ │ ├── META-INF
│ │ ├── aop.xml
│ │ ├── jpa-persistence.xml
│ │ └── orm.xml
│ │ ├── db
│ │ ├── db_readme.txt
│ │ ├── hsqldb
│ │ │ ├── initDB.txt
│ │ │ └── populateDB.txt
│ │ ├── mysql
│ │ │ ├── initDB.txt
│ │ │ ├── petclinic_db_setup_mysql.txt
│ │ │ └── populateDB.txt
│ │ └── petclinic_tomcat_all.xml
│ │ ├── jdbc.properties
│ │ ├── log4j.properties
│ │ ├── messages.properties
│ │ ├── messages_de.properties
│ │ ├── messages_en.properties
│ │ └── petclinic.hbm.xml
└── test
│ ├── java
│ └── org
│ │ └── springframework
│ │ └── samples
│ │ └── petclinic
│ │ ├── AbstractClinicTests.java
│ │ ├── OwnerTests.java
│ │ ├── hibernate
│ │ └── HibernateClinicTests.java
│ │ ├── jdbc
│ │ └── SimpleJdbcClinicTests.java
│ │ ├── jpa
│ │ ├── AbstractJpaClinicTests.java
│ │ ├── EntityManagerClinicTests.java
│ │ ├── HibernateEntityManagerClinicTests.java
│ │ └── OpenJpaEntityManagerClinicTests.java
│ │ └── web
│ │ └── VisitsAtomViewTest.java
│ └── resources
│ ├── log4j.xml
│ └── org
│ └── springframework
│ └── samples
│ └── petclinic
│ ├── AbstractClinicTests-context.xml
│ ├── hibernate
│ └── HibernateClinicTests-context.xml
│ ├── jdbc
│ └── SimpleJdbcClinicTests-context.xml
│ └── jpa
│ ├── applicationContext-entityManager.xml
│ ├── applicationContext-hibernateAdapter.xml
│ ├── applicationContext-jpaCommon.xml
│ ├── applicationContext-openJpaAdapter.xml
│ └── applicationContext-toplinkAdapter.xml
├── test
├── performance
│ └── browsing_test.rb
└── test_helper.rb
└── vendor
└── plugins
└── .gitkeep
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .svn
2 | target
3 | .bundle
4 | db/*.sqlite3
5 | log/*.log
6 | tmp/
7 | /refactoring-to-rails.war
8 | /vendor/bundle
9 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | org.springframework.samples.petclinic
4 |
5 |
6 | Servers
7 |
8 |
9 |
10 | org.eclipse.wst.jsdt.core.javascriptValidator
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javabuilder
16 |
17 |
18 |
19 |
20 | org.eclipse.wst.common.project.facet.core.builder
21 |
22 |
23 |
24 |
25 | org.eclipse.wst.validation.validationbuilder
26 |
27 |
28 |
29 |
30 | org.springframework.ide.eclipse.core.springbuilder
31 |
32 |
33 |
34 |
35 | org.maven.ide.eclipse.maven2Builder
36 |
37 |
38 |
39 |
40 |
41 | org.eclipse.jem.workbench.JavaEMFNature
42 | org.maven.ide.eclipse.maven2Nature
43 | org.springframework.ide.eclipse.core.springnature
44 | org.eclipse.jdt.core.javanature
45 | org.eclipse.wst.common.project.facet.core.nature
46 | org.eclipse.wst.common.modulecore.ModuleCoreNature
47 | org.eclipse.wst.jsdt.core.jsNature
48 |
49 |
50 |
--------------------------------------------------------------------------------
/.settings/.jsdtscope:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.settings/com.springsource.server.ide.jdt.core.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | #Tue Mar 17 10:00:21 EDT 2009
2 | eclipse.preferences.version=1
3 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
4 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
6 | org.eclipse.jdt.core.compiler.compliance=1.5
7 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
8 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
9 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
10 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
11 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
12 | org.eclipse.jdt.core.compiler.source=1.5
13 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jst.common.project.facet.core.prefs:
--------------------------------------------------------------------------------
1 | #Tue Mar 17 09:59:19 EDT 2009
2 | classpath.helper/org.eclipse.jdt.launching.JRE_CONTAINER\:\:org.eclipse.jdt.internal.launching.macosx.MacOSXType\:\:JVM\ 1.5.0\ (MacOS\ X\ Default)/owners=jst.java\:5.0
3 | eclipse.preferences.version=1
4 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.wst.common.component:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.wst.common.project.facet.core.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.wst.jsdt.ui.superType.container:
--------------------------------------------------------------------------------
1 | org.eclipse.wst.jsdt.launching.baseBrowserLibrary
--------------------------------------------------------------------------------
/.settings/org.eclipse.wst.jsdt.ui.superType.name:
--------------------------------------------------------------------------------
1 | Window
--------------------------------------------------------------------------------
/.settings/org.eclipse.wst.validation.prefs:
--------------------------------------------------------------------------------
1 | #Fri Jun 06 17:00:12 BST 2008
2 | DELEGATES_PREFERENCE=delegateValidatorListorg.eclipse.wst.wsdl.validation.internal.eclipse.WSDLDelegatingValidator\=org.eclipse.wst.wsdl.validation.internal.eclipse.Validator;org.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator\=org.eclipse.wst.xsd.core.internal.validation.eclipse.Validator;
3 | USER_BUILD_PREFERENCE=enabledBuildValidatorListorg.eclipse.wst.wsdl.validation.internal.eclipse.WSDLDelegatingValidator;org.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator;org.eclipse.jst.jsf.validation.internal.JSPSemanticsValidator;org.eclipse.wst.dtd.core.internal.validation.eclipse.Validator;org.eclipse.wst.xml.core.internal.validation.eclipse.Validator;org.eclipse.wst.common.componentcore.internal.ModuleCoreValidator;org.eclipse.jst.jsf.validation.internal.appconfig.AppConfigValidator;org.eclipse.jst.jsp.core.internal.validation.JSPBatchValidator;org.eclipse.wst.html.internal.validation.HTMLValidator;org.eclipse.jst.jsp.core.internal.validation.JSPContentValidator;org.eclipse.jst.j2ee.internal.classpathdep.ClasspathDependencyValidator;org.eclipse.wst.wsi.ui.internal.WSIMessageValidator;
4 | USER_MANUAL_PREFERENCE=enabledManualValidatorListorg.eclipse.wst.wsdl.validation.internal.eclipse.WSDLDelegatingValidator;org.eclipse.wst.xsd.core.internal.validation.eclipse.XSDDelegatingValidator;org.eclipse.jst.jsf.validation.internal.JSPSemanticsValidator;org.eclipse.wst.dtd.core.internal.validation.eclipse.Validator;org.eclipse.wst.xml.core.internal.validation.eclipse.Validator;org.eclipse.wst.common.componentcore.internal.ModuleCoreValidator;org.eclipse.jst.jsf.validation.internal.appconfig.AppConfigValidator;org.eclipse.jst.jsp.core.internal.validation.JSPBatchValidator;org.eclipse.wst.html.internal.validation.HTMLValidator;org.eclipse.jst.jsp.core.internal.validation.JSPContentValidator;org.eclipse.jst.j2ee.internal.classpathdep.ClasspathDependencyValidator;org.eclipse.wst.wsi.ui.internal.WSIMessageValidator;
5 | USER_PREFERENCE=overrideGlobalPreferencesfalse
6 | eclipse.preferences.version=1
7 |
--------------------------------------------------------------------------------
/.settings/org.maven.ide.eclipse.prefs:
--------------------------------------------------------------------------------
1 | #Tue Mar 17 14:28:16 EDT 2009
2 | activeProfiles=
3 | eclipse.preferences.version=1
4 | fullBuildGoals=process-test-resources
5 | includeModules=false
6 | resolveWorkspaceProjects=true
7 | resourceFilterGoals=process-resources resources\:testResources
8 | skipCompilerPlugin=true
9 | version=1
10 |
--------------------------------------------------------------------------------
/.settings/org.springframework.ide.eclipse.beans.core.prefs:
--------------------------------------------------------------------------------
1 | #Wed Dec 17 01:09:03 EST 2008
2 | eclipse.preferences.version=1
3 | org.springframework.ide.eclipse.beans.core.ignoreMissingNamespaceHandler=false
4 |
--------------------------------------------------------------------------------
/.springBeans:
--------------------------------------------------------------------------------
1 |
2 |
3 | 1
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'http://rubygems.org'
2 |
3 | gem 'rails', '3.0.5'
4 | gem 'jruby-openssl', :require => false
5 |
6 | group :development do
7 | gem 'maruku'
8 | end
9 |
10 | group :test do
11 | gem 'rspec-rails'
12 | gem 'cucumber-rails'
13 | gem 'capybara'
14 | gem 'database_cleaner'
15 | # This until launchy 1.0.0 is released to rubyforge
16 | gem 'spoon', '~> 0.0.1'
17 | gem 'launchy', '1.0.0', :git => 'https://github.com/copiousfreetime/launchy.git', :ref => 'v1.0.0'
18 | end
19 |
20 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GIT
2 | remote: https://github.com/copiousfreetime/launchy.git
3 | revision: f933aa72a3c925ecd15d83bdc510bd50b8f97d4f
4 | ref: v1.0.0
5 | specs:
6 | launchy (1.0.0)
7 |
8 | GEM
9 | remote: http://rubygems.org/
10 | specs:
11 | abstract (1.0.0)
12 | actionmailer (3.0.5)
13 | actionpack (= 3.0.5)
14 | mail (~> 2.2.15)
15 | actionpack (3.0.5)
16 | activemodel (= 3.0.5)
17 | activesupport (= 3.0.5)
18 | builder (~> 2.1.2)
19 | erubis (~> 2.6.6)
20 | i18n (~> 0.4)
21 | rack (~> 1.2.1)
22 | rack-mount (~> 0.6.13)
23 | rack-test (~> 0.5.7)
24 | tzinfo (~> 0.3.23)
25 | activemodel (3.0.5)
26 | activesupport (= 3.0.5)
27 | builder (~> 2.1.2)
28 | i18n (~> 0.4)
29 | activerecord (3.0.5)
30 | activemodel (= 3.0.5)
31 | activesupport (= 3.0.5)
32 | arel (~> 2.0.2)
33 | tzinfo (~> 0.3.23)
34 | activeresource (3.0.5)
35 | activemodel (= 3.0.5)
36 | activesupport (= 3.0.5)
37 | activesupport (3.0.5)
38 | arel (2.0.9)
39 | bouncy-castle-java (1.5.0145.2)
40 | builder (2.1.2)
41 | capybara (0.4.1.1)
42 | celerity (>= 0.7.9)
43 | culerity (>= 0.2.4)
44 | mime-types (>= 1.16)
45 | nokogiri (>= 1.3.3)
46 | rack (>= 1.0.0)
47 | rack-test (>= 0.5.4)
48 | selenium-webdriver (>= 0.0.27)
49 | xpath (~> 0.1.3)
50 | celerity (0.8.9)
51 | childprocess (0.1.6)
52 | ffi (~> 0.6.3)
53 | cucumber (0.10.0)
54 | builder (>= 2.1.2)
55 | diff-lcs (~> 1.1.2)
56 | gherkin (~> 2.3.2)
57 | json (~> 1.4.6)
58 | term-ansicolor (~> 1.0.5)
59 | cucumber-rails (0.3.2)
60 | cucumber (>= 0.8.0)
61 | culerity (0.2.15)
62 | database_cleaner (0.6.3)
63 | diff-lcs (1.1.2)
64 | erubis (2.6.6)
65 | abstract (>= 1.0.0)
66 | ffi (0.6.3-java)
67 | gherkin (2.3.3-java)
68 | json (~> 1.4.6)
69 | i18n (0.5.0)
70 | jruby-openssl (0.7.3)
71 | bouncy-castle-java
72 | json (1.4.6-java)
73 | json_pure (1.5.1)
74 | mail (2.2.15)
75 | activesupport (>= 2.3.6)
76 | i18n (>= 0.4.0)
77 | mime-types (~> 1.16)
78 | treetop (~> 1.4.8)
79 | maruku (0.6.0)
80 | syntax (>= 1.0.0)
81 | mime-types (1.16)
82 | nokogiri (1.4.4.2-java)
83 | weakling (>= 0.0.3)
84 | polyglot (0.3.1)
85 | rack (1.2.2)
86 | rack-mount (0.6.13)
87 | rack (>= 1.0.0)
88 | rack-test (0.5.7)
89 | rack (>= 1.0)
90 | rails (3.0.5)
91 | actionmailer (= 3.0.5)
92 | actionpack (= 3.0.5)
93 | activerecord (= 3.0.5)
94 | activeresource (= 3.0.5)
95 | activesupport (= 3.0.5)
96 | bundler (~> 1.0)
97 | railties (= 3.0.5)
98 | railties (3.0.5)
99 | actionpack (= 3.0.5)
100 | activesupport (= 3.0.5)
101 | rake (>= 0.8.7)
102 | thor (~> 0.14.4)
103 | rake (0.8.7)
104 | rspec (2.5.0)
105 | rspec-core (~> 2.5.0)
106 | rspec-expectations (~> 2.5.0)
107 | rspec-mocks (~> 2.5.0)
108 | rspec-core (2.5.1)
109 | rspec-expectations (2.5.0)
110 | diff-lcs (~> 1.1.2)
111 | rspec-mocks (2.5.0)
112 | rspec-rails (2.5.0)
113 | actionpack (~> 3.0)
114 | activesupport (~> 3.0)
115 | railties (~> 3.0)
116 | rspec (~> 2.5.0)
117 | rubyzip (0.9.4)
118 | selenium-webdriver (0.1.2)
119 | childprocess (~> 0.1.5)
120 | ffi (~> 0.6.3)
121 | json_pure
122 | rubyzip
123 | spoon (0.0.1)
124 | syntax (1.0.0)
125 | term-ansicolor (1.0.5)
126 | thor (0.14.6)
127 | treetop (1.4.9)
128 | polyglot (>= 0.3.1)
129 | tzinfo (0.3.24)
130 | weakling (0.0.4-java)
131 | xpath (0.1.3)
132 | nokogiri (~> 1.3)
133 |
134 | PLATFORMS
135 | java
136 |
137 | DEPENDENCIES
138 | capybara
139 | cucumber-rails
140 | database_cleaner
141 | jruby-openssl
142 | launchy (= 1.0.0)!
143 | maruku
144 | rails (= 3.0.5)
145 | rspec-rails
146 | spoon (~> 0.0.1)
147 |
--------------------------------------------------------------------------------
/README.markdown:
--------------------------------------------------------------------------------
1 | # Refactoring to Rails
2 |
3 | This is a project to demonstrate how you might refactor a legacy Java
4 | project to use Rails.
5 |
6 | The entire repository history is intended to be read start-to-finish.
7 | Each commit message is annotated with the goals of that particular
8 | step and what to expect. If you simply copy or imitate code from a
9 | particular snapshot without understanding how it got there, you're
10 | just practicing [cargo][c1] [cult][c2] [programming][c3] :).
11 |
12 | We're using the Spring-MVC-based "Petclinic" application as the
13 | project subject to the refactoring. We sourced the code of the
14 | application from [this subversion repository][svn].
15 |
16 | There are three versions of the refactoring: `small`, `medium` and
17 | `large`. Each version is stored on a different branch in this
18 | repository. The three branches build upon each other in succession.
19 | The size name of each of the refactorings is an indicator to the
20 | amount of deviation from the original Java-only Spring MVC project.
21 |
22 | ## Small
23 |
24 | The small refactoring is the starting point. We inject JRuby into a
25 | specific endpoint in the webapp without disrupting any of the main
26 | functionality. A couple of XML endpoints are transferred into Ruby
27 | code using Sinatra as the Ruby web framework.
28 |
29 | The techniques used in this section could be used to add a RESTful web
30 | service wrapper to any existing Java web application.
31 |
32 | ## Medium
33 |
34 | The medium refactoring introduces Rails into the web application
35 | without restructuring the project. Rails application sources are
36 | stored under `src/main/webapp` in the place where they would appear in
37 | the application `.war` file. The result is that Rails can drive parts
38 | of the webapp but you don't gain the benefits of Rails development
39 | tooling.
40 |
41 | The main technique of note in this refactoring is the use of a
42 | "Ruby-first Rack filter": Requests to the application are first
43 | handled by Ruby/Rails; if Rails returns an error code, then the
44 | request is reset and passed through. This allows Rails to service some
45 | requests but leave others alone, so that you can layer successively
46 | more Rails requests on top of the existing application.
47 |
48 | ## Large
49 |
50 | The large refactoring begins by creating the Rails application
51 | structure at the root of the project, and continues by moving more and
52 | more functionality from Spring to Rails, until the entire UI layer is
53 | ported from Spring MVC to Rails.
54 |
55 | The main reason for undertaking a project reorganization is to take
56 | advantage of the Rails workflow and tools: the console, generators,
57 | profiling and benchmarking, and so on.
58 |
59 | The large refactoring is completed by adding Warbler configuration,
60 | coming full-circle back to generating a `.war` file of the
61 | application. This shows that you don't have to sacrifice tradidional
62 | Java deployment models while still taking advantage of the "Rails way"
63 | of developing applications.
64 |
65 | # Getting Started
66 |
67 | To play with this code, you should [install JRuby][jruby], and then
68 | install Bundler with `gem install bundler`.
69 |
70 | You will also need MySQL installed. You'll need to do the one-time
71 | step of creating the `petclinic` database. Assuming the default MySQL
72 | development setup of a root user with no password, run `rake
73 | db:create` to create the petclinic database. (Alternately, you can log
74 | into the mysql console manually and load the file
75 | `src/main/resources/db/mysql/initDB.txt`.)
76 |
77 | At any point in the history, you should be able to:
78 |
79 | - `bundle install`: This ensures that you have all the gems needed to
80 | run the project.
81 | - `rake`: This runs the test suite. See also the output of `rake -T`
82 | to see all available tasks.
83 |
84 | [svn]: https://src.springframework.org/svn/spring-samples/petclinic/trunk
85 | [c1]: http://c2.com/cgi/wiki?CargoCultProgramming
86 | [c2]: http://c2.com/cgi/wiki?CopyAndPasteProgramming
87 | [c3]: http://c2.com/cgi/wiki?VoodooChickenCoding
88 | [jruby]: http://jruby.org/getting-started
89 |
90 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # Add your own tasks in files placed in lib/tasks ending in .rake,
2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3 |
4 | require File.expand_path('../config/application', __FILE__)
5 | require 'rake'
6 |
7 | SpringPetclinic::Application.load_tasks
8 |
--------------------------------------------------------------------------------
/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | protect_from_forgery
3 |
4 | require 'java_ext'
5 | require 'spring_helpers'
6 | include Spring
7 | end
8 |
--------------------------------------------------------------------------------
/app/controllers/owners_controller.rb:
--------------------------------------------------------------------------------
1 | class OwnersController < ApplicationController
2 | before_filter :load_owner, :only => [:edit, :show, :update]
3 |
4 | def index
5 | name = params[:lastName] || ''
6 | @owners = Owner.find_by_name(name)
7 | if @owners.size < 1
8 | flash[:notice] = "#{params[:lastName]} #{t(:notFound)}"
9 | render "search"
10 | elsif @owners.size == 1
11 | redirect_to owner_path(@owners.first)
12 | end
13 | end
14 |
15 | def search
16 | end
17 |
18 | def show
19 | end
20 |
21 | def edit
22 | end
23 |
24 | def new
25 | @owner = Owner.new
26 | end
27 |
28 | def create
29 | @owner = Owner.new
30 | create_or_update("new")
31 | end
32 |
33 | def update
34 | create_or_update("edit")
35 | end
36 |
37 | private
38 | def load_owner
39 | unless (@owner ||= Owner.load params[:id])
40 | flash[:notice] = t(:notFound)
41 | redirect_to owners_path
42 | end
43 | end
44 |
45 | def create_or_update(template)
46 | @owner.update_attributes params[:owner]
47 | if @owner.valid?
48 | @owner.save
49 | redirect_to owner_path(@owner)
50 | else
51 | render template
52 | end
53 | end
54 | end
55 |
--------------------------------------------------------------------------------
/app/controllers/pets_controller.rb:
--------------------------------------------------------------------------------
1 | class PetsController < ApplicationController
2 | before_filter :load_owner
3 | before_filter :new_pet, :only => [:new, :create]
4 | before_filter :load_pet, :only => [:show, :edit, :update, :destroy]
5 |
6 | def new
7 | @types = clinic.pet_types
8 | end
9 |
10 | def show
11 | end
12 |
13 | def edit
14 | @types = clinic.pet_types
15 | end
16 |
17 | def create
18 | create_or_update('new')
19 | end
20 |
21 | def update
22 | create_or_update('edit')
23 | end
24 |
25 | def destroy
26 | @pet.destroy
27 | redirect_to owner_path(params[:owner_id])
28 | end
29 |
30 | private
31 | def load_owner
32 | unless (@owner ||= Owner.load params[:owner_id].to_i)
33 | flash[:notice] = t(:notFound)
34 | redirect_to owners_path
35 | end
36 | end
37 |
38 | def load_pet
39 | @pet = Pet.load(params[:id])
40 | end
41 |
42 | def new_pet
43 | @pet = Pet.new.tap {|pet| pet.owner = @owner }
44 | end
45 |
46 | def create_or_update(template)
47 | @pet.update_attributes params[:pet]
48 | if @pet.valid?
49 | @pet.save
50 | redirect_to owner_path(@owner)
51 | else
52 | render template
53 | end
54 | end
55 | end
56 |
--------------------------------------------------------------------------------
/app/controllers/vets_controller.rb:
--------------------------------------------------------------------------------
1 | class VetsController < ApplicationController
2 | def index
3 | @vets = Vet.all
4 | respond_to do |format|
5 | format.html
6 | format.xml do
7 | render :xml => @vets.to_a.to_xml
8 | end
9 | format.json do
10 | render :json => @vets.to_a.to_json
11 | end
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/app/controllers/visits_controller.rb:
--------------------------------------------------------------------------------
1 | class VisitsController < ApplicationController
2 | before_filter :load_pet
3 | before_filter :new_visit, :only => [:new, :create]
4 | before_filter :load_visit, :only => [:show, :edit, :update]
5 |
6 | def index
7 | @visits = @pet.visits
8 | respond_to do |format|
9 | format.atom
10 | end
11 | end
12 |
13 | def new
14 | end
15 |
16 | def edit
17 | end
18 |
19 | def create
20 | create_or_update('new')
21 | end
22 |
23 | def update
24 | create_or_update('edit')
25 | end
26 |
27 | private
28 | def load_pet
29 | @pet = Pet.load(params[:pet_id])
30 | end
31 |
32 | def new_visit
33 | @visit = Visit.new.tap {|v| v.pet = @pet }
34 | end
35 |
36 | def load_visit
37 | unless (@visit = @pet.visits.detect {|v| v.id == params[:id].to_i})
38 | flash[:notice] = t(:notFound)
39 | redirect_to owner_path(@pet.owner)
40 | end
41 | end
42 |
43 | def create_or_update(template)
44 | @visit.update_attributes params[:visit]
45 | if @visit.valid?
46 | @visit.save
47 | redirect_to owner_path(@pet.owner)
48 | else
49 | render template
50 | end
51 | end
52 | end
53 |
--------------------------------------------------------------------------------
/app/controllers/welcome_controller.rb:
--------------------------------------------------------------------------------
1 | class WelcomeController < ApplicationController
2 | def index
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/models/owner.rb:
--------------------------------------------------------------------------------
1 | java_import org.springframework.samples.petclinic.Owner
2 |
3 | class Owner
4 | extend ActiveModel::Naming
5 | include ActiveModel::Validations
6 | include ActiveModel::Conversion
7 | include Spring
8 |
9 | Pet # dev-mode: ensure child models are decorated
10 |
11 | validates_presence_of :first_name, :last_name, :address, :city, :telephone
12 | validates_format_of :telephone, :with => /[-0-9.+ ]+/, :message => "can only have numbers, punctuation, or spaces"
13 |
14 | def self.find_by_name(name)
15 | clinic.findOwners(name)
16 | end
17 |
18 | def self.load(id)
19 | clinic.loadOwner(id.to_i)
20 | end
21 |
22 | def save
23 | clinic.storeOwner(self)
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/app/models/pet.rb:
--------------------------------------------------------------------------------
1 | java_import org.springframework.samples.petclinic.Pet
2 |
3 | class Pet
4 | extend ActiveModel::Naming
5 | include ActiveModel::Validations
6 | include ActiveModel::Conversion
7 | include Spring
8 |
9 | Owner; Visit ; PetType # dev-mode: ensure child models are decorated
10 |
11 | def birth_date
12 | getBirthDate && getBirthDate.to_date
13 | end
14 |
15 | def birth_date=(date)
16 | setBirthDate java.util.Date.from_date(date)
17 | end
18 |
19 | def type=(t)
20 | setType PetType === t ? t : PetType.load(t.to_i)
21 | end
22 |
23 | def self.load(id)
24 | clinic.loadPet(id.to_i)
25 | end
26 |
27 | def save
28 | clinic.storePet(self)
29 | end
30 |
31 | def destroy
32 | clinic.deletePet(id)
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/app/models/pet_type.rb:
--------------------------------------------------------------------------------
1 | java_import org.springframework.samples.petclinic.PetType
2 |
3 | class PetType
4 | extend ActiveModel::Naming
5 | include ActiveModel::Validations
6 | include ActiveModel::Conversion
7 | include Spring
8 |
9 | def self.load(id)
10 | clinic.getPetTypes.detect {|pt| pt.id == id.to_i }
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/app/models/vet.rb:
--------------------------------------------------------------------------------
1 | java_import org.springframework.samples.petclinic.Vet
2 |
3 | class Vet
4 | include ActiveModel::Serializers::Xml
5 | include ActiveModel::Serializers::JSON
6 | include Spring
7 |
8 | def serializable_hash(*)
9 | {
10 | "id" => id,
11 | "first_name" => first_name, "last_name" => last_name,
12 | "specialties" => specialties.map{|s| s.name}.join(', '),
13 | "nr_of_specialties" => nr_of_specialties
14 | }
15 | end
16 | alias attributes serializable_hash
17 |
18 | def self.all
19 | clinic.getVets
20 | end
21 | end
22 |
--------------------------------------------------------------------------------
/app/models/visit.rb:
--------------------------------------------------------------------------------
1 | java_import org.springframework.samples.petclinic.Visit
2 |
3 | class Visit
4 | extend ActiveModel::Naming
5 | include ActiveModel::Validations
6 | include ActiveModel::Conversion
7 | include Spring
8 |
9 | def date
10 | getDate.to_date
11 | end
12 |
13 | def date=(date)
14 | setDate java.util.Date.from_date(date)
15 | end
16 |
17 | def save
18 | clinic.storeVisit(self)
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | " element for 'petclinic' (see below). You can
100 | alternatively deploy the WAR including "META-INF/context.xml" from this
101 | sample application's "src/main/webapp" directory, in which case you
102 | will need to uncomment the Loader element in that file to enable the
103 | use of the TomcatInstrumentableClassLoader.
104 |
105 |
106 |
107 |
108 | ...
109 |
110 |
--------------------------------------------------------------------------------
/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
17 |
18 |
19 |
20 |
21 |
22 |
The page you were looking for doesn't exist.
23 |
You may have mistyped the address or the page may have moved.
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The change you wanted was rejected (422)
5 |
17 |
18 |
19 |
20 |
21 |
22 |
The change you wanted was rejected.
23 |
Maybe you tried to change something you didn't have access to.
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
17 |
18 |
19 |
20 |
21 |
22 |
We're sorry, but something went wrong.
23 |
We've been notified about this issue and we'll take a look at it shortly.
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nicksieger/refactoring-to-rails/6fa63e5e35b3ab054f8f3008689b44d267387db7/public/favicon.ico
--------------------------------------------------------------------------------
/public/images/banner-graphic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nicksieger/refactoring-to-rails/6fa63e5e35b3ab054f8f3008689b44d267387db7/public/images/banner-graphic.png
--------------------------------------------------------------------------------
/public/images/bullet-arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nicksieger/refactoring-to-rails/6fa63e5e35b3ab054f8f3008689b44d267387db7/public/images/bullet-arrow.png
--------------------------------------------------------------------------------
/public/images/pets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nicksieger/refactoring-to-rails/6fa63e5e35b3ab054f8f3008689b44d267387db7/public/images/pets.png
--------------------------------------------------------------------------------
/public/images/rails-banner-graphic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nicksieger/refactoring-to-rails/6fa63e5e35b3ab054f8f3008689b44d267387db7/public/images/rails-banner-graphic.png
--------------------------------------------------------------------------------
/public/images/rails.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nicksieger/refactoring-to-rails/6fa63e5e35b3ab054f8f3008689b44d267387db7/public/images/rails.png
--------------------------------------------------------------------------------
/public/images/springsource-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nicksieger/refactoring-to-rails/6fa63e5e35b3ab054f8f3008689b44d267387db7/public/images/springsource-logo.png
--------------------------------------------------------------------------------
/public/images/submit-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nicksieger/refactoring-to-rails/6fa63e5e35b3ab054f8f3008689b44d267387db7/public/images/submit-bg.png
--------------------------------------------------------------------------------
/public/javascripts/application.js:
--------------------------------------------------------------------------------
1 | // Place your application-specific JavaScript functions and classes here
2 | // This file is automatically included by javascript_include_tag :defaults
3 |
--------------------------------------------------------------------------------
/public/javascripts/rails.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | // Technique from Juriy Zaytsev
3 | // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
4 | function isEventSupported(eventName) {
5 | var el = document.createElement('div');
6 | eventName = 'on' + eventName;
7 | var isSupported = (eventName in el);
8 | if (!isSupported) {
9 | el.setAttribute(eventName, 'return;');
10 | isSupported = typeof el[eventName] == 'function';
11 | }
12 | el = null;
13 | return isSupported;
14 | }
15 |
16 | function isForm(element) {
17 | return Object.isElement(element) && element.nodeName.toUpperCase() == 'FORM'
18 | }
19 |
20 | function isInput(element) {
21 | if (Object.isElement(element)) {
22 | var name = element.nodeName.toUpperCase()
23 | return name == 'INPUT' || name == 'SELECT' || name == 'TEXTAREA'
24 | }
25 | else return false
26 | }
27 |
28 | var submitBubbles = isEventSupported('submit'),
29 | changeBubbles = isEventSupported('change')
30 |
31 | if (!submitBubbles || !changeBubbles) {
32 | // augment the Event.Handler class to observe custom events when needed
33 | Event.Handler.prototype.initialize = Event.Handler.prototype.initialize.wrap(
34 | function(init, element, eventName, selector, callback) {
35 | init(element, eventName, selector, callback)
36 | // is the handler being attached to an element that doesn't support this event?
37 | if ( (!submitBubbles && this.eventName == 'submit' && !isForm(this.element)) ||
38 | (!changeBubbles && this.eventName == 'change' && !isInput(this.element)) ) {
39 | // "submit" => "emulated:submit"
40 | this.eventName = 'emulated:' + this.eventName
41 | }
42 | }
43 | )
44 | }
45 |
46 | if (!submitBubbles) {
47 | // discover forms on the page by observing focus events which always bubble
48 | document.on('focusin', 'form', function(focusEvent, form) {
49 | // special handler for the real "submit" event (one-time operation)
50 | if (!form.retrieve('emulated:submit')) {
51 | form.on('submit', function(submitEvent) {
52 | var emulated = form.fire('emulated:submit', submitEvent, true)
53 | // if custom event received preventDefault, cancel the real one too
54 | if (emulated.returnValue === false) submitEvent.preventDefault()
55 | })
56 | form.store('emulated:submit', true)
57 | }
58 | })
59 | }
60 |
61 | if (!changeBubbles) {
62 | // discover form inputs on the page
63 | document.on('focusin', 'input, select, texarea', function(focusEvent, input) {
64 | // special handler for real "change" events
65 | if (!input.retrieve('emulated:change')) {
66 | input.on('change', function(changeEvent) {
67 | input.fire('emulated:change', changeEvent, true)
68 | })
69 | input.store('emulated:change', true)
70 | }
71 | })
72 | }
73 |
74 | function handleRemote(element) {
75 | var method, url, params;
76 |
77 | var event = element.fire("ajax:before");
78 | if (event.stopped) return false;
79 |
80 | if (element.tagName.toLowerCase() === 'form') {
81 | method = element.readAttribute('method') || 'post';
82 | url = element.readAttribute('action');
83 | params = element.serialize();
84 | } else {
85 | method = element.readAttribute('data-method') || 'get';
86 | url = element.readAttribute('href');
87 | params = {};
88 | }
89 |
90 | new Ajax.Request(url, {
91 | method: method,
92 | parameters: params,
93 | evalScripts: true,
94 |
95 | onComplete: function(request) { element.fire("ajax:complete", request); },
96 | onSuccess: function(request) { element.fire("ajax:success", request); },
97 | onFailure: function(request) { element.fire("ajax:failure", request); }
98 | });
99 |
100 | element.fire("ajax:after");
101 | }
102 |
103 | function handleMethod(element) {
104 | var method = element.readAttribute('data-method'),
105 | url = element.readAttribute('href'),
106 | csrf_param = $$('meta[name=csrf-param]')[0],
107 | csrf_token = $$('meta[name=csrf-token]')[0];
108 |
109 | var form = new Element('form', { method: "POST", action: url, style: "display: none;" });
110 | element.parentNode.insert(form);
111 |
112 | if (method !== 'post') {
113 | var field = new Element('input', { type: 'hidden', name: '_method', value: method });
114 | form.insert(field);
115 | }
116 |
117 | if (csrf_param) {
118 | var param = csrf_param.readAttribute('content'),
119 | token = csrf_token.readAttribute('content'),
120 | field = new Element('input', { type: 'hidden', name: param, value: token });
121 | form.insert(field);
122 | }
123 |
124 | form.submit();
125 | }
126 |
127 |
128 | document.on("click", "*[data-confirm]", function(event, element) {
129 | var message = element.readAttribute('data-confirm');
130 | if (!confirm(message)) event.stop();
131 | });
132 |
133 | document.on("click", "a[data-remote]", function(event, element) {
134 | if (event.stopped) return;
135 | handleRemote(element);
136 | event.stop();
137 | });
138 |
139 | document.on("click", "a[data-method]", function(event, element) {
140 | if (event.stopped) return;
141 | handleMethod(element);
142 | event.stop();
143 | });
144 |
145 | document.on("submit", function(event) {
146 | var element = event.findElement(),
147 | message = element.readAttribute('data-confirm');
148 | if (message && !confirm(message)) {
149 | event.stop();
150 | return false;
151 | }
152 |
153 | var inputs = element.select("input[type=submit][data-disable-with]");
154 | inputs.each(function(input) {
155 | input.disabled = true;
156 | input.writeAttribute('data-original-value', input.value);
157 | input.value = input.readAttribute('data-disable-with');
158 | });
159 |
160 | var element = event.findElement("form[data-remote]");
161 | if (element) {
162 | handleRemote(element);
163 | event.stop();
164 | }
165 | });
166 |
167 | document.on("ajax:after", "form", function(event, element) {
168 | var inputs = element.select("input[type=submit][disabled=true][data-disable-with]");
169 | inputs.each(function(input) {
170 | input.value = input.readAttribute('data-original-value');
171 | input.removeAttribute('data-original-value');
172 | input.disabled = false;
173 | });
174 | });
175 |
176 | Ajax.Responders.register({
177 | onCreate: function(request) {
178 | var csrf_meta_tag = $$('meta[name=csrf-token]')[0];
179 |
180 | if (csrf_meta_tag) {
181 | var header = 'X-CSRF-Token',
182 | token = csrf_meta_tag.readAttribute('content');
183 |
184 | if (!request.options.requestHeaders) {
185 | request.options.requestHeaders = {};
186 | }
187 | request.options.requestHeaders[header] = token;
188 | }
189 | }
190 | });
191 | })();
192 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
2 | #
3 | # To ban all spiders from the entire site uncomment the next two lines:
4 | # User-Agent: *
5 | # Disallow: /
6 |
--------------------------------------------------------------------------------
/public/stylesheets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nicksieger/refactoring-to-rails/6fa63e5e35b3ab054f8f3008689b44d267387db7/public/stylesheets/.gitkeep
--------------------------------------------------------------------------------
/public/stylesheets/petclinic.css:
--------------------------------------------------------------------------------
1 | /* main elements */
2 |
3 | body,div,td {
4 | font-family: Arial, Helvetica, sans-serif;
5 | font-size: 12px;
6 | color: #666;
7 | }
8 |
9 | body {
10 | background-color: #fff;
11 | background-image: url(../images/rails-banner-graphic.png);
12 | background-position: top center;
13 | background-repeat: no-repeat;
14 | text-align: center;
15 | min-width: 600px;
16 | margin-top: 60px;
17 | margin-left: auto;
18 | margin-right: auto;
19 | }
20 |
21 | div {
22 | margin: 5px 25px 5px 25px;
23 | text-align: left;
24 | }
25 |
26 | /* header and footer elements */
27 |
28 | #main {
29 | margin:0 auto;
30 | position:relative;
31 | top: 35px;
32 | left:0px;
33 | width:560px;
34 | text-align:left;
35 | }
36 |
37 | .footer {
38 | background:#fff;
39 | border:none;
40 | margin-top:20px;
41 | border-top:1px solid #999999;
42 | width:100%;
43 | }
44 |
45 | .footer td {color:#999999;}
46 |
47 | .footer a:link {color: #7db223;}
48 |
49 |
50 | /* text styles */
51 |
52 | h1,h2,h3 {
53 | font-family: Helvetica, sans-serif;
54 | color: #7db223;
55 | }
56 |
57 | h1 {
58 | font-size: 20px;
59 | line-height: 26px;
60 | }
61 |
62 | h2 {
63 | font-size: 18px;
64 | line-height: 24px;
65 | }
66 |
67 | h3 {
68 | font-size: 15px;
69 | line-height: 21px;
70 | color:#555;
71 | }
72 |
73 | h4 {
74 | font-size: 14px;
75 | line-height: 20px;
76 | }
77 |
78 | .errors {
79 | color: red;
80 | font-weight: bold;
81 | }
82 |
83 | a {
84 | text-decoration: underline;
85 | font-size: 13px;
86 | }
87 |
88 | a:link {
89 | color: #7db223;
90 | }
91 |
92 | a:hover {
93 | color: #456314;
94 | }
95 |
96 | a:active {
97 | color: #7db223;
98 | }
99 |
100 | a:visited {
101 | color: #7db223;
102 | }
103 |
104 | ul {
105 | list-style: disc url(../images/bullet-arrow.png);
106 | }
107 |
108 | li {
109 | padding-top: 5px;
110 | text-align: left;
111 | }
112 |
113 | li ul {
114 | list-style: square url(../images/bullet-arrow.png);
115 | }
116 |
117 | li ul li ul {
118 | list-style: circle none;
119 | }
120 |
121 | /* table elements */
122 |
123 | table {
124 | background: #d6e2c3;
125 | margin: 3px 0 0 0;
126 | border: 4px solid #d6e2c3;
127 | border-collapse: collapse;
128 | }
129 |
130 | table table {
131 | margin: -5px 0;
132 | border: 0px solid #e0e7d3;
133 | width: 100%;
134 | }
135 |
136 | table td,table th {
137 | padding: 8px;
138 | }
139 |
140 | table th {
141 | font-size: 12px;
142 | text-align: left;
143 | font-weight: bold;
144 | }
145 |
146 | table thead {
147 | font-weight: bold;
148 | font-style: italic;
149 | background-color: #c2ceaf;
150 | }
151 |
152 | table a:link {color: #303030;}
153 |
154 | caption {
155 | caption-side: top;
156 | width: auto;
157 | text-align: left;
158 | font-size: 12px;
159 | color: #848f73;
160 | padding-bottom: 4px;
161 | }
162 |
163 | fieldset {
164 | background: #e0e7d3;
165 | padding: 8px;
166 | padding-bottom: 22px;
167 | border: none;
168 | width: 560px;
169 | }
170 |
171 | fieldset label {
172 | width: 70px;
173 | float: left;
174 | margin-top: 1.7em;
175 | margin-left: 20px;
176 | }
177 |
178 | fieldset textfield {
179 | margin: 3px;
180 | height: 20px;
181 | background: #e0e7d3;
182 | }
183 |
184 | fieldset textarea {
185 | margin: 3px;
186 | height: 165px;
187 | background: #e0e7d3;
188 | }
189 |
190 | fieldset input {
191 | margin: 3px;
192 | height: 20px;
193 | background: #e0e7d3;
194 | }
195 |
196 | fieldset table {
197 | width: 100%;
198 | }
199 |
200 | fieldset th {
201 | padding-left: 25px;
202 | }
203 |
204 | .table-buttons {
205 | background-color:#fff;
206 | border:none;
207 | }
208 |
209 | .table-buttons td {
210 | border:none;
211 | }
212 |
213 | .submit input {
214 | background:url(../images/submit-bg.png) repeat-x;
215 | border: 2px outset #d7b9c9;
216 | color:#383838;
217 | padding:2px 10px;
218 | font-size:11px;
219 | text-transform:uppercase;
220 | font-weight:bold;
221 | }
222 |
223 | .updated {
224 | background:#ecf1e5;
225 | font-size:11px;
226 | margin-left:2px;
227 | border:4px solid #ecf1e5;
228 | }
229 |
230 | .updated td {
231 | padding:2px 8px;
232 | font-size:11px;
233 | color:#888888;
234 | }
235 |
--------------------------------------------------------------------------------
/script/cucumber:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | vendored_cucumber_bin = Dir["#{File.dirname(__FILE__)}/../vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
4 | if vendored_cucumber_bin
5 | load File.expand_path(vendored_cucumber_bin)
6 | else
7 | require 'rubygems' unless ENV['NO_RUBYGEMS']
8 | require 'cucumber'
9 | load Cucumber::BINARY
10 | end
11 |
--------------------------------------------------------------------------------
/script/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env jruby
2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3 |
4 | APP_PATH = File.expand_path('../../config/application', __FILE__)
5 | require File.expand_path('../../config/boot', __FILE__)
6 | require 'rails/commands'
7 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/BaseEntity.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic;
2 |
3 | /**
4 | * Simple JavaBean domain object with an id property.
5 | * Used as a base class for objects needing this property.
6 | *
7 | * @author Ken Krebs
8 | * @author Juergen Hoeller
9 | */
10 | public class BaseEntity {
11 |
12 | private Integer id;
13 |
14 |
15 | public void setId(Integer id) {
16 | this.id = id;
17 | }
18 |
19 | public Integer getId() {
20 | return id;
21 | }
22 |
23 | public boolean isNew() {
24 | return (this.id == null);
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/Clinic.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic;
2 |
3 | import java.util.Collection;
4 |
5 | import org.springframework.dao.DataAccessException;
6 |
7 | /**
8 | * The high-level PetClinic business interface.
9 | *
10 | * This is basically a data access object.
11 | * PetClinic doesn't have a dedicated business facade.
12 | *
13 | * @author Ken Krebs
14 | * @author Juergen Hoeller
15 | * @author Sam Brannen
16 | */
17 | public interface Clinic {
18 |
19 | /**
20 | * Retrieve all Vet
s from the data store.
21 | * @return a Collection
of Vet
s
22 | */
23 | Collection getVets() throws DataAccessException;
24 |
25 | /**
26 | * Retrieve all PetType
s from the data store.
27 | * @return a Collection
of PetType
s
28 | */
29 | Collection getPetTypes() throws DataAccessException;
30 |
31 | /**
32 | * Retrieve Owner
s from the data store by last name,
33 | * returning all owners whose last name starts with the given name.
34 | * @param lastName Value to search for
35 | * @return a Collection
of matching Owner
s
36 | * (or an empty Collection
if none found)
37 | */
38 | Collection findOwners(String lastName) throws DataAccessException;
39 |
40 | /**
41 | * Retrieve an Owner
from the data store by id.
42 | * @param id the id to search for
43 | * @return the Owner
if found
44 | * @throws org.springframework.dao.DataRetrievalFailureException if not found
45 | */
46 | Owner loadOwner(int id) throws DataAccessException;
47 |
48 | /**
49 | * Retrieve a Pet
from the data store by id.
50 | * @param id the id to search for
51 | * @return the Pet
if found
52 | * @throws org.springframework.dao.DataRetrievalFailureException if not found
53 | */
54 | Pet loadPet(int id) throws DataAccessException;
55 |
56 | /**
57 | * Save an Owner
to the data store, either inserting or updating it.
58 | * @param owner the Owner
to save
59 | * @see BaseEntity#isNew
60 | */
61 | void storeOwner(Owner owner) throws DataAccessException;
62 |
63 | /**
64 | * Save a Pet
to the data store, either inserting or updating it.
65 | * @param pet the Pet
to save
66 | * @see BaseEntity#isNew
67 | */
68 | void storePet(Pet pet) throws DataAccessException;
69 |
70 | /**
71 | * Save a Visit
to the data store, either inserting or updating it.
72 | * @param visit the Visit
to save
73 | * @see BaseEntity#isNew
74 | */
75 | void storeVisit(Visit visit) throws DataAccessException;
76 |
77 | /**
78 | * Deletes a Pet
from the data store.
79 | */
80 | void deletePet(int id) throws DataAccessException;
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/NamedEntity.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic;
2 |
3 | /**
4 | * Simple JavaBean domain object adds a name property to BaseEntity
.
5 | * Used as a base class for objects needing these properties.
6 | *
7 | * @author Ken Krebs
8 | * @author Juergen Hoeller
9 | */
10 | public class NamedEntity extends BaseEntity {
11 |
12 | private String name;
13 |
14 |
15 | public void setName(String name) {
16 | this.name = name;
17 | }
18 |
19 | public String getName() {
20 | return this.name;
21 | }
22 |
23 | @Override
24 | public String toString() {
25 | return this.getName();
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/Owner.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collections;
5 | import java.util.HashSet;
6 | import java.util.List;
7 | import java.util.Set;
8 |
9 | import org.springframework.beans.support.MutableSortDefinition;
10 | import org.springframework.beans.support.PropertyComparator;
11 | import org.springframework.core.style.ToStringCreator;
12 |
13 | /**
14 | * Simple JavaBean domain object representing an owner.
15 | *
16 | * @author Ken Krebs
17 | * @author Juergen Hoeller
18 | * @author Sam Brannen
19 | */
20 | public class Owner extends Person {
21 |
22 | private String address;
23 |
24 | private String city;
25 |
26 | private String telephone;
27 |
28 | private Set pets;
29 |
30 |
31 | public String getAddress() {
32 | return this.address;
33 | }
34 |
35 | public void setAddress(String address) {
36 | this.address = address;
37 | }
38 |
39 | public String getCity() {
40 | return this.city;
41 | }
42 |
43 | public void setCity(String city) {
44 | this.city = city;
45 | }
46 |
47 | public String getTelephone() {
48 | return this.telephone;
49 | }
50 |
51 | public void setTelephone(String telephone) {
52 | this.telephone = telephone;
53 | }
54 |
55 | protected void setPetsInternal(Set pets) {
56 | this.pets = pets;
57 | }
58 |
59 | protected Set getPetsInternal() {
60 | if (this.pets == null) {
61 | this.pets = new HashSet();
62 | }
63 | return this.pets;
64 | }
65 |
66 | public List getPets() {
67 | List sortedPets = new ArrayList(getPetsInternal());
68 | PropertyComparator.sort(sortedPets, new MutableSortDefinition("name", true, true));
69 | return Collections.unmodifiableList(sortedPets);
70 | }
71 |
72 | public void addPet(Pet pet) {
73 | getPetsInternal().add(pet);
74 | pet.setOwner(this);
75 | }
76 |
77 | /**
78 | * Return the Pet with the given name, or null if none found for this Owner.
79 | *
80 | * @param name to test
81 | * @return true if pet name is already in use
82 | */
83 | public Pet getPet(String name) {
84 | return getPet(name, false);
85 | }
86 |
87 | /**
88 | * Return the Pet with the given name, or null if none found for this Owner.
89 | *
90 | * @param name to test
91 | * @return true if pet name is already in use
92 | */
93 | public Pet getPet(String name, boolean ignoreNew) {
94 | name = name.toLowerCase();
95 | for (Pet pet : getPetsInternal()) {
96 | if (!ignoreNew || !pet.isNew()) {
97 | String compName = pet.getName();
98 | compName = compName.toLowerCase();
99 | if (compName.equals(name)) {
100 | return pet;
101 | }
102 | }
103 | }
104 | return null;
105 | }
106 |
107 | @Override
108 | public String toString() {
109 | return new ToStringCreator(this)
110 |
111 | .append("id", this.getId())
112 |
113 | .append("new", this.isNew())
114 |
115 | .append("lastName", this.getLastName())
116 |
117 | .append("firstName", this.getFirstName())
118 |
119 | .append("address", this.address)
120 |
121 | .append("city", this.city)
122 |
123 | .append("telephone", this.telephone)
124 |
125 | .toString();
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/Person.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic;
2 |
3 | /**
4 | * Simple JavaBean domain object representing an person.
5 | *
6 | * @author Ken Krebs
7 | */
8 | public class Person extends BaseEntity {
9 |
10 | private String firstName;
11 |
12 | private String lastName;
13 |
14 | public String getFirstName() {
15 | return this.firstName;
16 | }
17 |
18 | public void setFirstName(String firstName) {
19 | this.firstName = firstName;
20 | }
21 |
22 | public String getLastName() {
23 | return this.lastName;
24 | }
25 |
26 | public void setLastName(String lastName) {
27 | this.lastName = lastName;
28 | }
29 |
30 |
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/Pet.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collections;
5 | import java.util.Date;
6 | import java.util.HashSet;
7 | import java.util.List;
8 | import java.util.Set;
9 |
10 | import org.springframework.beans.support.MutableSortDefinition;
11 | import org.springframework.beans.support.PropertyComparator;
12 |
13 | /**
14 | * Simple JavaBean business object representing a pet.
15 | *
16 | * @author Ken Krebs
17 | * @author Juergen Hoeller
18 | * @author Sam Brannen
19 | */
20 | public class Pet extends NamedEntity {
21 |
22 | private Date birthDate;
23 |
24 | private PetType type;
25 |
26 | private Owner owner;
27 |
28 | private Set visits;
29 |
30 |
31 | public void setBirthDate(Date birthDate) {
32 | this.birthDate = birthDate;
33 | }
34 |
35 | public Date getBirthDate() {
36 | return this.birthDate;
37 | }
38 |
39 | public void setType(PetType type) {
40 | this.type = type;
41 | }
42 |
43 | public PetType getType() {
44 | return this.type;
45 | }
46 |
47 | protected void setOwner(Owner owner) {
48 | this.owner = owner;
49 | }
50 |
51 | public Owner getOwner() {
52 | return this.owner;
53 | }
54 |
55 | protected void setVisitsInternal(Set visits) {
56 | this.visits = visits;
57 | }
58 |
59 | protected Set getVisitsInternal() {
60 | if (this.visits == null) {
61 | this.visits = new HashSet();
62 | }
63 | return this.visits;
64 | }
65 |
66 | public List getVisits() {
67 | List sortedVisits = new ArrayList(getVisitsInternal());
68 | PropertyComparator.sort(sortedVisits, new MutableSortDefinition("date", false, false));
69 | return Collections.unmodifiableList(sortedVisits);
70 | }
71 |
72 | public void addVisit(Visit visit) {
73 | getVisitsInternal().add(visit);
74 | visit.setPet(this);
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/PetType.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic;
2 |
3 | /**
4 | * @author Juergen Hoeller
5 | */
6 | public class PetType extends NamedEntity {
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/Specialty.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic;
2 |
3 | /**
4 | * Models a {@link Vet Vet's} specialty (for example, dentistry).
5 | *
6 | * @author Juergen Hoeller
7 | */
8 | public class Specialty extends NamedEntity {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/Vet.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collections;
5 | import java.util.HashSet;
6 | import java.util.List;
7 | import java.util.Set;
8 | import javax.xml.bind.annotation.XmlElement;
9 |
10 | import org.springframework.beans.support.MutableSortDefinition;
11 | import org.springframework.beans.support.PropertyComparator;
12 |
13 | /**
14 | * Simple JavaBean domain object representing a veterinarian.
15 | *
16 | * @author Ken Krebs
17 | * @author Juergen Hoeller
18 | * @author Sam Brannen
19 | * @author Arjen Poutsma
20 | */
21 | public class Vet extends Person {
22 |
23 | private Set specialties;
24 |
25 |
26 | protected void setSpecialtiesInternal(Set specialties) {
27 | this.specialties = specialties;
28 | }
29 |
30 | protected Set getSpecialtiesInternal() {
31 | if (this.specialties == null) {
32 | this.specialties = new HashSet();
33 | }
34 | return this.specialties;
35 | }
36 |
37 | @XmlElement
38 | public List getSpecialties() {
39 | List sortedSpecs = new ArrayList(getSpecialtiesInternal());
40 | PropertyComparator.sort(sortedSpecs, new MutableSortDefinition("name", true, true));
41 | return Collections.unmodifiableList(sortedSpecs);
42 | }
43 |
44 | public int getNrOfSpecialties() {
45 | return getSpecialtiesInternal().size();
46 | }
47 |
48 | public void addSpecialty(Specialty specialty) {
49 | getSpecialtiesInternal().add(specialty);
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/Vets.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2002-2009 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.samples.petclinic;
18 |
19 | import java.util.ArrayList;
20 | import java.util.List;
21 | import javax.xml.bind.annotation.XmlElement;
22 | import javax.xml.bind.annotation.XmlRootElement;
23 |
24 | /**
25 | * Simple JavaBean domain object representing a list of veterinarians. Mostly here to be used for the 'vets'
26 | * {@link org.springframework.web.servlet.view.xml.MarshallingView}.
27 | *
28 | * @author Arjen Poutsma
29 | */
30 | @XmlRootElement
31 | public class Vets {
32 |
33 | private List vets;
34 |
35 | @XmlElement
36 | public List getVetList() {
37 | if (vets == null) {
38 | vets = new ArrayList();
39 | }
40 | return vets;
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/Visit.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic;
2 |
3 | import java.util.Date;
4 |
5 | /**
6 | * Simple JavaBean domain object representing a visit.
7 | *
8 | * @author Ken Krebs
9 | */
10 | public class Visit extends BaseEntity {
11 |
12 | /** Holds value of property date. */
13 | private Date date;
14 |
15 | /** Holds value of property description. */
16 | private String description;
17 |
18 | /** Holds value of property pet. */
19 | private Pet pet;
20 |
21 |
22 | /** Creates a new instance of Visit for the current date */
23 | public Visit() {
24 | this.date = new Date();
25 | }
26 |
27 |
28 | /** Getter for property date.
29 | * @return Value of property date.
30 | */
31 | public Date getDate() {
32 | return this.date;
33 | }
34 |
35 | /** Setter for property date.
36 | * @param date New value of property date.
37 | */
38 | public void setDate(Date date) {
39 | this.date = date;
40 | }
41 |
42 | /** Getter for property description.
43 | * @return Value of property description.
44 | */
45 | public String getDescription() {
46 | return this.description;
47 | }
48 |
49 | /** Setter for property description.
50 | * @param description New value of property description.
51 | */
52 | public void setDescription(String description) {
53 | this.description = description;
54 | }
55 |
56 | /** Getter for property pet.
57 | * @return Value of property pet.
58 | */
59 | public Pet getPet() {
60 | return this.pet;
61 | }
62 |
63 | /** Setter for property pet.
64 | * @param pet New value of property pet.
65 | */
66 | public void setPet(Pet pet) {
67 | this.pet = pet;
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/aspects/AbstractTraceAspect.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic.aspects;
2 |
3 | import org.aspectj.lang.JoinPoint;
4 | import org.aspectj.lang.annotation.Aspect;
5 | import org.aspectj.lang.annotation.Before;
6 | import org.aspectj.lang.annotation.Pointcut;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | /**
11 | * Aspect to illustrate Spring-driven load-time weaving.
12 | *
13 | * @author Ramnivas Laddad
14 | * @since 2.5
15 | */
16 | @Aspect
17 | public abstract class AbstractTraceAspect {
18 |
19 | private static final Logger logger = LoggerFactory.getLogger(AbstractTraceAspect.class);
20 |
21 | @Pointcut
22 | public abstract void traced();
23 |
24 | @Before("traced()")
25 | public void trace(JoinPoint.StaticPart jpsp) {
26 | if (logger.isTraceEnabled()) {
27 | logger.trace("Entering " + jpsp.getSignature().toLongString());
28 | }
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/aspects/CallMonitoringAspect.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic.aspects;
2 |
3 | import org.aspectj.lang.ProceedingJoinPoint;
4 | import org.aspectj.lang.annotation.Around;
5 | import org.aspectj.lang.annotation.Aspect;
6 |
7 | import org.springframework.jmx.export.annotation.ManagedAttribute;
8 | import org.springframework.jmx.export.annotation.ManagedOperation;
9 | import org.springframework.jmx.export.annotation.ManagedResource;
10 | import org.springframework.util.StopWatch;
11 |
12 | /**
13 | * Simple AspectJ aspect that monitors call count and call invocation time.
14 | * Implements the CallMonitor management interface.
15 | *
16 | * @author Rob Harrop
17 | * @author Juergen Hoeller
18 | * @since 2.5
19 | */
20 | @ManagedResource("petclinic:type=CallMonitor")
21 | @Aspect
22 | public class CallMonitoringAspect {
23 |
24 | private boolean isEnabled = true;
25 |
26 | private int callCount = 0;
27 |
28 | private long accumulatedCallTime = 0;
29 |
30 |
31 | @ManagedAttribute
32 | public void setEnabled(boolean enabled) {
33 | isEnabled = enabled;
34 | }
35 |
36 | @ManagedAttribute
37 | public boolean isEnabled() {
38 | return isEnabled;
39 | }
40 |
41 | @ManagedOperation
42 | public void reset() {
43 | this.callCount = 0;
44 | this.accumulatedCallTime = 0;
45 | }
46 |
47 | @ManagedAttribute
48 | public int getCallCount() {
49 | return callCount;
50 | }
51 |
52 | @ManagedAttribute
53 | public long getCallTime() {
54 | return (this.callCount > 0 ? this.accumulatedCallTime / this.callCount : 0);
55 | }
56 |
57 |
58 | @Around("within(@org.springframework.stereotype.Service *)")
59 | public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable {
60 | if (this.isEnabled) {
61 | StopWatch sw = new StopWatch(joinPoint.toShortString());
62 |
63 | sw.start("invoke");
64 | try {
65 | return joinPoint.proceed();
66 | }
67 | finally {
68 | sw.stop();
69 | synchronized (this) {
70 | this.callCount++;
71 | this.accumulatedCallTime += sw.getTotalTimeMillis();
72 | }
73 | }
74 | }
75 |
76 | else {
77 | return joinPoint.proceed();
78 | }
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/aspects/UsageLogAspect.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic.aspects;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collections;
5 | import java.util.List;
6 |
7 | import org.aspectj.lang.annotation.Aspect;
8 | import org.aspectj.lang.annotation.Before;
9 |
10 | /**
11 | * Sample AspectJ annotation-style aspect that saves
12 | * every owner name requested to the clinic.
13 | *
14 | * @author Rod Johnson
15 | * @author Juergen Hoeller
16 | * @since 2.0
17 | */
18 | @Aspect
19 | public class UsageLogAspect {
20 |
21 | private int historySize = 100;
22 |
23 | // Of course saving all names is not suitable for
24 | // production use, but this is a simple example.
25 | private List namesRequested = new ArrayList(this.historySize);
26 |
27 |
28 | public synchronized void setHistorySize(int historySize) {
29 | this.historySize = historySize;
30 | this.namesRequested = new ArrayList(historySize);
31 | }
32 |
33 | @Before("execution(* *.findOwners(String)) && args(name)")
34 | public synchronized void logNameRequest(String name) {
35 | // Not the most efficient implementation,
36 | // but we're aiming to illustrate the power of
37 | // @AspectJ AOP, not write perfect code here :-)
38 | if (this.namesRequested.size() > this.historySize) {
39 | this.namesRequested.remove(0);
40 | }
41 | this.namesRequested.add(name);
42 | }
43 |
44 | public synchronized List getNamesRequested() {
45 | return Collections.unmodifiableList(this.namesRequested);
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/hibernate/HibernateClinic.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic.hibernate;
2 |
3 | import java.util.Collection;
4 |
5 | import org.hibernate.SessionFactory;
6 |
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.dao.DataAccessException;
9 | import org.springframework.samples.petclinic.Clinic;
10 | import org.springframework.samples.petclinic.Owner;
11 | import org.springframework.samples.petclinic.Pet;
12 | import org.springframework.samples.petclinic.PetType;
13 | import org.springframework.samples.petclinic.Vet;
14 | import org.springframework.samples.petclinic.Visit;
15 | import org.springframework.stereotype.Repository;
16 | import org.springframework.transaction.annotation.Transactional;
17 |
18 | /**
19 | * Hibernate implementation of the Clinic interface.
20 | *
21 | * The mappings are defined in "petclinic.hbm.xml", located in the root of the
22 | * class path.
23 | *
24 | *
Note that transactions are declared with annotations and that some methods
25 | * contain "readOnly = true" which is an optimization that is particularly
26 | * valuable when using Hibernate (to suppress unnecessary flush attempts for
27 | * read-only operations).
28 | *
29 | * @author Juergen Hoeller
30 | * @author Sam Brannen
31 | * @author Mark Fisher
32 | * @since 19.10.2003
33 | */
34 | @Repository
35 | @Transactional
36 | public class HibernateClinic implements Clinic {
37 |
38 | private SessionFactory sessionFactory;
39 |
40 | @Autowired
41 | public HibernateClinic(SessionFactory sessionFactory) {
42 | this.sessionFactory = sessionFactory;
43 | }
44 |
45 | @Transactional(readOnly = true)
46 | @SuppressWarnings("unchecked")
47 | public Collection getVets() {
48 | return sessionFactory.getCurrentSession().createQuery("from Vet vet order by vet.lastName, vet.firstName").list();
49 | }
50 |
51 | @Transactional(readOnly = true)
52 | @SuppressWarnings("unchecked")
53 | public Collection getPetTypes() {
54 | return sessionFactory.getCurrentSession().createQuery("from PetType type order by type.name").list();
55 | }
56 |
57 | @Transactional(readOnly = true)
58 | @SuppressWarnings("unchecked")
59 | public Collection findOwners(String lastName) {
60 | return sessionFactory.getCurrentSession().createQuery("from Owner owner where owner.lastName like :lastName")
61 | .setString("lastName", lastName + "%").list();
62 | }
63 |
64 | @Transactional(readOnly = true)
65 | public Owner loadOwner(int id) {
66 | return (Owner) sessionFactory.getCurrentSession().load(Owner.class, id);
67 | }
68 |
69 | @Transactional(readOnly = true)
70 | public Pet loadPet(int id) {
71 | return (Pet) sessionFactory.getCurrentSession().load(Pet.class, id);
72 | }
73 |
74 | public void storeOwner(Owner owner) {
75 | // Note: Hibernate3's merge operation does not reassociate the object
76 | // with the current Hibernate Session. Instead, it will always copy the
77 | // state over to a registered representation of the entity. In case of a
78 | // new entity, it will register a copy as well, but will not update the
79 | // id of the passed-in object. To still update the ids of the original
80 | // objects too, we need to register Spring's
81 | // IdTransferringMergeEventListener on our SessionFactory.
82 | sessionFactory.getCurrentSession().merge(owner);
83 | }
84 |
85 | public void storePet(Pet pet) {
86 | sessionFactory.getCurrentSession().merge(pet);
87 | }
88 |
89 | public void storeVisit(Visit visit) {
90 | sessionFactory.getCurrentSession().merge(visit);
91 | }
92 |
93 | public void deletePet(int id) throws DataAccessException {
94 | Pet pet = loadPet(id);
95 | sessionFactory.getCurrentSession().delete(pet);
96 | }
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/hibernate/package-info.java:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | *
4 | * The classes in this package represent the Hibernate implementation
5 | * of PetClinic's persistence layer.
6 | *
7 | */
8 | package org.springframework.samples.petclinic.hibernate;
9 |
10 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/jdbc/JdbcPet.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic.jdbc;
2 |
3 | import org.springframework.samples.petclinic.Pet;
4 |
5 | /**
6 | * Subclass of Pet that carries temporary id properties which
7 | * are only relevant for a JDBC implmentation of the Clinic.
8 | *
9 | * @author Juergen Hoeller
10 | * @see SimpleJdbcClinic
11 | */
12 | class JdbcPet extends Pet {
13 |
14 | private int typeId;
15 |
16 | private int ownerId;
17 |
18 |
19 | public void setTypeId(int typeId) {
20 | this.typeId = typeId;
21 | }
22 |
23 | public int getTypeId() {
24 | return this.typeId;
25 | }
26 |
27 | public void setOwnerId(int ownerId) {
28 | this.ownerId = ownerId;
29 | }
30 |
31 | public int getOwnerId() {
32 | return this.ownerId;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/jdbc/SimpleJdbcClinicMBean.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic.jdbc;
2 |
3 | /**
4 | * Interface that defines a cache refresh operation.
5 | * To be exposed for management via JMX.
6 | *
7 | * @author Rob Harrop
8 | * @author Juergen Hoeller
9 | * @see SimpleJdbcClinic
10 | */
11 | public interface SimpleJdbcClinicMBean {
12 |
13 | /**
14 | * Refresh the cache of Vets that the Clinic is holding.
15 | * @see org.springframework.samples.petclinic.Clinic#getVets()
16 | * @see SimpleJdbcClinic#refreshVetsCache()
17 | */
18 | void refreshVetsCache();
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/jdbc/package-info.java:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | *
4 | * The classes in this package represent the JDBC implementation
5 | * of PetClinic's persistence layer.
6 | *
7 | */
8 | package org.springframework.samples.petclinic.jdbc;
9 |
10 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/jpa/EntityManagerClinic.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic.jpa;
2 |
3 | import java.util.Collection;
4 |
5 | import javax.persistence.EntityManager;
6 | import javax.persistence.PersistenceContext;
7 | import javax.persistence.Query;
8 |
9 | import org.springframework.samples.petclinic.Clinic;
10 | import org.springframework.samples.petclinic.Owner;
11 | import org.springframework.samples.petclinic.Pet;
12 | import org.springframework.samples.petclinic.PetType;
13 | import org.springframework.samples.petclinic.Vet;
14 | import org.springframework.samples.petclinic.Visit;
15 | import org.springframework.stereotype.Repository;
16 | import org.springframework.transaction.annotation.Transactional;
17 | import org.springframework.dao.DataAccessException;
18 |
19 | /**
20 | * JPA implementation of the Clinic interface using EntityManager.
21 | *
22 | * The mappings are defined in "orm.xml" located in the META-INF directory.
23 | *
24 | * @author Mike Keith
25 | * @author Rod Johnson
26 | * @author Sam Brannen
27 | * @since 22.4.2006
28 | */
29 | @Repository
30 | @Transactional
31 | public class EntityManagerClinic implements Clinic {
32 |
33 | @PersistenceContext
34 | private EntityManager em;
35 |
36 |
37 | @Transactional(readOnly = true)
38 | @SuppressWarnings("unchecked")
39 | public Collection getVets() {
40 | return this.em.createQuery("SELECT vet FROM Vet vet ORDER BY vet.lastName, vet.firstName").getResultList();
41 | }
42 |
43 | @Transactional(readOnly = true)
44 | @SuppressWarnings("unchecked")
45 | public Collection getPetTypes() {
46 | return this.em.createQuery("SELECT ptype FROM PetType ptype ORDER BY ptype.name").getResultList();
47 | }
48 |
49 | @Transactional(readOnly = true)
50 | @SuppressWarnings("unchecked")
51 | public Collection findOwners(String lastName) {
52 | Query query = this.em.createQuery("SELECT owner FROM Owner owner WHERE owner.lastName LIKE :lastName");
53 | query.setParameter("lastName", lastName + "%");
54 | return query.getResultList();
55 | }
56 |
57 | @Transactional(readOnly = true)
58 | public Owner loadOwner(int id) {
59 | return this.em.find(Owner.class, id);
60 | }
61 |
62 | @Transactional(readOnly = true)
63 | public Pet loadPet(int id) {
64 | return this.em.find(Pet.class, id);
65 | }
66 |
67 | public void storeOwner(Owner owner) {
68 | // Consider returning the persistent object here, for exposing
69 | // a newly assigned id using any persistence provider...
70 | Owner merged = this.em.merge(owner);
71 | this.em.flush();
72 | owner.setId(merged.getId());
73 | }
74 |
75 | public void storePet(Pet pet) {
76 | // Consider returning the persistent object here, for exposing
77 | // a newly assigned id using any persistence provider...
78 | Pet merged = this.em.merge(pet);
79 | this.em.flush();
80 | pet.setId(merged.getId());
81 | }
82 |
83 | public void storeVisit(Visit visit) {
84 | // Consider returning the persistent object here, for exposing
85 | // a newly assigned id using any persistence provider...
86 | Visit merged = this.em.merge(visit);
87 | this.em.flush();
88 | visit.setId(merged.getId());
89 | }
90 |
91 | public void deletePet(int id) throws DataAccessException {
92 | Pet pet = loadPet(id);
93 | this.em.remove(pet);
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/jpa/package-info.java:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | *
4 | * The classes in this package represent the JPA implementation
5 | * of PetClinic's persistence layer.
6 | *
7 | */
8 | package org.springframework.samples.petclinic.jpa;
9 |
10 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/package-info.java:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | *
4 | * The classes in this package represent PetClinic's business layer.
5 | *
6 | */
7 | package org.springframework.samples.petclinic;
8 |
9 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/toplink/EssentialsHSQLPlatformWithNativeSequence.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic.toplink;
2 |
3 | import java.io.IOException;
4 | import java.io.Writer;
5 |
6 | import oracle.toplink.essentials.exceptions.ValidationException;
7 | import oracle.toplink.essentials.platform.database.HSQLPlatform;
8 | import oracle.toplink.essentials.queryframework.ValueReadQuery;
9 |
10 | /**
11 | * Subclass of the TopLink Essentials default HSQLPlatform class, using native
12 | * HSQLDB identity columns for id generation.
13 | *
14 | * Necessary for PetClinic's default data model, which relies on identity
15 | * columns: this is uniformly used across all persistence layer implementations
16 | * (JDBC, Hibernate, and JPA).
17 | *
18 | * @author Juergen Hoeller
19 | * @author James Clark
20 | * @since 1.2
21 | */
22 | public class EssentialsHSQLPlatformWithNativeSequence extends HSQLPlatform {
23 |
24 | private static final long serialVersionUID = -55658009691346735L;
25 |
26 |
27 | public EssentialsHSQLPlatformWithNativeSequence() {
28 | // setUsesNativeSequencing(true);
29 | }
30 |
31 | @Override
32 | public boolean supportsNativeSequenceNumbers() {
33 | return true;
34 | }
35 |
36 | @Override
37 | public boolean shouldNativeSequenceAcquireValueAfterInsert() {
38 | return true;
39 | }
40 |
41 | @Override
42 | public ValueReadQuery buildSelectQueryForNativeSequence() {
43 | return new ValueReadQuery("CALL IDENTITY()");
44 | }
45 |
46 | @Override
47 | public void printFieldIdentityClause(Writer writer) throws ValidationException {
48 | try {
49 | writer.write(" IDENTITY");
50 | }
51 | catch (IOException ex) {
52 | throw ValidationException.fileError(ex);
53 | }
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/toplink/package-info.java:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | *
4 | * The classes in this package provide support for using the TopLink
5 | * implementation with PetClinic's EntityManagerClinic.
6 | *
7 | *
8 | */
9 | package org.springframework.samples.petclinic.toplink;
10 |
11 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/util/EntityUtils.java:
--------------------------------------------------------------------------------
1 |
2 | package org.springframework.samples.petclinic.util;
3 |
4 | import java.util.Collection;
5 |
6 | import org.springframework.orm.ObjectRetrievalFailureException;
7 | import org.springframework.samples.petclinic.BaseEntity;
8 |
9 | /**
10 | * Utility methods for handling entities. Separate from the BaseEntity class
11 | * mainly because of dependency on the ORM-associated
12 | * ObjectRetrievalFailureException.
13 | *
14 | * @author Juergen Hoeller
15 | * @author Sam Brannen
16 | * @since 29.10.2003
17 | * @see org.springframework.samples.petclinic.BaseEntity
18 | */
19 | public abstract class EntityUtils {
20 |
21 | /**
22 | * Look up the entity of the given class with the given id in the given
23 | * collection.
24 | *
25 | * @param entities the collection to search
26 | * @param entityClass the entity class to look up
27 | * @param entityId the entity id to look up
28 | * @return the found entity
29 | * @throws ObjectRetrievalFailureException if the entity was not found
30 | */
31 | public static T getById(Collection entities, Class entityClass, int entityId)
32 | throws ObjectRetrievalFailureException {
33 | for (T entity : entities) {
34 | if (entity.getId().intValue() == entityId && entityClass.isInstance(entity)) {
35 | return entity;
36 | }
37 | }
38 | throw new ObjectRetrievalFailureException(entityClass, new Integer(entityId));
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/validation/OwnerValidator.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic.validation;
2 |
3 | import org.springframework.samples.petclinic.Owner;
4 | import org.springframework.util.StringUtils;
5 | import org.springframework.validation.Errors;
6 |
7 | /**
8 | * Validator
for Owner
forms.
9 | *
10 | * @author Ken Krebs
11 | * @author Juergen Hoeller
12 | */
13 | public class OwnerValidator {
14 |
15 | public void validate(Owner owner, Errors errors) {
16 | if (!StringUtils.hasLength(owner.getFirstName())) {
17 | errors.rejectValue("firstName", "required", "required");
18 | }
19 | if (!StringUtils.hasLength(owner.getLastName())) {
20 | errors.rejectValue("lastName", "required", "required");
21 | }
22 | if (!StringUtils.hasLength(owner.getAddress())) {
23 | errors.rejectValue("address", "required", "required");
24 | }
25 | if (!StringUtils.hasLength(owner.getCity())) {
26 | errors.rejectValue("city", "required", "required");
27 | }
28 |
29 | String telephone = owner.getTelephone();
30 | if (!StringUtils.hasLength(telephone)) {
31 | errors.rejectValue("telephone", "required", "required");
32 | }
33 | else {
34 | for (int i = 0; i < telephone.length(); ++i) {
35 | if ((Character.isDigit(telephone.charAt(i))) == false) {
36 | errors.rejectValue("telephone", "nonNumeric", "non-numeric");
37 | break;
38 | }
39 | }
40 | }
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/validation/PetValidator.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic.validation;
2 |
3 | import org.springframework.samples.petclinic.Pet;
4 | import org.springframework.util.StringUtils;
5 | import org.springframework.validation.Errors;
6 |
7 | /**
8 | * Validator
for Pet
forms.
9 | *
10 | * @author Ken Krebs
11 | * @author Juergen Hoeller
12 | */
13 | public class PetValidator {
14 |
15 | public void validate(Pet pet, Errors errors) {
16 | String name = pet.getName();
17 | if (!StringUtils.hasLength(name)) {
18 | errors.rejectValue("name", "required", "required");
19 | }
20 | else if (pet.isNew() && pet.getOwner().getPet(name, true) != null) {
21 | errors.rejectValue("name", "duplicate", "already exists");
22 | }
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/validation/VisitValidator.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic.validation;
2 |
3 | import org.springframework.samples.petclinic.Visit;
4 | import org.springframework.util.StringUtils;
5 | import org.springframework.validation.Errors;
6 |
7 | /**
8 | * Validator
for Visit
forms.
9 | *
10 | * @author Ken Krebs
11 | * @author Juergen Hoeller
12 | */
13 | public class VisitValidator {
14 |
15 | public void validate(Visit visit, Errors errors) {
16 | if (!StringUtils.hasLength(visit.getDescription())) {
17 | errors.rejectValue("description", "required", "required");
18 | }
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/validation/package-info.java:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | *
4 | * The classes in this package represent the set of Validator objects
5 | * the Business Layer makes available to the Presentation Layer.
6 | *
7 | */
8 | package org.springframework.samples.petclinic.validation;
9 |
10 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/web/AddOwnerForm.java:
--------------------------------------------------------------------------------
1 |
2 | package org.springframework.samples.petclinic.web;
3 |
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.samples.petclinic.Clinic;
6 | import org.springframework.samples.petclinic.Owner;
7 | import org.springframework.samples.petclinic.validation.OwnerValidator;
8 | import org.springframework.stereotype.Controller;
9 | import org.springframework.ui.Model;
10 | import org.springframework.validation.BindingResult;
11 | import org.springframework.web.bind.WebDataBinder;
12 | import org.springframework.web.bind.annotation.InitBinder;
13 | import org.springframework.web.bind.annotation.ModelAttribute;
14 | import org.springframework.web.bind.annotation.RequestMapping;
15 | import org.springframework.web.bind.annotation.RequestMethod;
16 | import org.springframework.web.bind.annotation.SessionAttributes;
17 | import org.springframework.web.bind.support.SessionStatus;
18 |
19 | /**
20 | * JavaBean form controller that is used to add a new Owner
to the
21 | * system.
22 | *
23 | * @author Juergen Hoeller
24 | * @author Ken Krebs
25 | * @author Arjen Poutsma
26 | */
27 | @Controller
28 | @RequestMapping("/owners/new")
29 | @SessionAttributes(types = Owner.class)
30 | public class AddOwnerForm {
31 |
32 | private final Clinic clinic;
33 |
34 |
35 | @Autowired
36 | public AddOwnerForm(Clinic clinic) {
37 | this.clinic = clinic;
38 | }
39 |
40 | @InitBinder
41 | public void setAllowedFields(WebDataBinder dataBinder) {
42 | dataBinder.setDisallowedFields("id");
43 | }
44 |
45 | @RequestMapping(method = RequestMethod.GET)
46 | public String setupForm(Model model) {
47 | Owner owner = new Owner();
48 | model.addAttribute(owner);
49 | return "owners/form";
50 | }
51 |
52 | @RequestMapping(method = RequestMethod.POST)
53 | public String processSubmit(@ModelAttribute Owner owner, BindingResult result, SessionStatus status) {
54 | new OwnerValidator().validate(owner, result);
55 | if (result.hasErrors()) {
56 | return "owners/form";
57 | }
58 | else {
59 | this.clinic.storeOwner(owner);
60 | status.setComplete();
61 | return "redirect:/owners/" + owner.getId();
62 | }
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/web/AddPetForm.java:
--------------------------------------------------------------------------------
1 |
2 | package org.springframework.samples.petclinic.web;
3 |
4 | import java.util.Collection;
5 |
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.samples.petclinic.Clinic;
8 | import org.springframework.samples.petclinic.Owner;
9 | import org.springframework.samples.petclinic.Pet;
10 | import org.springframework.samples.petclinic.PetType;
11 | import org.springframework.samples.petclinic.validation.PetValidator;
12 | import org.springframework.stereotype.Controller;
13 | import org.springframework.ui.Model;
14 | import org.springframework.validation.BindingResult;
15 | import org.springframework.web.bind.WebDataBinder;
16 | import org.springframework.web.bind.annotation.InitBinder;
17 | import org.springframework.web.bind.annotation.ModelAttribute;
18 | import org.springframework.web.bind.annotation.PathVariable;
19 | import org.springframework.web.bind.annotation.RequestMapping;
20 | import org.springframework.web.bind.annotation.RequestMethod;
21 | import org.springframework.web.bind.annotation.SessionAttributes;
22 | import org.springframework.web.bind.support.SessionStatus;
23 |
24 | /**
25 | * JavaBean form controller that is used to add a new Pet
to the
26 | * system.
27 | *
28 | * @author Juergen Hoeller
29 | * @author Ken Krebs
30 | * @author Arjen Poutsma
31 | */
32 | @Controller
33 | @RequestMapping("/owners/{ownerId}/pets/new")
34 | @SessionAttributes("pet")
35 | public class AddPetForm {
36 |
37 | private final Clinic clinic;
38 |
39 |
40 | @Autowired
41 | public AddPetForm(Clinic clinic) {
42 | this.clinic = clinic;
43 | }
44 |
45 | @ModelAttribute("types")
46 | public Collection populatePetTypes() {
47 | return this.clinic.getPetTypes();
48 | }
49 |
50 | @InitBinder
51 | public void setAllowedFields(WebDataBinder dataBinder) {
52 | dataBinder.setDisallowedFields("id");
53 | }
54 |
55 | @RequestMapping(method = RequestMethod.GET)
56 | public String setupForm(@PathVariable("ownerId") int ownerId, Model model) {
57 | Owner owner = this.clinic.loadOwner(ownerId);
58 | Pet pet = new Pet();
59 | owner.addPet(pet);
60 | model.addAttribute("pet", pet);
61 | return "pets/form";
62 | }
63 |
64 | @RequestMapping(method = RequestMethod.POST)
65 | public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result, SessionStatus status) {
66 | new PetValidator().validate(pet, result);
67 | if (result.hasErrors()) {
68 | return "pets/form";
69 | }
70 | else {
71 | this.clinic.storePet(pet);
72 | status.setComplete();
73 | return "redirect:/owners/" + pet.getOwner().getId();
74 | }
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/web/AddVisitForm.java:
--------------------------------------------------------------------------------
1 |
2 | package org.springframework.samples.petclinic.web;
3 |
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.samples.petclinic.Clinic;
6 | import org.springframework.samples.petclinic.Pet;
7 | import org.springframework.samples.petclinic.Visit;
8 | import org.springframework.samples.petclinic.validation.VisitValidator;
9 | import org.springframework.stereotype.Controller;
10 | import org.springframework.ui.Model;
11 | import org.springframework.validation.BindingResult;
12 | import org.springframework.web.bind.WebDataBinder;
13 | import org.springframework.web.bind.annotation.InitBinder;
14 | import org.springframework.web.bind.annotation.ModelAttribute;
15 | import org.springframework.web.bind.annotation.PathVariable;
16 | import org.springframework.web.bind.annotation.RequestMapping;
17 | import org.springframework.web.bind.annotation.RequestMethod;
18 | import org.springframework.web.bind.annotation.SessionAttributes;
19 | import org.springframework.web.bind.support.SessionStatus;
20 |
21 | /**
22 | * JavaBean form controller that is used to add a new Visit
to the
23 | * system.
24 | *
25 | * @author Juergen Hoeller
26 | * @author Ken Krebs
27 | * @author Arjen Poutsma
28 | */
29 | @Controller
30 | @RequestMapping("/owners/*/pets/{petId}/visits/new")
31 | @SessionAttributes("visit")
32 | public class AddVisitForm {
33 |
34 | private final Clinic clinic;
35 |
36 |
37 | @Autowired
38 | public AddVisitForm(Clinic clinic) {
39 | this.clinic = clinic;
40 | }
41 |
42 | @InitBinder
43 | public void setAllowedFields(WebDataBinder dataBinder) {
44 | dataBinder.setDisallowedFields("id");
45 | }
46 |
47 | @RequestMapping(method = RequestMethod.GET)
48 | public String setupForm(@PathVariable("petId") int petId, Model model) {
49 | Pet pet = this.clinic.loadPet(petId);
50 | Visit visit = new Visit();
51 | pet.addVisit(visit);
52 | model.addAttribute("visit", visit);
53 | return "pets/visitForm";
54 | }
55 |
56 | @RequestMapping(method = RequestMethod.POST)
57 | public String processSubmit(@ModelAttribute("visit") Visit visit, BindingResult result, SessionStatus status) {
58 | new VisitValidator().validate(visit, result);
59 | if (result.hasErrors()) {
60 | return "pets/visitForm";
61 | }
62 | else {
63 | this.clinic.storeVisit(visit);
64 | status.setComplete();
65 | return "redirect:/owners/" + visit.getPet().getOwner().getId();
66 | }
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/web/ClinicBindingInitializer.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic.web;
2 |
3 | import java.text.SimpleDateFormat;
4 | import java.util.Date;
5 |
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.beans.propertyeditors.CustomDateEditor;
8 | import org.springframework.beans.propertyeditors.StringTrimmerEditor;
9 | import org.springframework.samples.petclinic.Clinic;
10 | import org.springframework.samples.petclinic.PetType;
11 | import org.springframework.web.bind.WebDataBinder;
12 | import org.springframework.web.bind.support.WebBindingInitializer;
13 | import org.springframework.web.context.request.WebRequest;
14 |
15 | /**
16 | * Shared WebBindingInitializer for PetClinic's custom editors.
17 | *
18 | * Alternatively, such init-binder code may be put into
19 | * {@link org.springframework.web.bind.annotation.InitBinder}
20 | * annotated methods on the controller classes themselves.
21 | *
22 | * @author Juergen Hoeller
23 | */
24 | public class ClinicBindingInitializer implements WebBindingInitializer {
25 |
26 | @Autowired
27 | private Clinic clinic;
28 |
29 | public void initBinder(WebDataBinder binder, WebRequest request) {
30 | SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
31 | dateFormat.setLenient(false);
32 | binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
33 | binder.registerCustomEditor(String.class, new StringTrimmerEditor(false));
34 | binder.registerCustomEditor(PetType.class, new PetTypeEditor(this.clinic));
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/web/ClinicController.java:
--------------------------------------------------------------------------------
1 |
2 | package org.springframework.samples.petclinic.web;
3 |
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.samples.petclinic.Clinic;
6 | import org.springframework.samples.petclinic.Vets;
7 | import org.springframework.stereotype.Controller;
8 | import org.springframework.ui.ModelMap;
9 | import org.springframework.web.bind.annotation.PathVariable;
10 | import org.springframework.web.bind.annotation.RequestMapping;
11 | import org.springframework.web.bind.annotation.RequestMethod;
12 | import org.springframework.web.servlet.ModelAndView;
13 |
14 | /**
15 | * Annotation-driven MultiActionController that handles all non-form
16 | * URL's.
17 | *
18 | * @author Juergen Hoeller
19 | * @author Mark Fisher
20 | * @author Ken Krebs
21 | * @author Arjen Poutsma
22 | */
23 | @Controller
24 | public class ClinicController {
25 |
26 | private final Clinic clinic;
27 |
28 |
29 | @Autowired
30 | public ClinicController(Clinic clinic) {
31 | this.clinic = clinic;
32 | }
33 |
34 | /**
35 | * Custom handler for the welcome view.
36 | *
37 | * Note that this handler relies on the RequestToViewNameTranslator to
38 | * determine the logical view name based on the request URL: "/welcome.do"
39 | * -> "welcome".
40 | */
41 | @RequestMapping("/")
42 | public String welcomeHandler() {
43 | return "welcome";
44 | }
45 |
46 | /**
47 | * Custom handler for displaying vets.
48 | *
49 | *
Note that this handler returns a plain {@link ModelMap} object instead of
50 | * a ModelAndView, thus leveraging convention-based model attribute names.
51 | * It relies on the RequestToViewNameTranslator to determine the logical
52 | * view name based on the request URL: "/vets.do" -> "vets".
53 | *
54 | * @return a ModelMap with the model attributes for the view
55 | */
56 | @RequestMapping("/vets")
57 | public ModelMap vetsHandler() {
58 | Vets vets = new Vets();
59 | vets.getVetList().addAll(this.clinic.getVets());
60 | return new ModelMap(vets);
61 | }
62 |
63 | /**
64 | * Custom handler for displaying an owner.
65 | *
66 | * @param ownerId the ID of the owner to display
67 | * @return a ModelMap with the model attributes for the view
68 | */
69 | @RequestMapping("/owners/{ownerId}")
70 | public ModelAndView ownerHandler(@PathVariable("ownerId") int ownerId) {
71 | ModelAndView mav = new ModelAndView("owners/show");
72 | mav.addObject(this.clinic.loadOwner(ownerId));
73 | return mav;
74 | }
75 |
76 | /**
77 | * Custom handler for displaying an list of visits.
78 | *
79 | * @param petId the ID of the pet whose visits to display
80 | * @return a ModelMap with the model attributes for the view
81 | */
82 | @RequestMapping(value="/owners/*/pets/{petId}/visits", method=RequestMethod.GET)
83 | public ModelAndView visitsHandler(@PathVariable int petId) {
84 | ModelAndView mav = new ModelAndView("visits");
85 | mav.addObject("visits", this.clinic.loadPet(petId).getVisits());
86 | return mav;
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/web/EditOwnerForm.java:
--------------------------------------------------------------------------------
1 |
2 | package org.springframework.samples.petclinic.web;
3 |
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.samples.petclinic.Clinic;
6 | import org.springframework.samples.petclinic.Owner;
7 | import org.springframework.samples.petclinic.validation.OwnerValidator;
8 | import org.springframework.stereotype.Controller;
9 | import org.springframework.ui.Model;
10 | import org.springframework.validation.BindingResult;
11 | import org.springframework.web.bind.WebDataBinder;
12 | import org.springframework.web.bind.annotation.InitBinder;
13 | import org.springframework.web.bind.annotation.ModelAttribute;
14 | import org.springframework.web.bind.annotation.PathVariable;
15 | import org.springframework.web.bind.annotation.RequestMapping;
16 | import org.springframework.web.bind.annotation.RequestMethod;
17 | import org.springframework.web.bind.annotation.SessionAttributes;
18 | import org.springframework.web.bind.support.SessionStatus;
19 |
20 | /**
21 | * JavaBean Form controller that is used to edit an existing Owner
.
22 | *
23 | * @author Juergen Hoeller
24 | * @author Ken Krebs
25 | * @author Arjen Poutsma
26 | */
27 | @Controller
28 | @RequestMapping("/owners/{ownerId}/edit")
29 | @SessionAttributes(types = Owner.class)
30 | public class EditOwnerForm {
31 |
32 | private final Clinic clinic;
33 |
34 |
35 | @Autowired
36 | public EditOwnerForm(Clinic clinic) {
37 | this.clinic = clinic;
38 | }
39 |
40 | @InitBinder
41 | public void setAllowedFields(WebDataBinder dataBinder) {
42 | dataBinder.setDisallowedFields("id");
43 | }
44 |
45 | @RequestMapping(method = RequestMethod.GET)
46 | public String setupForm(@PathVariable("ownerId") int ownerId, Model model) {
47 | Owner owner = this.clinic.loadOwner(ownerId);
48 | model.addAttribute(owner);
49 | return "owners/form";
50 | }
51 |
52 | @RequestMapping(method = RequestMethod.PUT)
53 | public String processSubmit(@ModelAttribute Owner owner, BindingResult result, SessionStatus status) {
54 | new OwnerValidator().validate(owner, result);
55 | if (result.hasErrors()) {
56 | return "owners/form";
57 | }
58 | else {
59 | this.clinic.storeOwner(owner);
60 | status.setComplete();
61 | return "redirect:/owners/" + owner.getId();
62 | }
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/web/EditPetForm.java:
--------------------------------------------------------------------------------
1 |
2 | package org.springframework.samples.petclinic.web;
3 |
4 | import java.util.Collection;
5 |
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.samples.petclinic.Clinic;
8 | import org.springframework.samples.petclinic.Pet;
9 | import org.springframework.samples.petclinic.PetType;
10 | import org.springframework.samples.petclinic.validation.PetValidator;
11 | import org.springframework.stereotype.Controller;
12 | import org.springframework.ui.Model;
13 | import org.springframework.validation.BindingResult;
14 | import org.springframework.web.bind.WebDataBinder;
15 | import org.springframework.web.bind.annotation.InitBinder;
16 | import org.springframework.web.bind.annotation.ModelAttribute;
17 | import org.springframework.web.bind.annotation.PathVariable;
18 | import org.springframework.web.bind.annotation.RequestMapping;
19 | import org.springframework.web.bind.annotation.RequestMethod;
20 | import org.springframework.web.bind.annotation.SessionAttributes;
21 | import org.springframework.web.bind.support.SessionStatus;
22 |
23 | /**
24 | * JavaBean Form controller that is used to edit an existing Pet
.
25 | *
26 | * @author Juergen Hoeller
27 | * @author Ken Krebs
28 | * @author Arjen Poutsma
29 | */
30 | @Controller
31 | @RequestMapping("/owners/*/pets/{petId}/edit")
32 | @SessionAttributes("pet")
33 | public class EditPetForm {
34 |
35 | private final Clinic clinic;
36 |
37 |
38 | @Autowired
39 | public EditPetForm(Clinic clinic) {
40 | this.clinic = clinic;
41 | }
42 |
43 | @ModelAttribute("types")
44 | public Collection populatePetTypes() {
45 | return this.clinic.getPetTypes();
46 | }
47 |
48 | @InitBinder
49 | public void setAllowedFields(WebDataBinder dataBinder) {
50 | dataBinder.setDisallowedFields("id");
51 | }
52 |
53 | @RequestMapping(method = RequestMethod.GET)
54 | public String setupForm(@PathVariable("petId") int petId, Model model) {
55 | Pet pet = this.clinic.loadPet(petId);
56 | model.addAttribute("pet", pet);
57 | return "pets/form";
58 | }
59 |
60 | @RequestMapping(method = { RequestMethod.PUT, RequestMethod.POST })
61 | public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result, SessionStatus status) {
62 | new PetValidator().validate(pet, result);
63 | if (result.hasErrors()) {
64 | return "pets/form";
65 | }
66 | else {
67 | this.clinic.storePet(pet);
68 | status.setComplete();
69 | return "redirect:/owners/" + pet.getOwner().getId();
70 | }
71 | }
72 |
73 | @RequestMapping(method = RequestMethod.DELETE)
74 | public String deletePet(@PathVariable int petId) {
75 | Pet pet = this.clinic.loadPet(petId);
76 | this.clinic.deletePet(petId);
77 | return "redirect:/owners/" + pet.getOwner().getId();
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/web/FindOwnersForm.java:
--------------------------------------------------------------------------------
1 |
2 | package org.springframework.samples.petclinic.web;
3 |
4 | import java.util.Collection;
5 |
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.samples.petclinic.Clinic;
8 | import org.springframework.samples.petclinic.Owner;
9 | import org.springframework.stereotype.Controller;
10 | import org.springframework.ui.Model;
11 | import org.springframework.validation.BindingResult;
12 | import org.springframework.web.bind.WebDataBinder;
13 | import org.springframework.web.bind.annotation.InitBinder;
14 | import org.springframework.web.bind.annotation.RequestMapping;
15 | import org.springframework.web.bind.annotation.RequestMethod;
16 |
17 | /**
18 | * JavaBean Form controller that is used to search for Owner
s by
19 | * last name.
20 | *
21 | * @author Juergen Hoeller
22 | * @author Ken Krebs
23 | * @author Arjen Poutsma
24 | */
25 | @Controller
26 | public class FindOwnersForm {
27 |
28 | private final Clinic clinic;
29 |
30 |
31 | @Autowired
32 | public FindOwnersForm(Clinic clinic) {
33 | this.clinic = clinic;
34 | }
35 |
36 | @InitBinder
37 | public void setAllowedFields(WebDataBinder dataBinder) {
38 | dataBinder.setDisallowedFields("id");
39 | }
40 |
41 | @RequestMapping(value = "/owners/search", method = RequestMethod.GET)
42 | public String setupForm(Model model) {
43 | model.addAttribute("owner", new Owner());
44 | return "owners/search";
45 | }
46 |
47 | @RequestMapping(value = "/owners", method = RequestMethod.GET)
48 | public String processSubmit(Owner owner, BindingResult result, Model model) {
49 |
50 | // allow parameterless GET request for /owners to return all records
51 | if (owner.getLastName() == null) {
52 | owner.setLastName(""); // empty string signifies broadest possible search
53 | }
54 |
55 | // find owners by last name
56 | Collection results = this.clinic.findOwners(owner.getLastName());
57 | if (results.size() < 1) {
58 | // no owners found
59 | result.rejectValue("lastName", "notFound", "not found");
60 | return "owners/search";
61 | }
62 | if (results.size() > 1) {
63 | // multiple owners found
64 | model.addAttribute("selections", results);
65 | return "owners/list";
66 | }
67 | else {
68 | // 1 owner found
69 | owner = results.iterator().next();
70 | return "redirect:/owners/" + owner.getId();
71 | }
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/web/PetTypeEditor.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic.web;
2 |
3 | import java.beans.PropertyEditorSupport;
4 |
5 | import org.springframework.samples.petclinic.Clinic;
6 | import org.springframework.samples.petclinic.PetType;
7 |
8 | /**
9 | * @author Mark Fisher
10 | * @author Juergen Hoeller
11 | */
12 | public class PetTypeEditor extends PropertyEditorSupport {
13 |
14 | private final Clinic clinic;
15 |
16 |
17 | public PetTypeEditor(Clinic clinic) {
18 | this.clinic = clinic;
19 | }
20 |
21 | @Override
22 | public void setAsText(String text) throws IllegalArgumentException {
23 | for (PetType type : this.clinic.getPetTypes()) {
24 | if (type.getName().equals(text)) {
25 | setValue(type);
26 | }
27 | }
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/web/VisitsAtomView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2002-2009 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.samples.petclinic.web;
18 |
19 | import java.util.ArrayList;
20 | import java.util.Date;
21 | import java.util.List;
22 | import java.util.Map;
23 | import javax.servlet.http.HttpServletRequest;
24 | import javax.servlet.http.HttpServletResponse;
25 |
26 | import com.sun.syndication.feed.atom.Content;
27 | import com.sun.syndication.feed.atom.Entry;
28 | import com.sun.syndication.feed.atom.Feed;
29 |
30 | import org.springframework.samples.petclinic.Visit;
31 | import org.springframework.web.servlet.view.feed.AbstractAtomFeedView;
32 |
33 | /**
34 | * A view creating a Atom representation from a list of Visit objects.
35 | *
36 | * @author Alef Arendsen
37 | * @author Arjen Poutsma
38 | */
39 | public class VisitsAtomView extends AbstractAtomFeedView {
40 |
41 | @Override
42 | protected void buildFeedMetadata(Map model, Feed feed, HttpServletRequest request) {
43 | feed.setId("tag:springsource.com");
44 | feed.setTitle("Pet Clinic Visits");
45 | @SuppressWarnings("unchecked")
46 | List visits = (List) model.get("visits");
47 | for (Visit visit : visits) {
48 | Date date = visit.getDate();
49 | if (feed.getUpdated() == null || date.compareTo(feed.getUpdated()) > 0) {
50 | feed.setUpdated(date);
51 | }
52 | }
53 | }
54 |
55 | @Override
56 | protected List buildFeedEntries(Map model,
57 | HttpServletRequest request, HttpServletResponse response) throws Exception {
58 |
59 | @SuppressWarnings("unchecked")
60 | List visits = (List) model.get("visits");
61 | List entries = new ArrayList(visits.size());
62 |
63 | for (Visit visit : visits) {
64 | Entry entry = new Entry();
65 | String date = String.format("%1$tY-%1$tm-%1$td", visit.getDate());
66 | // see http://diveintomark.org/archives/2004/05/28/howto-atom-id#other
67 | entry.setId(String.format("tag:springsource.com,%s:%d", date, visit.getId()));
68 | entry.setTitle(String.format("%s visit on %s", visit.getPet().getName(), date));
69 | entry.setUpdated(visit.getDate());
70 |
71 | Content summary = new Content();
72 | summary.setValue(visit.getDescription());
73 | entry.setSummary(summary);
74 |
75 | entries.add(entry);
76 | }
77 |
78 | return entries;
79 |
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/org/springframework/samples/petclinic/web/package-info.java:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | *
4 | * The classes in this package represent PetClinic's web presentation layer.
5 | *
6 | */
7 | package org.springframework.samples.petclinic.web;
8 |
9 |
--------------------------------------------------------------------------------
/src/main/java/overview.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The Spring Data Binding framework, an internal library used by Spring Web Flow.
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/aop.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/jpa-persistence.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 | META-INF/orm.xml
10 |
11 |
12 | true
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/orm.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 | PROPERTY
11 |
12 |
13 |
14 | org.springframework.samples.petclinic
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | DATE
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 | DATE
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/src/main/resources/db/db_readme.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | === Spring PetClinic sample application - Database Configuration ===
3 | ================================================================================
4 |
5 | @author Costin Leau
6 |
7 | --------------------------------------------------------------------------------
8 |
9 | In its default configuration, Petclinic uses an in-memory database (HSQLDB) which
10 | gets populated at startup with data. A similar setup is provided for Mysql in case
11 | a persistent database configuration is needed.
12 | Note that whenever the database type is changed, the jdbc.properties file needs to
13 | be updated.
--------------------------------------------------------------------------------
/src/main/resources/db/hsqldb/initDB.txt:
--------------------------------------------------------------------------------
1 | CREATE TABLE vets (
2 | id INTEGER NOT NULL IDENTITY PRIMARY KEY,
3 | first_name VARCHAR(30),
4 | last_name VARCHAR(30)
5 | );
6 | CREATE INDEX vets_last_name ON vets(last_name);
7 |
8 | CREATE TABLE specialties (
9 | id INTEGER NOT NULL IDENTITY PRIMARY KEY,
10 | name VARCHAR(80)
11 | );
12 | CREATE INDEX specialties_name ON specialties(name);
13 |
14 | CREATE TABLE vet_specialties (
15 | vet_id INTEGER NOT NULL,
16 | specialty_id INTEGER NOT NULL
17 | );
18 | alter table vet_specialties add constraint fk_vet_specialties_vets foreign key (vet_id) references vets(id);
19 | alter table vet_specialties add constraint fk_vet_specialties_specialties foreign key (specialty_id) references specialties(id);
20 |
21 | CREATE TABLE types (
22 | id INTEGER NOT NULL IDENTITY PRIMARY KEY,
23 | name VARCHAR(80)
24 | );
25 | CREATE INDEX types_name ON types(name);
26 |
27 | CREATE TABLE owners (
28 | id INTEGER NOT NULL IDENTITY PRIMARY KEY,
29 | first_name VARCHAR(30),
30 | last_name VARCHAR(30),
31 | address VARCHAR(255),
32 | city VARCHAR(80),
33 | telephone VARCHAR(20)
34 | );
35 | CREATE INDEX owners_last_name ON owners(last_name);
36 |
37 | CREATE TABLE pets (
38 | id INTEGER NOT NULL IDENTITY PRIMARY KEY,
39 | name VARCHAR(30),
40 | birth_date DATE,
41 | type_id INTEGER NOT NULL,
42 | owner_id INTEGER NOT NULL
43 | );
44 | alter table pets add constraint fk_pets_owners foreign key (owner_id) references owners(id);
45 | alter table pets add constraint fk_pets_types foreign key (type_id) references types(id);
46 | CREATE INDEX pets_name ON pets(name);
47 |
48 | CREATE TABLE visits (
49 | id INTEGER NOT NULL IDENTITY PRIMARY KEY,
50 | pet_id INTEGER NOT NULL,
51 | visit_date DATE,
52 | description VARCHAR(255)
53 | );
54 | alter table visits add constraint fk_visits_pets foreign key (pet_id) references pets(id);
55 | CREATE INDEX visits_pet_id ON visits(pet_id);
56 |
--------------------------------------------------------------------------------
/src/main/resources/db/hsqldb/populateDB.txt:
--------------------------------------------------------------------------------
1 | INSERT INTO vets VALUES (1, 'James', 'Carter');
2 | INSERT INTO vets VALUES (2, 'Helen', 'Leary');
3 | INSERT INTO vets VALUES (3, 'Linda', 'Douglas');
4 | INSERT INTO vets VALUES (4, 'Rafael', 'Ortega');
5 | INSERT INTO vets VALUES (5, 'Henry', 'Stevens');
6 | INSERT INTO vets VALUES (6, 'Sharon', 'Jenkins');
7 |
8 | INSERT INTO specialties VALUES (1, 'radiology');
9 | INSERT INTO specialties VALUES (2, 'surgery');
10 | INSERT INTO specialties VALUES (3, 'dentistry');
11 |
12 | INSERT INTO vet_specialties VALUES (2, 1);
13 | INSERT INTO vet_specialties VALUES (3, 2);
14 | INSERT INTO vet_specialties VALUES (3, 3);
15 | INSERT INTO vet_specialties VALUES (4, 2);
16 | INSERT INTO vet_specialties VALUES (5, 1);
17 |
18 | INSERT INTO types VALUES (1, 'cat');
19 | INSERT INTO types VALUES (2, 'dog');
20 | INSERT INTO types VALUES (3, 'lizard');
21 | INSERT INTO types VALUES (4, 'snake');
22 | INSERT INTO types VALUES (5, 'bird');
23 | INSERT INTO types VALUES (6, 'hamster');
24 |
25 | INSERT INTO owners VALUES (1, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023');
26 | INSERT INTO owners VALUES (2, 'Betty', 'Davis', '638 Cardinal Ave.', 'Sun Prairie', '6085551749');
27 | INSERT INTO owners VALUES (3, 'Eduardo', 'Rodriquez', '2693 Commerce St.', 'McFarland', '6085558763');
28 | INSERT INTO owners VALUES (4, 'Harold', 'Davis', '563 Friendly St.', 'Windsor', '6085553198');
29 | INSERT INTO owners VALUES (5, 'Peter', 'McTavish', '2387 S. Fair Way', 'Madison', '6085552765');
30 | INSERT INTO owners VALUES (6, 'Jean', 'Coleman', '105 N. Lake St.', 'Monona', '6085552654');
31 | INSERT INTO owners VALUES (7, 'Jeff', 'Black', '1450 Oak Blvd.', 'Monona', '6085555387');
32 | INSERT INTO owners VALUES (8, 'Maria', 'Escobito', '345 Maple St.', 'Madison', '6085557683');
33 | INSERT INTO owners VALUES (9, 'David', 'Schroeder', '2749 Blackhawk Trail', 'Madison', '6085559435');
34 | INSERT INTO owners VALUES (10, 'Carlos', 'Estaban', '2335 Independence La.', 'Waunakee', '6085555487');
35 |
36 | INSERT INTO pets VALUES (1, 'Leo', '2000-09-07', 1, 1);
37 | INSERT INTO pets VALUES (2, 'Basil', '2002-08-06', 6, 2);
38 | INSERT INTO pets VALUES (3, 'Rosy', '2001-04-17', 2, 3);
39 | INSERT INTO pets VALUES (4, 'Jewel', '2000-03-07', 2, 3);
40 | INSERT INTO pets VALUES (5, 'Iggy', '2000-11-30', 3, 4);
41 | INSERT INTO pets VALUES (6, 'George', '2000-01-20', 4, 5);
42 | INSERT INTO pets VALUES (7, 'Samantha', '1995-09-04', 1, 6);
43 | INSERT INTO pets VALUES (8, 'Max', '1995-09-04', 1, 6);
44 | INSERT INTO pets VALUES (9, 'Lucky', '1999-08-06', 5, 7);
45 | INSERT INTO pets VALUES (10, 'Mulligan', '1997-02-24', 2, 8);
46 | INSERT INTO pets VALUES (11, 'Freddy', '2000-03-09', 5, 9);
47 | INSERT INTO pets VALUES (12, 'Lucky', '2000-06-24', 2, 10);
48 | INSERT INTO pets VALUES (13, 'Sly', '2002-06-08', 1, 10);
49 |
50 | INSERT INTO visits VALUES (1, 7, '1996-03-04', 'rabies shot');
51 | INSERT INTO visits VALUES (2, 8, '1996-03-04', 'rabies shot');
52 | INSERT INTO visits VALUES (3, 8, '1996-06-04', 'neutered');
53 | INSERT INTO visits VALUES (4, 7, '1996-09-04', 'spayed');
54 |
--------------------------------------------------------------------------------
/src/main/resources/db/mysql/initDB.txt:
--------------------------------------------------------------------------------
1 | CREATE DATABASE IF NOT EXISTS petclinic;
2 | GRANT ALL PRIVILEGES ON petclinic.* TO pc@localhost IDENTIFIED BY 'pc';
3 |
4 | USE petclinic;
5 |
6 | CREATE TABLE IF NOT EXISTS vets (
7 | id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
8 | first_name VARCHAR(30),
9 | last_name VARCHAR(30),
10 | INDEX(last_name)
11 | ) engine=InnoDB;
12 |
13 | CREATE TABLE IF NOT EXISTS specialties (
14 | id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
15 | name VARCHAR(80),
16 | INDEX(name)
17 | ) engine=InnoDB;
18 |
19 | CREATE TABLE IF NOT EXISTS vet_specialties (
20 | vet_id INT(4) UNSIGNED NOT NULL,
21 | specialty_id INT(4) UNSIGNED NOT NULL,
22 | FOREIGN KEY (vet_id) REFERENCES vets(id),
23 | FOREIGN KEY (specialty_id) REFERENCES specialties(id),
24 | UNIQUE (vet_id,specialty_id)
25 | ) engine=InnoDB;
26 |
27 | CREATE TABLE IF NOT EXISTS types (
28 | id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
29 | name VARCHAR(80),
30 | INDEX(name)
31 | ) engine=InnoDB;
32 |
33 | CREATE TABLE IF NOT EXISTS owners (
34 | id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
35 | first_name VARCHAR(30),
36 | last_name VARCHAR(30),
37 | address VARCHAR(255),
38 | city VARCHAR(80),
39 | telephone VARCHAR(20),
40 | INDEX(last_name)
41 | ) engine=InnoDB;
42 |
43 | CREATE TABLE IF NOT EXISTS pets (
44 | id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
45 | name VARCHAR(30),
46 | birth_date DATE,
47 | type_id INT(4) UNSIGNED NOT NULL,
48 | owner_id INT(4) UNSIGNED NOT NULL,
49 | INDEX(name),
50 | FOREIGN KEY (owner_id) REFERENCES owners(id),
51 | FOREIGN KEY (type_id) REFERENCES types(id)
52 | ) engine=InnoDB;
53 |
54 | CREATE TABLE IF NOT EXISTS visits (
55 | id INT(4) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
56 | pet_id INT(4) UNSIGNED NOT NULL,
57 | visit_date DATE,
58 | description VARCHAR(255),
59 | FOREIGN KEY (pet_id) REFERENCES pets(id)
60 | ) engine=InnoDB;
--------------------------------------------------------------------------------
/src/main/resources/db/mysql/petclinic_db_setup_mysql.txt:
--------------------------------------------------------------------------------
1 | ================================================================================
2 | === Spring PetClinic sample application - MySQL Configuration ===
3 | ================================================================================
4 |
5 | @author Sam Brannen
6 | @author Costin Leau
7 |
8 | --------------------------------------------------------------------------------
9 |
10 | 1) Download and install the MySQL database (e.g., MySQL Community Server 5.1.x),
11 | which can be found here: http://dev.mysql.com/downloads/
12 |
13 | 2) Download Connector/J, the MySQL JDBC driver (e.g., Connector/J 5.1.x), which
14 | can be found here: http://dev.mysql.com/downloads/connector/j/
15 | Copy the Connector/J JAR file (e.g., mysql-connector-java-5.1.5-bin.jar) into
16 | the db/mysql directory. Alternatively, uncomment the mysql-connector from the
17 | Petclinic pom.
18 |
19 | 3) Create the PetClinic database and user by executing the "db/mysql/createDB.txt"
20 | script.
21 |
22 | 4) Open "src/main/resources/jdbc.properties"; comment out all properties in the
23 | "HSQL Settings" section; uncomment all properties in the "MySQL Settings"
24 | section.
--------------------------------------------------------------------------------
/src/main/resources/db/mysql/populateDB.txt:
--------------------------------------------------------------------------------
1 | INSERT IGNORE INTO vets VALUES (1, 'James', 'Carter');
2 | INSERT IGNORE INTO vets VALUES (2, 'Helen', 'Leary');
3 | INSERT IGNORE INTO vets VALUES (3, 'Linda', 'Douglas');
4 | INSERT IGNORE INTO vets VALUES (4, 'Rafael', 'Ortega');
5 | INSERT IGNORE INTO vets VALUES (5, 'Henry', 'Stevens');
6 | INSERT IGNORE INTO vets VALUES (6, 'Sharon', 'Jenkins');
7 |
8 | INSERT IGNORE INTO specialties VALUES (1, 'radiology');
9 | INSERT IGNORE INTO specialties VALUES (2, 'surgery');
10 | INSERT IGNORE INTO specialties VALUES (3, 'dentistry');
11 |
12 | INSERT IGNORE INTO vet_specialties VALUES (2, 1);
13 | INSERT IGNORE INTO vet_specialties VALUES (3, 2);
14 | INSERT IGNORE INTO vet_specialties VALUES (3, 3);
15 | INSERT IGNORE INTO vet_specialties VALUES (4, 2);
16 | INSERT IGNORE INTO vet_specialties VALUES (5, 1);
17 |
18 | INSERT IGNORE INTO types VALUES (1, 'cat');
19 | INSERT IGNORE INTO types VALUES (2, 'dog');
20 | INSERT IGNORE INTO types VALUES (3, 'lizard');
21 | INSERT IGNORE INTO types VALUES (4, 'snake');
22 | INSERT IGNORE INTO types VALUES (5, 'bird');
23 | INSERT IGNORE INTO types VALUES (6, 'hamster');
24 |
25 | INSERT IGNORE INTO owners VALUES (1, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023');
26 | INSERT IGNORE INTO owners VALUES (2, 'Betty', 'Davis', '638 Cardinal Ave.', 'Sun Prairie', '6085551749');
27 | INSERT IGNORE INTO owners VALUES (3, 'Eduardo', 'Rodriquez', '2693 Commerce St.', 'McFarland', '6085558763');
28 | INSERT IGNORE INTO owners VALUES (4, 'Harold', 'Davis', '563 Friendly St.', 'Windsor', '6085553198');
29 | INSERT IGNORE INTO owners VALUES (5, 'Peter', 'McTavish', '2387 S. Fair Way', 'Madison', '6085552765');
30 | INSERT IGNORE INTO owners VALUES (6, 'Jean', 'Coleman', '105 N. Lake St.', 'Monona', '6085552654');
31 | INSERT IGNORE INTO owners VALUES (7, 'Jeff', 'Black', '1450 Oak Blvd.', 'Monona', '6085555387');
32 | INSERT IGNORE INTO owners VALUES (8, 'Maria', 'Escobito', '345 Maple St.', 'Madison', '6085557683');
33 | INSERT IGNORE INTO owners VALUES (9, 'David', 'Schroeder', '2749 Blackhawk Trail', 'Madison', '6085559435');
34 | INSERT IGNORE INTO owners VALUES (10, 'Carlos', 'Estaban', '2335 Independence La.', 'Waunakee', '6085555487');
35 |
36 | INSERT IGNORE INTO pets VALUES (1, 'Leo', '2000-09-07', 1, 1);
37 | INSERT IGNORE INTO pets VALUES (2, 'Basil', '2002-08-06', 6, 2);
38 | INSERT IGNORE INTO pets VALUES (3, 'Rosy', '2001-04-17', 2, 3);
39 | INSERT IGNORE INTO pets VALUES (4, 'Jewel', '2000-03-07', 2, 3);
40 | INSERT IGNORE INTO pets VALUES (5, 'Iggy', '2000-11-30', 3, 4);
41 | INSERT IGNORE INTO pets VALUES (6, 'George', '2000-01-20', 4, 5);
42 | INSERT IGNORE INTO pets VALUES (7, 'Samantha', '1995-09-04', 1, 6);
43 | INSERT IGNORE INTO pets VALUES (8, 'Max', '1995-09-04', 1, 6);
44 | INSERT IGNORE INTO pets VALUES (9, 'Lucky', '1999-08-06', 5, 7);
45 | INSERT IGNORE INTO pets VALUES (10, 'Mulligan', '1997-02-24', 2, 8);
46 | INSERT IGNORE INTO pets VALUES (11, 'Freddy', '2000-03-09', 5, 9);
47 | INSERT IGNORE INTO pets VALUES (12, 'Lucky', '2000-06-24', 2, 10);
48 | INSERT IGNORE INTO pets VALUES (13, 'Sly', '2002-06-08', 1, 10);
49 |
50 | INSERT IGNORE INTO visits VALUES (1, 7, '1996-03-04', 'rabies shot');
51 | INSERT IGNORE INTO visits VALUES (2, 8, '1996-03-04', 'rabies shot');
52 | INSERT IGNORE INTO visits VALUES (3, 8, '1996-06-04', 'neutered');
53 | INSERT IGNORE INTO visits VALUES (4, 7, '1996-09-04', 'spayed');
54 |
--------------------------------------------------------------------------------
/src/main/resources/db/petclinic_tomcat_all.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | factory
12 | org.apache.commons.dbcp.BasicDataSourceFactory
13 |
14 |
15 |
16 | driverClassName
17 | org.hsqldb.jdbcDriver
18 |
19 |
20 | url
21 | jdbc:hsqldb:hsql://localhost:9001
22 |
23 |
24 | username
25 | sa
26 |
27 |
28 |
29 | maxActive
30 | 50
31 |
32 |
33 | maxIdle
34 | 10
35 |
36 |
37 | maxWait
38 | 10000
39 |
40 |
41 | removeAbandoned
42 | true
43 |
44 |
45 | removeAbandonedTimeout
46 | 60
47 |
48 |
49 | logAbandoned
50 | true
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | factory
59 | org.apache.commons.dbcp.BasicDataSourceFactory
60 |
61 |
62 |
63 | driverClassName
64 | org.gjt.mm.mysql.Driver
65 |
66 |
72 |
73 | url
74 | jdbc:mysql://localhost:3306/petclinic?autoReconnect=true
75 |
76 |
77 | username
78 | pc
79 |
80 |
81 | password
82 | pc
83 |
84 |
85 |
86 | maxActive
87 | 50
88 |
89 |
90 | maxIdle
91 | 10
92 |
93 |
94 | maxWait
95 | 10000
96 |
97 |
98 | removeAbandoned
99 | true
100 |
101 |
102 | removeAbandonedTimeout
103 | 60
104 |
105 |
106 | logAbandoned
107 | true
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/src/main/resources/jdbc.properties:
--------------------------------------------------------------------------------
1 | # Properties file with JDBC and JPA settings.
2 | #
3 | # Applied by from
4 | # various application context XML files (e.g., "applicationContext-*.xml").
5 | # Targeted at system administrators, to avoid touching the context XML files.
6 |
7 |
8 | #-------------------------------------------------------------------------------
9 | # Common Settings
10 |
11 | hibernate.generate_statistics=true
12 | hibernate.show_sql=true
13 | jpa.showSql=true
14 |
15 |
16 | #-------------------------------------------------------------------------------
17 | # HSQL Settings
18 |
19 | # jdbc.driverClassName=org.hsqldb.jdbcDriver
20 | # jdbc.url=jdbc:hsqldb:mem:petclinic
21 | # jdbc.username=sa
22 | # jdbc.password=
23 |
24 | # # Properties that control the population of schema and data for a new data source
25 | # jdbc.initLocation=classpath:db/hsqldb/initDB.txt
26 | # jdbc.dataLocation=classpath:db/hsqldb/populateDB.txt
27 |
28 | # # Property that determines which Hibernate dialect to use
29 | # # (only applied with "applicationContext-hibernate.xml")
30 | # hibernate.dialect=org.hibernate.dialect.HSQLDialect
31 |
32 | # # Property that determines which JPA DatabasePlatform to use with TopLink Essentials
33 | # jpa.databasePlatform=org.springframework.samples.petclinic.toplink.EssentialsHSQLPlatformWithNativeSequence
34 |
35 | # # Property that determines which database to use with an AbstractJpaVendorAdapter
36 | # jpa.database=HSQL
37 |
38 |
39 | #-------------------------------------------------------------------------------
40 | # MySQL Settings
41 |
42 | jdbc.driverClassName=com.mysql.jdbc.Driver
43 | jdbc.url=jdbc:mysql://localhost:3306/petclinic
44 | jdbc.username=root
45 | jdbc.password=
46 |
47 | # Properties that control the population of schema and data for a new data source
48 | jdbc.initLocation=classpath:db/mysql/initDB.txt
49 | jdbc.dataLocation=classpath:db/mysql/populateDB.txt
50 |
51 | # Property that determines which Hibernate dialect to use
52 | # (only applied with "applicationContext-hibernate.xml")
53 | hibernate.dialect=org.hibernate.dialect.MySQLDialect
54 |
55 | # Property that determines which JPA DatabasePlatform to use with TopLink Essentials
56 | jpa.databasePlatform=oracle.toplink.essentials.platform.database.MySQL4Platform
57 |
58 | # Property that determines which database to use with an AbstractJpaVendorAdapter
59 | jpa.database=MYSQL
60 |
--------------------------------------------------------------------------------
/src/main/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | # For JBoss: Avoid to setup Log4J outside $JBOSS_HOME/server/default/deploy/log4j.xml!
2 | # For all other servers: Comment out the Log4J listener in web.xml to activate Log4J.
3 | log4j.rootLogger=INFO, stdout, logfile
4 |
5 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
6 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
7 | log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
8 |
9 | log4j.appender.logfile=org.apache.log4j.RollingFileAppender
10 | log4j.appender.logfile.File=${petclinic.root}/WEB-INF/petclinic.log
11 | log4j.appender.logfile.MaxFileSize=512KB
12 | # Keep three backup files.
13 | log4j.appender.logfile.MaxBackupIndex=3
14 | # Pattern to output: date priority [category] - message
15 | log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
16 | log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
17 |
18 | log4j.logger.org.springframework.samples.petclinic.aspects=DEBUG
19 |
--------------------------------------------------------------------------------
/src/main/resources/messages.properties:
--------------------------------------------------------------------------------
1 | welcome=Welcome
2 | required=is required
3 | notFound=has not been found
4 | duplicate=is already in use
5 | nonNumeric=must be all numeric
6 | duplicateFormSubmission=Duplicate form submission is not allowed
7 | typeMismatch.date=invalid date
8 | typeMismatch.birthDate=invalid date
9 |
--------------------------------------------------------------------------------
/src/main/resources/messages_de.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nicksieger/refactoring-to-rails/6fa63e5e35b3ab054f8f3008689b44d267387db7/src/main/resources/messages_de.properties
--------------------------------------------------------------------------------
/src/main/resources/messages_en.properties:
--------------------------------------------------------------------------------
1 | # This file is intentionally empty. Message look-ups will fall back to the default "messages.properties" file.
--------------------------------------------------------------------------------
/src/main/resources/petclinic.hbm.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/samples/petclinic/OwnerTests.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic;
2 |
3 | import static org.junit.Assert.assertEquals;
4 | import static org.junit.Assert.assertNull;
5 |
6 | import org.junit.Test;
7 |
8 | /**
9 | * JUnit test for the {@link Owner} class.
10 | *
11 | * @author Ken Krebs
12 | */
13 | public class OwnerTests {
14 |
15 | @Test
16 | public void testHasPet() {
17 | Owner owner = new Owner();
18 | Pet fido = new Pet();
19 | fido.setName("Fido");
20 | assertNull(owner.getPet("Fido"));
21 | assertNull(owner.getPet("fido"));
22 | owner.addPet(fido);
23 | assertEquals(fido, owner.getPet("Fido"));
24 | assertEquals(fido, owner.getPet("fido"));
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/samples/petclinic/hibernate/HibernateClinicTests.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic.hibernate;
2 |
3 | import org.springframework.samples.petclinic.AbstractClinicTests;
4 | import org.springframework.test.annotation.DirtiesContext;
5 | import org.springframework.test.context.ContextConfiguration;
6 |
7 | /**
8 | *
9 | * Integration tests for the {@link HibernateClinic} implementation.
10 | *
11 | *
12 | * "HibernateClinicTests-context.xml" determines the actual beans to test.
13 | *
14 | *
15 | * @author Juergen Hoeller
16 | * @author Sam Brannen
17 | */
18 | @ContextConfiguration
19 | @DirtiesContext
20 | public class HibernateClinicTests extends AbstractClinicTests {
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/samples/petclinic/jdbc/SimpleJdbcClinicTests.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic.jdbc;
2 |
3 | import org.springframework.samples.petclinic.AbstractClinicTests;
4 | import org.springframework.test.annotation.DirtiesContext;
5 | import org.springframework.test.context.ContextConfiguration;
6 |
7 | /**
8 | *
9 | * Integration tests for the {@link SimpleJdbcClinic} implementation.
10 | *
11 | *
12 | * "SimpleJdbcClinicTests-context.xml" determines the actual beans to test.
13 | *
14 | *
15 | * @author Thomas Risberg
16 | */
17 | @ContextConfiguration
18 | @DirtiesContext
19 | public class SimpleJdbcClinicTests extends AbstractClinicTests {
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/samples/petclinic/jpa/EntityManagerClinicTests.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic.jpa;
2 |
3 | import java.util.List;
4 |
5 | import org.springframework.samples.petclinic.aspects.UsageLogAspect;
6 |
7 | /**
8 | *
9 | * Tests for the DAO variant based on the shared EntityManager approach. Uses
10 | * TopLink Essentials (the reference implementation) for testing.
11 | *
12 | *
13 | * Specifically tests usage of an orm.xml
file, loaded by the
14 | * persistence provider through the Spring-provided persistence unit root URL.
15 | *
16 | *
17 | * @author Rod Johnson
18 | * @author Juergen Hoeller
19 | */
20 | public class EntityManagerClinicTests extends AbstractJpaClinicTests {
21 |
22 | private UsageLogAspect usageLogAspect;
23 |
24 | public void setUsageLogAspect(UsageLogAspect usageLogAspect) {
25 | this.usageLogAspect = usageLogAspect;
26 | }
27 |
28 | @Override
29 | protected String[] getConfigPaths() {
30 | return new String[] {
31 | "applicationContext-jpaCommon.xml",
32 | "applicationContext-toplinkAdapter.xml",
33 | "applicationContext-entityManager.xml"
34 | };
35 | }
36 |
37 | public void testUsageLogAspectIsInvoked() {
38 | String name1 = "Schuurman";
39 | String name2 = "Greenwood";
40 | String name3 = "Leau";
41 |
42 | assertTrue(this.clinic.findOwners(name1).isEmpty());
43 | assertTrue(this.clinic.findOwners(name2).isEmpty());
44 |
45 | List namesRequested = this.usageLogAspect.getNamesRequested();
46 | assertTrue(namesRequested.contains(name1));
47 | assertTrue(namesRequested.contains(name2));
48 | assertFalse(namesRequested.contains(name3));
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/samples/petclinic/jpa/HibernateEntityManagerClinicTests.java:
--------------------------------------------------------------------------------
1 | package org.springframework.samples.petclinic.jpa;
2 |
3 | /**
4 | *
5 | * Tests for the DAO variant based on the shared EntityManager approach, using
6 | * Hibernate EntityManager for testing instead of the reference implementation.
7 | *
8 | *
9 | * Specifically tests usage of an orm.xml
file, loaded by the
10 | * persistence provider through the Spring-provided persistence unit root URL.
11 | *
12 | *
13 | * @author Juergen Hoeller
14 | */
15 | public class HibernateEntityManagerClinicTests extends EntityManagerClinicTests {
16 |
17 | @Override
18 | protected String[] getConfigPaths() {
19 | return new String[] {
20 | "applicationContext-jpaCommon.xml",
21 | "applicationContext-hibernateAdapter.xml",
22 | "applicationContext-entityManager.xml"
23 | };
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/samples/petclinic/jpa/OpenJpaEntityManagerClinicTests.java:
--------------------------------------------------------------------------------
1 |
2 | package org.springframework.samples.petclinic.jpa;
3 |
4 | /**
5 | *
6 | * Tests for the DAO variant based on the shared EntityManager approach, using
7 | * Apache OpenJPA for testing instead of the reference implementation.
8 | *
9 | *
10 | * Specifically tests usage of an orm.xml
file, loaded by the
11 | * persistence provider through the Spring-provided persistence unit root URL.
12 | *
13 | *
14 | * @author Juergen Hoeller
15 | */
16 | public class OpenJpaEntityManagerClinicTests extends EntityManagerClinicTests {
17 |
18 | @Override
19 | protected String[] getConfigPaths() {
20 | return new String[] {
21 | "applicationContext-jpaCommon.xml",
22 | "applicationContext-openJpaAdapter.xml",
23 | "applicationContext-entityManager.xml"
24 | };
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/test/java/org/springframework/samples/petclinic/web/VisitsAtomViewTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2002-2009 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.samples.petclinic.web;
18 |
19 | import java.util.ArrayList;
20 | import java.util.Date;
21 | import java.util.HashMap;
22 | import java.util.List;
23 | import java.util.Map;
24 |
25 | import com.sun.syndication.feed.atom.Entry;
26 | import com.sun.syndication.feed.atom.Feed;
27 | import static org.junit.Assert.assertEquals;
28 | import static org.junit.Assert.assertNotNull;
29 | import org.junit.Before;
30 | import org.junit.Test;
31 |
32 | import org.springframework.samples.petclinic.Pet;
33 | import org.springframework.samples.petclinic.PetType;
34 | import org.springframework.samples.petclinic.Visit;
35 |
36 | /**
37 | * @author Arjen Poutsma
38 | */
39 | public class VisitsAtomViewTest {
40 |
41 | private VisitsAtomView visitView;
42 |
43 | private Map model;
44 |
45 | private Feed feed;
46 |
47 | @Before
48 | public void setUp() {
49 | visitView = new VisitsAtomView();
50 | PetType dog = new PetType();
51 | dog.setName("dog");
52 | Pet bello = new Pet();
53 | bello.setName("Bello");
54 | bello.setType(dog);
55 | Visit belloVisit = new Visit();
56 | belloVisit.setPet(bello);
57 | belloVisit.setDate(new Date(2009, 0, 1));
58 | belloVisit.setDescription("Bello visit");
59 | Pet wodan = new Pet();
60 | wodan.setName("Wodan");
61 | wodan.setType(dog);
62 | Visit wodanVisit = new Visit();
63 | wodanVisit.setPet(wodan);
64 | wodanVisit.setDate(new Date(2009, 0, 2));
65 | wodanVisit.setDescription("Wodan visit");
66 | List visits = new ArrayList();
67 | visits.add(belloVisit);
68 | visits.add(wodanVisit);
69 |
70 | model = new HashMap();
71 | model.put("visits", visits);
72 | feed = new Feed();
73 |
74 | }
75 |
76 | @Test
77 | public void buildFeedMetadata() {
78 | visitView.buildFeedMetadata(model, feed, null);
79 |
80 | assertNotNull("No id set", feed.getId());
81 | assertNotNull("No title set", feed.getTitle());
82 | assertEquals("Invalid update set", new Date(2009, 0, 2), feed.getUpdated());
83 | }
84 |
85 | @Test
86 | public void buildFeedEntries() throws Exception {
87 | List entries = visitView.buildFeedEntries(model, null, null);
88 | assertEquals("Invalid amount of entries", 2, entries.size());
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/test/resources/log4j.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/test/resources/org/springframework/samples/petclinic/AbstractClinicTests-context.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/test/resources/org/springframework/samples/petclinic/hibernate/HibernateClinicTests-context.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
12 |
13 |
14 | ${hibernate.dialect}
15 | ${hibernate.show_sql}
16 |
17 |
18 |
19 |
24 |
25 |
26 |
27 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/test/resources/org/springframework/samples/petclinic/jdbc/SimpleJdbcClinicTests-context.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/test/resources/org/springframework/samples/petclinic/jpa/applicationContext-entityManager.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/test/resources/org/springframework/samples/petclinic/jpa/applicationContext-hibernateAdapter.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/test/resources/org/springframework/samples/petclinic/jpa/applicationContext-jpaCommon.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
38 |
39 |
--------------------------------------------------------------------------------
/src/test/resources/org/springframework/samples/petclinic/jpa/applicationContext-openJpaAdapter.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/test/resources/org/springframework/samples/petclinic/jpa/applicationContext-toplinkAdapter.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/test/performance/browsing_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 | require 'rails/performance_test_help'
3 |
4 | # Profiling results for each test method are written to tmp/performance.
5 | class BrowsingTest < ActionDispatch::PerformanceTest
6 | def test_homepage
7 | get '/'
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | ENV["RAILS_ENV"] = "test"
2 | require File.expand_path('../../config/environment', __FILE__)
3 | require 'rails/test_help'
4 |
5 | class ActiveSupport::TestCase
6 | # Add more helper methods to be used by all tests here...
7 | end
8 |
--------------------------------------------------------------------------------
/vendor/plugins/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nicksieger/refactoring-to-rails/6fa63e5e35b3ab054f8f3008689b44d267387db7/vendor/plugins/.gitkeep
--------------------------------------------------------------------------------