Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# JoyOfCoding repository instructions

## Build, test, and lint

- Use the Maven Wrapper from the repository root. The CI build is `./mvnw --batch-mode verify --file pom.xml`; it runs unit tests, integration tests, and the configured JaCoCo reporting. CI runs this with JDK 21 and 24. The reactor enforces Java 21, except `projects-parent/projects`, which deliberately compiles Java 8-compatible APIs.
- Run a module's unit tests with its required reactor dependencies: `./mvnw --batch-mode -pl <module> -am test`. For one test or method, add `-Dtest=FullyQualifiedTestClass` or `-Dtest=FullyQualifiedTestClass#method`; for example, `./mvnw --batch-mode -pl projects-parent/projects -am -Dtest=edu.pdx.cs.joy.InvokeMainTest test`.
- Integration tests live in `src/it/java`, are compiled separately, and run through Failsafe during `verify`. Run one with `./mvnw --batch-mode -pl web -am -Dit.test=edu.pdx.cs.joy.servlets.MovieDatabaseServletIT verify`. The `web` module starts Jetty on port 8080 for its integration-test lifecycle.
- The project does not have one reactor-wide lint phase. The reference project modules under `projects-parent/originals-parent` bind Checkstyle; run it for a changed reference project with `./mvnw --batch-mode -pl projects-parent/originals-parent/<project> checkstyle:check`. Generate the Maven documentation site with `./mvnw --batch-mode site --file pom.xml`.

## Architecture

- This is a Maven multi-module codebase for "The Joy of Coding" course. The root reactor builds `examples`, `web`, `family`, `grader`, and `projects-parent`.
- `projects-parent/projects` is the shared course API: abstract domain types, parsers/dumpers, XML helpers, and test utilities used by the course projects. Keep it Java 8-compatible because Android projects consume it.
- `projects-parent/originals-parent` contains the reference implementations of student assignments (airline, appointment book, phone bill, student, and kata, including web variants). `projects-parent/archetypes-parent` packages the corresponding student project templates. Template source is under each archetype's `src/main/resources/archetype-resources`; its `META-INF/maven/archetype-metadata.xml` controls which files are filtered and packaged.
- `examples` contains independent Java examples, while `family` is a family-tree application and `grader` is the course grading/gradebook tooling. The grader produces a shaded executable with `edu.pdx.cs.joy.grader.GraderTools` as its entry point.
- `web` packages a WAR. Traditional servlet endpoints and URL mappings are declared in `web/src/main/webapp/WEB-INF/web.xml`; RESTEasy/Guice REST services are registered in `edu.pdx.cs.joy.di.RestModule` and served beneath `/rest`.

## Codebase conventions

- Use JUnit Jupiter for tests, with Hamcrest matchers commonly used for expressive assertions. Keep fast tests in `src/test/java`; put tests that need external services, Jetty, or mail fixtures in `src/it/java` and name them `*IT`.
- Course-project command-line tests should extend `edu.pdx.cs.joy.InvokeMainTestCase` from the shared `projects` test JAR. Its default invocation rejects mutable static fields and captures standard output/error; use its explicit `invokeMainAllowingMutableStaticFields` only when that behavior is intentional.
- Reference projects are built with the `grader` profile, which applies API-doclet validation and JaCoCo thresholds (at least 75% instruction coverage and no missed classes). Preserve the original project and archetype-template distinction when changing assignment-facing behavior.
8 changes: 4 additions & 4 deletions examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
<parent>
<artifactId>joy</artifactId>
<groupId>io.github.davidwhitlock.joy</groupId>
<version>1.3.0</version>
<version>1.3.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>examples</artifactId>
<name>examples</name>
<version>1.4.1</version>
<version>1.4.2-SNAPSHOT</version>
<url>https://www.cs.pdx.edu/~whitlock</url>
<dependencies>
<dependency>
<groupId>io.github.davidwhitlock.joy</groupId>
<artifactId>projects</artifactId>
<version>3.0.5</version>
<version>3.0.6-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
Expand Down Expand Up @@ -45,7 +45,7 @@
<dependency>
<groupId>io.github.davidwhitlock.joy</groupId>
<artifactId>projects</artifactId>
<version>3.0.5</version>
<version>3.0.6-SNAPSHOT</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
Expand Down
40 changes: 0 additions & 40 deletions examples/src/resources/java/edu/pdx/cs410J/xml/phonebook.dtd

This file was deleted.

8 changes: 4 additions & 4 deletions family/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,25 @@
<parent>
<artifactId>joy</artifactId>
<groupId>io.github.davidwhitlock.joy</groupId>
<version>1.3.0</version>
<version>1.3.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>family</artifactId>
<packaging>jar</packaging>
<version>1.1.7</version>
<version>1.1.8-SNAPSHOT</version>
<name>Family Tree Application</name>
<description>An Family Tree application for The Joy of Coding</description>
<url>https://www.cs.pdx.edu/~whitlock</url>
<dependencies>
<dependency>
<groupId>io.github.davidwhitlock.joy</groupId>
<artifactId>projects</artifactId>
<version>3.0.5</version>
<version>3.0.6-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.github.davidwhitlock.joy</groupId>
<artifactId>examples</artifactId>
<version>1.4.1</version>
<version>1.4.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
Expand Down
6 changes: 3 additions & 3 deletions grader/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<parent>
<artifactId>joy</artifactId>
<groupId>io.github.davidwhitlock.joy</groupId>
<version>1.3.0</version>
<version>1.3.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>grader</artifactId>
Expand Down Expand Up @@ -34,7 +34,7 @@
<dependency>
<groupId>io.github.davidwhitlock.joy</groupId>
<artifactId>projects</artifactId>
<version>3.0.5</version>
<version>3.0.6-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.opencsv</groupId>
Expand Down Expand Up @@ -64,7 +64,7 @@
<dependency>
<groupId>com.icegreen</groupId>
<artifactId>greenmail</artifactId>
<version>2.0.1</version>
<version>2.1.12</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,12 @@
import com.icegreen.greenmail.user.GreenMailUser;
import com.icegreen.greenmail.util.GreenMail;
import com.icegreen.greenmail.util.ServerSetup;
import com.sun.mail.util.MailSSLSocketFactory;
import jakarta.mail.*;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;

import java.security.GeneralSecurityException;
import java.util.Properties;

public class GreenmailIntegrationTestCase {
Expand Down Expand Up @@ -78,12 +76,10 @@ protected Folder openFolder(Store store, String folderName) throws MessagingExce
return folder;
}

protected Store connectToIMAPServer() throws GeneralSecurityException, MessagingException {
protected Store connectToIMAPServer() throws MessagingException {
Properties props = new Properties();

MailSSLSocketFactory socketFactory = new MailSSLSocketFactory();
socketFactory.setTrustedHosts(new String[]{"127.0.0.1", "localhost"});
props.put("mail.imaps.ssl.socketFactory", socketFactory);
props.put("mail.imaps.ssl.trust", emailServerHost);
props.put("mail.imaps.ssl.checkserveridentity", "false");

Session session = Session.getInstance(props, null);
Store store = session.getStore("imaps");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalToIgnoringCase;
import static org.mockito.Mockito.*;

public class POASubmissionsDownloaderIT extends GreenmailIntegrationTestCase {
Expand Down Expand Up @@ -88,7 +89,7 @@ private void assertEmailIsProperlyProcessed(String subject, String poa, String s
POASubmission submission = captor.getValue();
assertThat(submission.getSubject(), equalTo(subject));
assertThat(submission.getContent(), equalTo(poa));
assertThat(submission.getContentType(), equalTo(contentType));
assertThat(submission.getContentType(), equalToIgnoringCase(contentType));
assertThat(submission.getSubmitter(), equalTo(sender));

ArgumentCaptor<StatusMessage> statusCaptor = ArgumentCaptor.forClass(StatusMessage.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package edu.pdx.cs.joy.grader;

import com.google.common.annotations.VisibleForTesting;
import com.sun.mail.util.MailSSLSocketFactory;
import jakarta.mail.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
Expand Down Expand Up @@ -280,17 +278,16 @@ private Store connectToIMAPServer() {
Properties props = new Properties();

if (this.trustLocalhostSSL) {
MailSSLSocketFactory socketFactory= new MailSSLSocketFactory();
socketFactory.setTrustedHosts("127.0.0.1", "localhost");
props.put("mail.imaps.ssl.socketFactory", socketFactory);
props.put("mail.imaps.ssl.trust", "127.0.0.1 localhost");
props.put("mail.imaps.ssl.checkserveridentity", "false");
}

Session session = Session.getInstance(props, null);
Store store = session.getStore("imaps");
store.connect(this.emailServerHostName, this.emailServerPort, this.userName, this.password);
return store;

} catch (MessagingException | GeneralSecurityException ex) {
} catch (MessagingException ex) {
throw new IllegalStateException("While connecting to " + this.emailServerHostName + ":" + this.emailServerPort, ex);
}
}
Expand Down
Empty file.
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.davidwhitlock.joy</groupId>
<version>1.3.0</version>
<version>1.3.1-SNAPSHOT</version>
<artifactId>joy</artifactId>
<packaging>pom</packaging>
<name>Java Example Code</name>
Expand Down Expand Up @@ -94,7 +94,7 @@
<jacoco.min.instruction.covered.ratio>0.75</jacoco.min.instruction.covered.ratio>
<jacoco.max.missed.classes>0</jacoco.max.missed.classes>

<grader.version>1.6.0</grader.version>
<grader.version>1.6.1-SNAPSHOT</grader.version>
</properties>
<dependencies>
<dependency>
Expand Down
4 changes: 2 additions & 2 deletions projects-parent/archetypes-parent/airline-archetype/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
<parent>
<artifactId>archetypes-parent</artifactId>
<groupId>io.github.davidwhitlock.joy</groupId>
<version>2.2.6</version>
<version>2.2.7-SNAPSHOT</version>
</parent>
<artifactId>airline-archetype</artifactId>
<version>2.2.6</version>
<version>2.2.7-SNAPSHOT</version>
<packaging>maven-archetype</packaging>

<name>airline-archetype</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<parent>
<artifactId>joy</artifactId>
<groupId>io.github.davidwhitlock.joy</groupId>
<version>1.3.0</version>
<version>1.3.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>${groupId}</groupId>
Expand Down Expand Up @@ -32,12 +32,12 @@
<dependency>
<groupId>io.github.davidwhitlock.joy</groupId>
<artifactId>projects</artifactId>
<version>3.0.5</version>
<version>3.0.6-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.github.davidwhitlock.joy</groupId>
<artifactId>projects</artifactId>
<version>3.0.5</version>
<version>3.0.6-SNAPSHOT</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
<parent>
<artifactId>archetypes-parent</artifactId>
<groupId>io.github.davidwhitlock.joy</groupId>
<version>2.2.6</version>
<version>2.2.7-SNAPSHOT</version>
</parent>
<artifactId>airline-web-archetype</artifactId>
<version>3.1.0</version>
<version>3.1.1-SNAPSHOT</version>
<packaging>maven-archetype</packaging>

<name>airline-web-archetype</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<parent>
<artifactId>joy</artifactId>
<groupId>io.github.davidwhitlock.joy</groupId>
<version>1.3.0</version>
<version>1.3.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>${groupId}</groupId>
Expand All @@ -21,17 +21,17 @@
<dependency>
<groupId>io.github.davidwhitlock.joy</groupId>
<artifactId>projects</artifactId>
<version>3.0.5</version>
<version>3.0.6-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.github.davidwhitlock.joy</groupId>
<artifactId>examples</artifactId>
<version>1.4.1</version>
<version>1.4.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.github.davidwhitlock.joy</groupId>
<artifactId>projects</artifactId>
<version>3.0.5</version>
<version>3.0.6-SNAPSHOT</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
Expand Down
4 changes: 2 additions & 2 deletions projects-parent/archetypes-parent/apptbook-archetype/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
<parent>
<artifactId>archetypes-parent</artifactId>
<groupId>io.github.davidwhitlock.joy</groupId>
<version>2.2.6</version>
<version>2.2.7-SNAPSHOT</version>
</parent>
<artifactId>apptbook-archetype</artifactId>
<version>2.2.6</version>
<version>2.2.7-SNAPSHOT</version>
<packaging>maven-archetype</packaging>

<name>apptbook-archetype</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<parent>
<artifactId>joy</artifactId>
<groupId>io.github.davidwhitlock.joy</groupId>
<version>1.3.0</version>
<version>1.3.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>${groupId}</groupId>
Expand Down Expand Up @@ -32,12 +32,12 @@
<dependency>
<groupId>io.github.davidwhitlock.joy</groupId>
<artifactId>projects</artifactId>
<version>3.0.5</version>
<version>3.0.6-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.github.davidwhitlock.joy</groupId>
<artifactId>projects</artifactId>
<version>3.0.5</version>
<version>3.0.6-SNAPSHOT</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
Expand Down

This file was deleted.

Loading
Loading