Skip to content

Commit dba383b

Browse files
committed
Add sample Shell application for Spring Petclinic
1 parent 741b2c5 commit dba383b

File tree

10 files changed

+387
-0
lines changed

10 files changed

+387
-0
lines changed

pom.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@
6565
<jakarta.el.version>4.0.2</jakarta.el.version>
6666
<log4j.version>2.25.2</log4j.version>
6767

68+
<!-- samples dependencies -->
69+
<h2-database.version>2.4.240</h2-database.version>
70+
6871
<!-- documentation dependencies -->
6972
<antora-maven-plugin.version>1.0.0-alpha.5</antora-maven-plugin.version>
7073
<antora-component-version-maven-plugin.version>0.0.4</antora-component-version-maven-plugin.version>

spring-shell-samples/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
<modules>
1717
<module>spring-shell-sample-hello-world</module>
18+
<module>spring-shell-sample-petclinic</module>
1819
<!-- <module>spring-shell-sample-hello-world-spring-boot</module>-->
1920
<!-- <module>spring-shell-sample-catalog</module>-->
2021
<!-- <module>spring-shell-sample-commands</module>-->
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<parent>
6+
<groupId>org.springframework.shell</groupId>
7+
<artifactId>spring-shell-samples</artifactId>
8+
<version>4.0.0-SNAPSHOT</version>
9+
</parent>
10+
11+
<artifactId>spring-shell-sample-petclinic</artifactId>
12+
<name>Spring Shell Samples - Spring PetClinic</name>
13+
<packaging>jar</packaging>
14+
<description>Spring Petclinic Shell application</description>
15+
16+
<dependencies>
17+
<dependency>
18+
<groupId>org.springframework.shell</groupId>
19+
<artifactId>spring-shell-core</artifactId>
20+
<version>${project.parent.version}</version>
21+
</dependency>
22+
<dependency>
23+
<groupId>org.springframework</groupId>
24+
<artifactId>spring-jdbc</artifactId>
25+
<version>${spring-framework.version}</version>
26+
</dependency>
27+
28+
<dependency>
29+
<groupId>org.hibernate.validator</groupId>
30+
<artifactId>hibernate-validator</artifactId>
31+
<version>${hibernate-validator.version}</version>
32+
</dependency>
33+
<dependency>
34+
<groupId>org.glassfish</groupId>
35+
<artifactId>jakarta.el</artifactId>
36+
<version>${jakarta.el.version}</version>
37+
</dependency>
38+
39+
<dependency>
40+
<groupId>com.h2database</groupId>
41+
<artifactId>h2</artifactId>
42+
<version>${h2-database.version}</version>
43+
</dependency>
44+
</dependencies>
45+
46+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright 2025-present 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+
* https://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+
package org.springframework.shell.samples.petclinic;
17+
18+
import org.springframework.context.ApplicationContext;
19+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
20+
import org.springframework.context.annotation.Bean;
21+
import org.springframework.jdbc.core.simple.JdbcClient;
22+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
23+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
24+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
25+
import org.springframework.shell.core.ShellRunner;
26+
import org.springframework.shell.core.command.annotation.EnableCommand;
27+
import org.springframework.shell.samples.petclinic.commands.OwnerDetailsCommand;
28+
import org.springframework.shell.samples.petclinic.commands.OwnersListCommand;
29+
30+
/**
31+
* @author Mahmoud Ben Hassine
32+
*/
33+
@EnableCommand(SpringShellApplication.class)
34+
public class SpringShellApplication {
35+
36+
public static void main(String[] args) throws Exception {
37+
Class<?>[] classes = { SpringShellApplication.class };
38+
ApplicationContext context = new AnnotationConfigApplicationContext(classes);
39+
ShellRunner runner = context.getBean(ShellRunner.class);
40+
runner.run(args);
41+
}
42+
43+
@Bean
44+
public OwnersListCommand ownersCommand(JdbcClient jdbcClient) {
45+
return new OwnersListCommand(jdbcClient);
46+
}
47+
48+
@Bean
49+
public OwnerDetailsCommand ownerDetailsCommand(JdbcClient jdbcClient) {
50+
return new OwnerDetailsCommand(jdbcClient);
51+
}
52+
53+
@Bean
54+
public JdbcClient jdbcClient() {
55+
EmbeddedDatabase database = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)
56+
.addScript("schema.sql")
57+
.addScript("data.sql")
58+
.build();
59+
return JdbcClient.create(database);
60+
}
61+
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2025-present 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+
* https://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+
package org.springframework.shell.samples.petclinic.commands;
17+
18+
import java.io.PrintWriter;
19+
20+
import org.springframework.jdbc.core.DataClassRowMapper;
21+
import org.springframework.jdbc.core.simple.JdbcClient;
22+
import org.springframework.shell.core.command.CommandContext;
23+
import org.springframework.shell.core.command.ExitStatus;
24+
import org.springframework.shell.core.commands.AbstractCommand;
25+
import org.springframework.shell.samples.petclinic.domain.Owner;
26+
27+
/**
28+
* Spring Shell command to show the details of a Pet clinic owner.
29+
*
30+
* @author Mahmoud Ben Hassine
31+
*/
32+
public class OwnerDetailsCommand extends AbstractCommand {
33+
34+
private final JdbcClient jdbcClient;
35+
36+
public OwnerDetailsCommand(JdbcClient jdbcClient) {
37+
super("owner", "Show details of a given owner", "Pet Clinic", "Command to show the details of a given owner");
38+
this.jdbcClient = jdbcClient;
39+
}
40+
41+
@Override
42+
public ExitStatus doExecute(CommandContext commandContext) {
43+
PrintWriter writer = commandContext.terminal().writer();
44+
if (commandContext.arguments().isEmpty()) {
45+
writer.println("Owner ID is required");
46+
writer.println("Usage: owner <ownerId>");
47+
writer.flush();
48+
return ExitStatus.USAGE_ERROR;
49+
}
50+
String ownerId = commandContext.arguments().get(0).value();
51+
Owner owner = this.jdbcClient.sql("SELECT * FROM OWNERS where id = " + ownerId)
52+
.query(new DataClassRowMapper<>(Owner.class))
53+
.single();
54+
writer.println(owner);
55+
writer.flush();
56+
return ExitStatus.OK;
57+
}
58+
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2025-present 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+
* https://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+
package org.springframework.shell.samples.petclinic.commands;
17+
18+
import java.io.PrintWriter;
19+
import java.util.List;
20+
21+
import org.jspecify.annotations.Nullable;
22+
23+
import org.springframework.jdbc.core.DataClassRowMapper;
24+
import org.springframework.jdbc.core.simple.JdbcClient;
25+
import org.springframework.shell.core.command.CommandContext;
26+
import org.springframework.shell.core.command.ExitStatus;
27+
import org.springframework.shell.core.commands.AbstractCommand;
28+
import org.springframework.shell.samples.petclinic.domain.Owner;
29+
30+
/**
31+
* Spring Shell command to list Pet clinic owners.
32+
*
33+
* @author Mahmoud Ben Hassine
34+
*/
35+
public class OwnersListCommand extends AbstractCommand {
36+
37+
private final JdbcClient jdbcClient;
38+
39+
public OwnersListCommand(JdbcClient jdbcClient) {
40+
super("owners", "List owners", "Pet Clinic", "Command to list owners");
41+
this.jdbcClient = jdbcClient;
42+
}
43+
44+
@Override
45+
public ExitStatus doExecute(CommandContext commandContext) {
46+
PrintWriter writer = commandContext.terminal().writer();
47+
List<@Nullable Owner> owners = this.jdbcClient.sql("SELECT id, first_name, last_name FROM OWNERS")
48+
.query(new DataClassRowMapper<>(Owner.class))
49+
.list();
50+
for (Owner owner : owners) {
51+
writer.println(owner);
52+
}
53+
writer.flush();
54+
return ExitStatus.OK;
55+
}
56+
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright 2025-present 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+
* https://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+
package org.springframework.shell.samples.petclinic.domain;
17+
18+
/**
19+
* @author Mahmoud Ben Hassine
20+
*/
21+
public record Owner(int id, String firstName, String lastName) {
22+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
INSERT INTO vets VALUES (default, 'James', 'Carter');
2+
INSERT INTO vets VALUES (default, 'Helen', 'Leary');
3+
INSERT INTO vets VALUES (default, 'Linda', 'Douglas');
4+
INSERT INTO vets VALUES (default, 'Rafael', 'Ortega');
5+
INSERT INTO vets VALUES (default, 'Henry', 'Stevens');
6+
INSERT INTO vets VALUES (default, 'Sharon', 'Jenkins');
7+
8+
INSERT INTO specialties VALUES (default, 'radiology');
9+
INSERT INTO specialties VALUES (default, 'surgery');
10+
INSERT INTO specialties VALUES (default, '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 (default, 'cat');
19+
INSERT INTO types VALUES (default, 'dog');
20+
INSERT INTO types VALUES (default, 'lizard');
21+
INSERT INTO types VALUES (default, 'snake');
22+
INSERT INTO types VALUES (default, 'bird');
23+
INSERT INTO types VALUES (default, 'hamster');
24+
25+
INSERT INTO owners VALUES (default, 'George', 'Franklin', '110 W. Liberty St.', 'Madison', '6085551023');
26+
INSERT INTO owners VALUES (default, 'Betty', 'Davis', '638 Cardinal Ave.', 'Sun Prairie', '6085551749');
27+
INSERT INTO owners VALUES (default, 'Eduardo', 'Rodriquez', '2693 Commerce St.', 'McFarland', '6085558763');
28+
INSERT INTO owners VALUES (default, 'Harold', 'Davis', '563 Friendly St.', 'Windsor', '6085553198');
29+
INSERT INTO owners VALUES (default, 'Peter', 'McTavish', '2387 S. Fair Way', 'Madison', '6085552765');
30+
INSERT INTO owners VALUES (default, 'Jean', 'Coleman', '105 N. Lake St.', 'Monona', '6085552654');
31+
INSERT INTO owners VALUES (default, 'Jeff', 'Black', '1450 Oak Blvd.', 'Monona', '6085555387');
32+
INSERT INTO owners VALUES (default, 'Maria', 'Escobito', '345 Maple St.', 'Madison', '6085557683');
33+
INSERT INTO owners VALUES (default, 'David', 'Schroeder', '2749 Blackhawk Trail', 'Madison', '6085559435');
34+
INSERT INTO owners VALUES (default, 'Carlos', 'Estaban', '2335 Independence La.', 'Waunakee', '6085555487');
35+
36+
INSERT INTO pets VALUES (default, 'Leo', '2010-09-07', 1, 1);
37+
INSERT INTO pets VALUES (default, 'Basil', '2012-08-06', 6, 2);
38+
INSERT INTO pets VALUES (default, 'Rosy', '2011-04-17', 2, 3);
39+
INSERT INTO pets VALUES (default, 'Jewel', '2010-03-07', 2, 3);
40+
INSERT INTO pets VALUES (default, 'Iggy', '2010-11-30', 3, 4);
41+
INSERT INTO pets VALUES (default, 'George', '2010-01-20', 4, 5);
42+
INSERT INTO pets VALUES (default, 'Samantha', '2012-09-04', 1, 6);
43+
INSERT INTO pets VALUES (default, 'Max', '2012-09-04', 1, 6);
44+
INSERT INTO pets VALUES (default, 'Lucky', '2011-08-06', 5, 7);
45+
INSERT INTO pets VALUES (default, 'Mulligan', '2007-02-24', 2, 8);
46+
INSERT INTO pets VALUES (default, 'Freddy', '2010-03-09', 5, 9);
47+
INSERT INTO pets VALUES (default, 'Lucky', '2010-06-24', 2, 10);
48+
INSERT INTO pets VALUES (default, 'Sly', '2012-06-08', 1, 10);
49+
50+
INSERT INTO visits VALUES (default, 7, '2013-01-01', 'rabies shot');
51+
INSERT INTO visits VALUES (default, 8, '2013-01-02', 'rabies shot');
52+
INSERT INTO visits VALUES (default, 8, '2013-01-03', 'neutered');
53+
INSERT INTO visits VALUES (default, 7, '2013-01-04', 'spayed');
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<configuration>
2+
3+
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
4+
<layout class="ch.qos.logback.classic.PatternLayout">
5+
<Pattern>
6+
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
7+
</Pattern>
8+
</layout>
9+
</appender>
10+
11+
<root level="info">
12+
<appender-ref ref="CONSOLE"/>
13+
</root>
14+
15+
</configuration>

0 commit comments

Comments
 (0)