diff --git a/README.md b/README.md index 59166bab..168e5ae3 100644 --- a/README.md +++ b/README.md @@ -6,26 +6,42 @@ ## Welcome -Advanced Software Construction provides you with the experience and skills necessary to use a modern programming language in an advanced development environment to design, test, and build a large multi-user application. Your application will have a client frontend program that communicates, over the network, with a centralized backend server. - -The content for this course is represented by the following parts. +Advanced software construction (CS240) helps you become responsible software engineers who continually improve your ability to frame, design, build, and test reliable systems. You will work with object-oriented design, network protocols, distributed services, and databases, while emphasizing long-term code quality, correctness, and responsibility for software others depend on—all while reflecting an eternal stewardship and concern for humanity. - [Syllabus](instruction/syllabus/syllabus.md) - Course policies -- [Instruction](instruction/modules.md) - Course topics - [Chess](chess/chess.md) - Instructions for building your application - [Pet Shop](petshop/petshop.md) - Demonstration application - [📅 Schedule: Dr. Wilkerson](schedule/spring2026-wilkerson.md) + ## Outcomes -By the end of the course you should have experienced the following outcomes. +You will learn to: + +- **Frame** software engineering problems by clarifying system purpose, constraints, and responsibilities, demonstrating both sound technical judgment and a sense of ownership for the long-term impact of software others depend on. +- **Explore** object-oriented frameworks, network protocols, distributed services, and databases with curiosity and discipline, developing accurate mental models while valuing learning as essential to responsible engineering practice. +- **Design** software systems using object-oriented principles and clear interfaces that support reliability and maintainability, motivated by care for future users, collaborators, and the evolution of the system over time. +- **Build** distributed applications that faithfully translate design intent into readable, testable implementations, showing diligence and integrity in the quality of code produced. +- **Test** software systems systematically to validate behavior and uncover failure modes, valuing evidence, honesty, and accountability as foundations of trustworthy software. + +## Culminating Experience + +You will build a Semester long project that builds a full stack application that has been rigorously tested. The project will have the following characteristics. + +1. Documented and tested distributed architecture +1. Account creation and authentication +1. Multiple user roles +1. Enforcement of role restrictions +1. Creation and joining of groups +1. Real-time peer interaction over a network +1. Persistent storage of data +1. Robust handling of failure cases + +## Checkpoints + +As you work on your culminating experience project you will pass through a series of checkpoints that demonstrate your increasing mastery. -- Learn to construct a medium-scale server program with data persistence in a principled way by applying relevant engineering techniques such as up-front design, quality code construction, unit testing, assertions, and error handling. -- Learn and apply basic software design principles such as single responsibility, low coupling, avoidance of code duplication and information/data hiding to create modular code. -- Learn and apply the basics of relational database design, modeling and programmatic access. -- Learn and apply basic security principles and concepts. -- Learn to validate a program’s behavior against its specification using testing practices. -- Use modern software tools including integrated development environments, testing frameworks, debuggers, version control, and documentation processing tools. +![checkpoints.jpg](checkpoints.jpg) ## Technologies @@ -34,11 +50,10 @@ The course covers a full software stack of technologies and topics. - Command console - Java - HTTP -- Web Services -- Data Services demonstrated with MySQL +- Web services +- Data services demonstrated with MySQL - Realtime peer to peer interaction with WebSocket - Security - Testing - Application design -_Image Source: Dall-E_ diff --git a/checkpoints.jpg b/checkpoints.jpg new file mode 100644 index 00000000..b12a274c Binary files /dev/null and b/checkpoints.jpg differ diff --git a/chess/1-chess-game/chess-game.md b/chess/1-chess-game/chess-game.md index dfbb0375..4277da97 100644 --- a/chess/1-chess-game/chess-game.md +++ b/chess/1-chess-game/chess-game.md @@ -12,6 +12,7 @@ Complete the [Getting Started](getting-started.md) instructions before working o ## Code Class Structure ```mermaid +%%{init: { 'theme': 'neutral', 'themeVariables': { 'lineColor': '#000000', 'primaryTextColor': '#000000', 'actorBorder': '#000000', 'participantBorder': '#000000', 'noteBorderColor': '#000000' } }}%% classDiagram diff --git a/chess/3-web-api/coverage-runner.gif b/chess/3-web-api/coverage-runner.gif new file mode 100644 index 00000000..0d8e5d6b Binary files /dev/null and b/chess/3-web-api/coverage-runner.gif differ diff --git a/chess/3-web-api/getting-started.md b/chess/3-web-api/getting-started.md index d3469b4a..ebca030a 100644 --- a/chess/3-web-api/getting-started.md +++ b/chess/3-web-api/getting-started.md @@ -66,3 +66,16 @@ Open a browser and go to `http://localhost:8080` (If you picked another port, re You can use this to test your endpoints as you are coding the project. If you want to see how this works in greater depth or need help troubleshooting, take a look at [this page](../../instruction/web-api/web-api.md). + + +## Setup Code Coverage Runner + +For this phase, you will write your own unit tests. The autograder will test your unit tests and run code coverage on your tests using the JaCoCo library. IntelliJ uses it's own coverage runner by default, but you can swap to JaCoCo by doing the following: + +1. Go to your IntelliJ settings +1. Click on `Build, Execution, Deployment` +1. Click on Coverage +1. Where it says `Choose Coverage Runner`, click the dropdown box +1. Select JaCoCo + +![coverage runner](coverage-runner.gif) \ No newline at end of file diff --git a/chess/3-web-api/web-api.md b/chess/3-web-api/web-api.md index da77594f..a308bc34 100644 --- a/chess/3-web-api/web-api.md +++ b/chess/3-web-api/web-api.md @@ -380,7 +380,9 @@ When you use a browser to access your server the web interface will display by d In addition to the HTTP server pass off tests provided in the starter code, you need to write tests that execute directly against your service classes. These tests skip the HTTP server network communication and will help you in the development of your service code for this phase. -Good tests extensively show that we get the expected behavior. This could be asserting that data put into the database is really there, or that a function throws an error when it should. Write a positive and a negative JUNIT test case for each public method on your Service classes, except for Clear which only needs a positive test case. A positive test case is one for which the action happens successfully (e.g., successfully claiming a spot in a game). A negative test case is one for which the operation fails (e.g., trying to claim an already claimed spot). +Good tests extensively show that we get the expected behavior. This could be asserting that data put into the database is really there, or that a function throws an error when it should. We expect this code to meet **80% line coverage on all service classes.** + +If you are unsure where to start, consider writing a positive and a negative JUNIT test case for each public method on your Service classes. A positive test case is one for which the action happens successfully (e.g., successfully claiming a spot in a game). A negative test case is one for which the operation fails (e.g., trying to claim an already claimed spot). Some services may not need a negative test case. The service unit tests must directly call the methods on your service classes. They should not use the HTTP server pass off test code that is provided with the starter code. @@ -433,6 +435,8 @@ Once you have written the `clear` and `register` endpoints, you can run the `Sta - [Single Responsibility Principle](../../instruction/design-principles/design-principles.md#single-responsibility-principle): Organizing many server responsibilities into comprehensible units - [Dependency Inversion Principle](../../instruction/design-principles/design-principles.md#dependency-inversion-principle): Organizing the layers of the server. - [Interface Segregation Principle](../../instruction/design-principles/design-principles.md#interface-segregation-principle): Organizing the DAO interfaces. +- [Unit Testing](../../instruction/unit-testing/unit-testing.md): How to write unit tests +- [Code Coverage](../../instruction/code-coverage/code-coverage.md): The benefits and drawbacks of code coverage - [PetShop Server Architecture](../../petshop/petshop.md): Layer organization and component architecture. ## ☑ Deliverable @@ -468,10 +472,14 @@ To pass off this assignment use the course [auto-grading](https://cs240.click/) | GitHub History | At least 12 GitHub commits evenly spread over the assignment period that demonstrate proof of work | Prerequisite | | Web API Works | All pass off test cases succeed | 125 | | Code Quality | [Rubric](../code-quality-rubric.md) | 30 | -| Unit Tests | All test cases pass
Each public method on your **Service classes** has two test cases, one positive test and one negative test
Every test case includes an Assert statement of some type | 25 | +| Unit Tests | All test cases pass
Line coverage on `service` package is at least 80%
Every test case includes an Assert statement of some type
1.25 points of extra credit for 90% line coverage| 25 | | | **Total** | **180** | ## Videos -- 🎥 [Phase 3 Overview (19:26)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=edaa730e-e247-4356-9cf4-b2cd014ecf59) - [[transcript]](https://github.com/user-attachments/files/17707002/CS_240_Chess_Phase_3_Transcript.pdf) -- 🎥 [Chess Server Implementation Tips (18:43)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=2528dac9-1689-4e75-aff1-b2cd014e3b13) - [[transcript]](https://github.com/user-attachments/files/17707009/CS_240_Chess_Server_Implementation_Tips_Transcript.pdf) +- 🎥 [Phase 3 Overview (4:11)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=ff20952c-4442-4c05-af4d-b458015da74d) +- 🎥 [Chess Server Implementation Tips (5:08)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=7fbada42-7406-4aed-8d4f-b4580159ecb7) +- 🎥 [JSON and Serialization Tips (2:33)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=edf929ac-0468-4539-bad7-b458015bfeac) +- 🎥 [Data Access Classes (3:28)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=40f18f38-908f-4b90-af61-b458015f03e5) +- 🎥 [Unit Tests (1:59)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=7179270b-92a3-42e3-a607-b45801605534) +- 🎥 [Code Quality (2:10)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=bc9dcdad-b376-41dc-b4d6-b4580161004d) diff --git a/chess/4-database/database.md b/chess/4-database/database.md index 10dc0a41..2a408d8d 100644 --- a/chess/4-database/database.md +++ b/chess/4-database/database.md @@ -112,12 +112,14 @@ The pass off tests do not examine your game board. That means it is critical tha As part of your unit test deliverable you need to meet the following requirements. -1. Write a positive and a negative JUNIT test case for each public method on your DAO classes, except for Clear methods which only need a positive test case. A positive test case is one for which the action happens successfully (e.g., creating a new user in the database). A negative test case is one for which the operation fails (e.g., creating a User that has the same username as an existing user). +1. **Reach 80% line coverage on your SQL DAOs.** If you are unsure where to start, consider writing a positive and a negative JUNIT test case for each public method on your DAO classes. A positive test case is one for which the action happens successfully (e.g., creating a new user in the database). A negative test case is one for which the operation fails (e.g., creating a User that has the same username as an existing user). Some methods may not need a negative test case. 1. Ensure that all of your unit tests work, including the new DAO tests and the Service tests you wrote in the previous assignment. > [!IMPORTANT] > > You must place your data access test cases in a folder named `server/src/test/java/dataaccess`. Your test class must also end with the suffix `Test` or `Tests`. Without this the autograder will not find your tests. +> +> Coverage will be collected on the folder `server/src/main/java/dataccess/sql`. If you do not have this package, the autograder will not be able to grade your unit tests. ### Code Quality @@ -140,7 +142,7 @@ To pass off this assignment use the course [auto-grading](https://cs240.click/) | GitHub History | At least 8 GitHub commits evenly spread over the assignment period that demonstrate proof of work | Prerequisite | | Functionality | All pass off test cases succeed | 100 | | Code Quality | [Rubric](../code-quality-rubric.md) | 30 | -| Unit Tests | All test cases pass
Each public method on DAO classes has two test cases, one positive test and one negative test
Every test case includes an Assert statement of some type | 25 | +| Unit Tests | All test cases pass
Line coverage on `dataaccess.sql` package is at least 80%
Every test case includes an Assert statement of some type
1.25 points of extra credit for 90% line coverage | 25 | | | **Total** | **155** | ## Videos @@ -150,5 +152,5 @@ To pass off this assignment use the course [auto-grading](https://cs240.click/) - 🎥 [Initializing Your Database and Tables (4:22)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=953900dc-0b8e-4ed8-a732-b193015b7e64) - [[transcript]](https://github.com/user-attachments/files/17707074/CS_240_Initializing_Your_Database_and_Tables_Transcript.pdf) - 🎥 [Password Hashing (4:14)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=671b0db7-323b-4bec-b0b7-b193015cf733) - [[transcript]](https://github.com/user-attachments/files/17707082/CS_240_Password_Hashing_Transcript.pdf) - 🎥 [ChessGame Serialization/Deserialization (6:17)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=5b9f4b5e-a3ae-442f-a311-b193015f1b34) - [[transcript]](https://github.com/user-attachments/files/17707104/CS_240_ChessGame_Serialization_Deserialization_Transcript.pdf) -- 🎥 [Database Unit Tests (1:52)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=ab5a02c1-bf04-4514-afc0-b19301611d40) - [[transcript]](https://github.com/user-attachments/files/17707118/CS_240_Database_Unit_Tests_Transcript.pdf) +- 🎥 [Database Unit Tests (0:58)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=02024c96-3566-411a-b500-b45801627254) - [transcript] - 🎥 [Grading Rubric (2:02)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=1b8d4c3b-1e76-4474-9007-b19301620058) - [[transcript]](https://github.com/user-attachments/files/17707133/CS_240_Grading_Rubric_Transcript.pdf) diff --git a/chess/5-pregame/pregame.md b/chess/5-pregame/pregame.md index 6c9ccd48..e1577818 100644 --- a/chess/5-pregame/pregame.md +++ b/chess/5-pregame/pregame.md @@ -99,7 +99,7 @@ There are no new pass off test cases for this assignment. ### Unit Tests -Write positive and negative unit tests for each method on your ServerFacade class (all the methods used to call your server). +Reach 80% line coverage on your `ServerFacade` class. If you are unsure where to start, consider writing a positive and a negative test case for each public method. Your tests must be located in the file `client/src/test/java/client/ServerFacadeTests.java`, provided in the starter code. @@ -186,7 +186,7 @@ Before coming to passoff with a TA, check to make sure your code functions prope | GitHub History | At least 12 GitHub commits evenly spread over the assignment period that demonstrate proof of work | Prerequisite | | Functionality | Program supports all required functionality | 100 | | Code Quality | [Rubric](../code-quality-rubric.md) | 30 | -| Unit Tests | All test cases pass
Each public method on the Server Facade class has two test cases, one positive test and one negative test
Every test case includes an Assert statement of some type | 25 | +| Unit Tests | All test cases pass
Line coverage on `SeverFacade` class is at least 80%
Every test case includes an Assert statement of some type
1.25 points of extra credit for 90% line coverage | 25 | | | **Total** | **155** | ## Videos @@ -197,5 +197,5 @@ Before coming to passoff with a TA, check to make sure your code functions prope The Video for `Drawing the Board` is outdated. Instead, of printing both sides of the board, you should print the black board when you join the game as black and print the white board when you join the game as white or an observer, not both. - 🎥 [Drawing the Board (1:26)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=6a77c895-f2b8-49d9-8b11-b19a0156aef8) - [[transcript]](https://github.com/user-attachments/files/17805392/CS_240_Drawing_the_Board_Transcript.pdf) - 🎥 [Server Facade (8:49)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=48c546dc-bdd6-491f-88c1-b2c80118cb9f)- [transcript] -- 🎥 [Phase 5 Requirements (3:11)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=1a171c4d-c7dc-41d0-828f-b19a01594498) - [[transcript]](https://github.com/user-attachments/files/17805398/CS_240_Phase_5_Requirements_Transcript.pdf) +- 🎥 [Phase 5 Requirements (2:20)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=da07b0b6-d523-4d34-a765-b4580161b6be) - [transcript] - 🎥 [Client HTTP (12:11)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=781ae49b-6284-4e1a-836b-b1930162c54b) - [[transcript]](https://github.com/user-attachments/files/17805399/CS_240_Client_HTTP_Transcript.pdf) diff --git a/course.json b/course.json index 974d61b8..cd3be4f6 100644 --- a/course.json +++ b/course.json @@ -10,44 +10,28 @@ "path": "README.md", "id": "700a970e-d602-437f-9f00-91136b1f8096", "state": "published", - "interactions": [], - "commit": "849ec93b31efbeb34f62966d4c19b7f7a7464515" + "interactions": [] }, { "title": "Syllabus", "path": "instruction/syllabus/syllabus.md", "id": "afd15fd1-0747-4fed-bb39-2e3a561dc317", "state": "published", - "interactions": [], - "commit": "289056316c1198bd5924e1825432dc499eee4200" + "interactions": [] }, { "title": "Instruction topics", "path": "instruction/modules.md", "id": "5054878e-9c3c-4402-bb16-73614596a0b2", "state": "published", - "interactions": [], - "commit": "cef6a585f931f9aa450d7393b67cfb723c804d2e" - }, - { - "title": "Schedule: Dr. Rodham", - "path": "schedule/winter2026-rodham.md", - "id": "de98c0da-d6c9-4c5b-bcbf-11e233da7666", - "state": "published" - }, - { - "title": "Schedule: Dr. Wilkerson", - "path": "schedule/winter2026-wilkerson.md", - "id": "7a454cc0-921e-4748-a552-616a887b34e3", - "state": "published" + "interactions": [] }, { "title": "Asking questions", "path": "instruction/askingQuestions/askingQuestions.md", "id": "cbd516e5-8b00-499f-9442-8b11fb587f79", "state": "published", - "interactions": [], - "commit": "17a6a55b6393dd855be8aecd22beafb0d96c6485" + "interactions": [] } ] }, @@ -142,8 +126,7 @@ "path": "instruction/interfaces-abstract-classes/interfaces-and-abstract-classes.md", "id": "8d35e1bd-e7d0-4838-9272-e6902a5c4622", "state": "published", - "interactions": [], - "commit": "8ec2297a548e6f7f00e57bd4e514da79fb4a3ef1" + "interactions": [] }, { "title": "Copying Objects", @@ -167,13 +150,15 @@ "title": "Object Oriented Design", "path": "instruction/object-oriented-design/object-oriented-design.md", "id": "f5a08e81-81a8-4f56-830d-b6714f96279b", - "state": "published" + "state": "published", + "interactions": [] }, { "title": "Design Principles", "path": "instruction/design-principles/design-principles.md", "id": "38005272-6339-43da-912b-886bda6bcbae", - "state": "published" + "state": "published", + "interactions": [] }, { "title": "Java Inner Classes", @@ -191,13 +176,15 @@ "title": "☑ Phase 1: Chess Game", "path": "chess/1-chess-game/chess-game.md", "id": "3d7737da-c17e-413a-8596-2eac96d88274", - "state": "published" + "state": "published", + "interactions": [] }, { "title": "Java Input and Output (IO)", "path": "instruction/io/io.md", "id": "9ac207b1-23da-46b6-a879-ad4b748c55c9", - "state": "published" + "state": "published", + "interactions": [] }, { "title": "Java Generics", diff --git a/instruction/askingQuestions/askingQuestions.md b/instruction/askingQuestions/askingQuestions.md deleted file mode 100644 index 47c16cd6..00000000 --- a/instruction/askingQuestions/askingQuestions.md +++ /dev/null @@ -1,39 +0,0 @@ -# Asking questions - -🔑 **Required reading**: [Stack Overflow - How to ask a good question](https://stackoverflow.com/help/how-to-ask) - -## Getting help - -- [Discord](https://discord.com) ([Invite](https://discord.gg/rY57bzYVUn)) -- [TA Office](https://docs.google.com/document/d/12ZrcsQAfVirCuCwzI0TKX_tSPyBOjqB9vDE-sx1n_S0) (1066 TMCB) -- [Professor Jensen](https://cs.byu.edu/department/directories/faculty-directory/lee-jensen/) - Office hours through [Calendly](https://calendly.com/lee-cs/30min) -- [Dr. Wilkerson](https://cs.byu.edu/department/directories/faculty-directory/jerod-wilkerson/) -- [Dr. Rodham](https://cs.byu.edu/department/directories/faculty-directory/ken-rodham/) - -| Who | How | Where | When | -| ---------- | ------------------- | ---------------------- | ------------------------------- | -| TA | Online or in person | Discord, TA Office | [TA Schedule](https://docs.google.com/document/d/12ZrcsQAfVirCuCwzI0TKX_tSPyBOjqB9vDE-sx1n_S0) | -| Instructor | Online or in person | Discord, Class, Office | Office Hours, Class Times | -| Peers | Online or in person | Discord, Class | Depends on how friendly you are | - -## How to ask questions - -If you would like to get some help from others, please make sure that you have done the following first: - -- Have read deliverable specifications thoroughly. Sometimes this means 3 – 4 times. -- Work at solving the problem on your own for at least 30 minutes. -- Use unit tests to help you debug your problems. -- Read the course instructional content before asking questions. -- Try consulting the API documentation first. -- Debug your code using the IDE. -- Write, run, and be able to justify the effectiveness of your own test cases. -- Attend every class. -- Have a well-formed question to ask the TA. -- Put yourself in a frame of mind to accept new ideas. -- Remember one purpose of this class is for you to learn how to learn. If the TA feels you are not putting forth your full, they may ask you to return later when you have fulfilled these requirements. - -Remember that TAs are _assistants_. They are more than willing to assist you as you learn, but you need to do your part as well. Because of this, the help queue has a limit of 3 session per day per student. Exceptions are made for when you are attempting to passing off a deliverable. - -## Pay it forward - -Always remember how it felt to receive help. Actively look for opportunities to help others in a kind respectful way. After all, that is the Gospel of Jesus Christ at its core. We are a team. We are better together. diff --git a/instruction/aws-chess-server/ami.png b/instruction/aws-chess-server/ami.png deleted file mode 100644 index c61aef76..00000000 Binary files a/instruction/aws-chess-server/ami.png and /dev/null differ diff --git a/instruction/aws-chess-server/aws-chess-server.md b/instruction/aws-chess-server/aws-chess-server.md deleted file mode 100644 index 95c8ef5d..00000000 --- a/instruction/aws-chess-server/aws-chess-server.md +++ /dev/null @@ -1,204 +0,0 @@ -# AWS Chess Server - -🖥️ [Lecture Videos](#videos) - -Playing chess in your development environment by yourself can get old after a while. Wouldn't it be nice if you could actually play with your friends or family? The great thing is that your code is already designed to allow any computer in the world to talk to your HTTP server, you just need to put it in a place where it is accessible. To do this, you need to run your chess server on a device that has a public IP address and open up your network port so that it is externally accessible. - -There are lots of ways you can accomplish this. You could lease an IP address from your internet service provider (ISP) and assign it to your laptop, or you could lease a server from a cloud provider such as Digital Ocean, Azure, or Amazon Web Services (AWS). - -In this instruction we will go with AWS. Note that there is a cost involved in renting a server from AWS. Although if you are careful it shouldn't cost more than $5 a month. - -## Get AWS account - -Go to [AWS](https://aws.amazon.com/) and register for an account if you don't already have one. You will need a credit card, but you won't be charged for anything until you start using their services. Make sure you are aware of the pricing model for anything that you use so that you don't get any unexpected surprises with your monthly bill. - -## Launch an EC2 instance - -The Amazon Elastic Compute Cloud (EC2) service provides all of the functionality you need to launch a virtual server in an Amazon data center that is accessible to the world. After you have created your AWS account, use the AWS browser console to navigate to the EC2 service and lease your server with the following steps. - -1. From the search bar type in EC2 and select the displayed EC2 dashboard. ![EC2 service selection](awsEc2Selection.png) -1. Create a security group - - 1. The security group will expose the ability to talk to our server over HTTP on the server's network port. This is usually port 8080. From the EC2 dashboard select the `Security Group` view from the options on the left. - 1. Select the option to create a security group. - 1. Give it a meaningful name and description. Select the default VPC. ![Create security group](createSecurityGroup.png) - 1. In the `Inbound rules` section, create a rule that opens port 22 and port 8080 to everywhere. ![Inbound rules](inboundRules.png) - 1. Save the security group. - -1. Launch a server instance. - - 1. Navigate back to the EC2 dashboard. - 1. Select the option to `Launch instance`. - 1. Give your instance a name like `cs240-chessserver`. - 1. Chose AWS linux for your Amazon Machine Image (AMI). ![Amazon Machine Image](ami.png) - 1. Set the instance type of t2.micro. If you are eligible for the free tier then you will not be billing for the first 12 months of your first t2.micro instance. - - ![Instance type](instanceType.png) - - 1. In the Key pair input select an existing key pair if you have created one previously, or select the `Create new key pair` option. Make sure you save the key pair to a safe place in your development environment. You will need this to connect to your server, and you do not want to let anyone else have access to it. Do not check the key pair into GitHub or any other publicly available location.

**Note:** You may need to change the file permissions to protect your key file before you can use it to access your AWS instance. If using a Mac or Linux, use the command `chmod 600 `. - 1. In the `Network settings` you specify how the world can access your server. Choose the option to `Select existing security group` and pick the security group you created previously. - - ![Security group configuration](securityGroup.png) - - 1. Scroll past the remaining options and press `Launch instance`. This will display a message saying that the instance has been successfully launched. You can then navigate to the `Instances` view and click on your newly created server to see all of the details. - - ![EC2 Instance settings](ec2InstanceSettings.png) - - You will want to copy the `Public IPv4 address` so that you can remotely connect to the server using a secure shell (SSH) and also access your server from the browser in order to play a game of chess. - -## Install MySQL - -Now that you have your AWS EC2 server up and running you need to install MySQL so that you can store your user and game information. - -First you need to remotely connect to your server using a secure shell (SSH). Usually you do this by opening a console, or terminal, window in your development environment and typing the command `ssh`. In order to connect, you need the key pair you used to launch your server. The command looks like this: - -```sh -ssh -i youkeypairhere.pem ec2-user@youripaddresshere -``` - -Once you have shelled into your EC2 server you can download, install, and start MySQL with the following commands. - -```sh -sudo wget https://dev.mysql.com/get/mysql80-community-release-el9-1.noarch.rpm -sudo dnf install mysql80-community-release-el9-1.noarch.rpm -y -sudo rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2023 -sudo dnf install mysql-community-client -y -sudo dnf install mysql-community-server -y -sudo systemctl start mysqld -``` - -When MySQL was installed it created a random password for the root user. You can get the password from the MySQL log file and use that to login to the MySQL client and change the password. - -```sh -sudo grep 'temporary password' /var/log/mysqld.log -mysql -u root -p -ALTER USER 'root'@'localhost' IDENTIFIED BY 'yourpassword'; -``` - -If your password is not complicated enough for the default MySQL password checker, you can disable the checker, but first you must change the password to something that is acceptable. - -```sh -ALTER USER 'root'@'localhost' IDENTIFIED BY '1Really~Complicated!!'; -UNINSTALL COMPONENT 'file://component_validate_password'; -ALTER USER 'root'@'localhost' IDENTIFIED BY 'monkeypie'; -``` - -**Note:** Make sure your password matches the root password specified in the db.properties file in your chess client. - -## Install Java - -Use the following to install the latest version of Java on your EC2 server. - -1. SSH into server as described above -1. Install java `sudo dnf install java` -1. Check that Java is running with `java --version` - -## Modify your client code - -You may need to modify your Chess Client code so that you can specify the server that it connects to. The following are two possible changes you might make. - -1. Make it so your chess client can take the `youripaddresshere:port` as a parameter. - ```java - public static void main(String[] args) { - var serverName = args.length > 0 ? args[0] : "localhost:8080"; - ChessClient client = new ChessClient(serverName); - // ... - } - ``` -1. Modify your web/index.html so your user can download your java client - ```html -

Download the client. Run with:

-
java -jar client.jar server:8080
- - ``` - -## Build the client and server jars - -Build the client Jar and copy it to your server's resources web directory so that it can be downloaded from the server when someone wants to play chess. - -```sh -mvn package -pl client -DskipTests -cp client/target/client-jar-with-dependencies.jar server/src/main/resources/web/client.jar -``` - -Now we can build the server jar. - -```sh -mvn package -pl server -DskipTests -``` - -This will create the following `server/target/server-jar-with-dependencies.jar` - -## Copy server code - -With the server and client built, we can copy the server jar up to the EC2 server using the secure copy utility `scp`. - -```sh -scp -i youkeypairhere.pem server/target/server-jar-with-dependencies.jar ec2-user@youripaddresshere:server.jar -``` - -## Start up the server - -Now you are ready to start up the server. - -1. SSH into server as described above -1. Run your server using the Java runtime and your server.jar - -```sh -java -jar server.jar -``` - -This should output that the server is successfully running on the assigned port. Now you should be able to open up a browser on any computer in the world and see the web interface for your chess server. When you open your browser, put the public IP address and port number of your EC2 Instance. This should be something like `http://youripaddresshere:8080`. - -![Chess web interface](chessServerWebInterface.png) - -You can then click the link that you created to download the client. Note that you may need to tell your browser to load your web page even though it is not secure, as well as specifying that you want to download the jar file. - -![Ignore security warnings](ignoreSecurityWarnings.png) - -Now you can use the Java runtime to run your chess client. Make sure you provide the ip address and port number as parameters. - -```sh -java -jar client.jar youripaddress:8080 -``` - -![Playing chess](playingChess.png) - -## Make your chess server start whenever you start the AWS instance - -Invoking your chess server from ssh will require you to keep the ssh terminal open. You can make your chess server start automatically every time your AWS instance is started by following these instructions: - -1. SSH into your server as described above -2. Create and open a service description file: `sudo nano /etc/systemd/system/chess_server.service` -3. Enter and save the following in the Nano code editor window: - -```[Unit] -Description=Chess Server -After=network.target - -[Service] -Type=simple -ExecStart=java -jar /home/ec2-user/server.jar 8080 - -[Install] -WantedBy=multi-user.target -sudo systemctl enable chess_server -``` - -4. Enable the chess server service: `sudo systemctl enable chess_server` -5. Start the chess server service: `sudo systemctl start chess_server` -6. Check the status of the chess server service: `sudo systemctl status chess_server` -7. To confirm that the service starts whenever the AWS instance is started, stop and restart the AWS instance from the AWS console or use this command: `sudo reboot` - -Have fun! You have just taken the first step in becoming the world's best chess server. - -## Videos - -- 🎥 [Overview (1:41)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=10672ba0-ba2d-4c9b-b6c1-b1ae01071d55&start=0) - [[transcript]](https://github.com/user-attachments/files/17707228/CS_240_Deploying_your_Chess_Server_on_AWS_Overview_Transcript.pdf) -- 🎥 [Launch an EC2 Instance (14:42)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=feea3668-a904-402d-97d1-b1ae0107c46d&start=0) - [[transcript]](https://github.com/user-attachments/files/17707232/CS_240_Launch_an_EC2_Instance_Transcript.pdf) -- 🎥 [Setup Your EC2 Instance (13:42)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=a5252593-01e6-479b-8532-b1ae010c4e9b&start=0) - [[transcript]](https://github.com/user-attachments/files/17707242/CS_240_Set_Up_Your_EC2_Instance_Transcript.pdf) -- 🎥 [Modify Your Client Code (7:50)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=c20793cb-452e-4a52-bf1d-b1ae01121603&start=0) - [[transcript]](https://github.com/user-attachments/files/17707251/CS_240_Modify_Your_Client_Code_Transcript.pdf) -- 🎥 [Deploy Code and Start the Server (17:49)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=d0fcb3f4-5aea-44b1-af53-b1ae01149092&start=0) - [[transcript]](https://github.com/user-attachments/files/17707258/CS_240_Deploy_Code_and_Start_the_Server_Transcript.pdf) -- 🎥 [Configure Your Chess Server to Start When Your EC2 Instance Starts (8:39)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=56af2673-5e59-4019-8e49-b1ae0119d612&start=0) - [[transcript]](https://github.com/user-attachments/files/17707267/CS_240_Configure_Your_Chess_Server_to_Start_When_Your_EC2_Instance_Starts_Transcript.pdf) diff --git a/instruction/aws-chess-server/awsEc2Selection.png b/instruction/aws-chess-server/awsEc2Selection.png deleted file mode 100644 index 11ae7044..00000000 Binary files a/instruction/aws-chess-server/awsEc2Selection.png and /dev/null differ diff --git a/instruction/aws-chess-server/chessServerWebInterface.png b/instruction/aws-chess-server/chessServerWebInterface.png deleted file mode 100644 index 55cc6c89..00000000 Binary files a/instruction/aws-chess-server/chessServerWebInterface.png and /dev/null differ diff --git a/instruction/aws-chess-server/createSecurityGroup.png b/instruction/aws-chess-server/createSecurityGroup.png deleted file mode 100644 index 7842eadc..00000000 Binary files a/instruction/aws-chess-server/createSecurityGroup.png and /dev/null differ diff --git a/instruction/aws-chess-server/ec2InstanceSettings.png b/instruction/aws-chess-server/ec2InstanceSettings.png deleted file mode 100644 index fa58e3fa..00000000 Binary files a/instruction/aws-chess-server/ec2InstanceSettings.png and /dev/null differ diff --git a/instruction/aws-chess-server/ignoreSecurityWarnings.png b/instruction/aws-chess-server/ignoreSecurityWarnings.png deleted file mode 100644 index 3dad78b7..00000000 Binary files a/instruction/aws-chess-server/ignoreSecurityWarnings.png and /dev/null differ diff --git a/instruction/aws-chess-server/inboundRules.png b/instruction/aws-chess-server/inboundRules.png deleted file mode 100644 index ecb7102a..00000000 Binary files a/instruction/aws-chess-server/inboundRules.png and /dev/null differ diff --git a/instruction/aws-chess-server/install.sh b/instruction/aws-chess-server/install.sh deleted file mode 100644 index 56f5551f..00000000 --- a/instruction/aws-chess-server/install.sh +++ /dev/null @@ -1,14 +0,0 @@ -sudo mkdir /opt/chess - -sudo useradd -r chess -sudo chown -R chess:chess /opt/chess - -echo "DAWN Installing service" -sudo mv /opt/chess/service.sh /etc/init.d/chess -sudo sed -i -e 's/\r//g' /etc/init.d/chess #Make sure we don't have any /r in the script -sudo chmod +x /etc/init.d/chess -sudo chkconfig chess on #Enable the service for runlevels 2, 3, 4, and 5 -sudo ln -s /opt/chess/chess /usr/bin/chess #Create the symlink to point to the actual binaries -sudo systemctl daemon-reload #Tell sysv that new scripts are loaded -sudo setcap 'cap_net_bind_service=+ep' /opt/chess/chess #Enable use of port 80 -sudo service chess start \ No newline at end of file diff --git a/instruction/aws-chess-server/instanceType.png b/instruction/aws-chess-server/instanceType.png deleted file mode 100644 index e587d7da..00000000 Binary files a/instruction/aws-chess-server/instanceType.png and /dev/null differ diff --git a/instruction/aws-chess-server/playingChess.png b/instruction/aws-chess-server/playingChess.png deleted file mode 100644 index 3d6d80cf..00000000 Binary files a/instruction/aws-chess-server/playingChess.png and /dev/null differ diff --git a/instruction/aws-chess-server/securityGroup.png b/instruction/aws-chess-server/securityGroup.png deleted file mode 100644 index 3d565a8c..00000000 Binary files a/instruction/aws-chess-server/securityGroup.png and /dev/null differ diff --git a/instruction/aws-chess-server/service.sh b/instruction/aws-chess-server/service.sh deleted file mode 100644 index 11c95f6b..00000000 --- a/instruction/aws-chess-server/service.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/sh -# -# Chess -# -# chkconfig: - 64 36 -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 2 3 4 6 -# Required-Start: -# description: Chess -# processname: chess -# pidfile: none -# lockfile: /var/lock/subsys/chess - -# Source function library. -. /etc/rc.d/init.d/functions - -# Source networking configuration. -. /etc/sysconfig/network - -# Check that networking is up. -[ "$NETWORKING" = "no" ] && exit 0 - -USER="chess" -APPNAME="chess" -APPBIN="/usr/bin/chess" -APPARGS="-config config.json" -LOGFILE="/var/log/$APPNAME/error.log" -LOCKFILE="/var/lock/subsys/$APPNAME" - -LOGPATH=$(dirname $LOGFILE) - -start() { - [ -x $prog ] || exit 5 - [ -d $LOGPATH ] || mkdir $LOGPATH; chown $USER:$USER $LOGPATH - [ -f $LOGFILE ] || touch $LOGFILE; chown $USER:$USER $LOGFILE - - echo -n $"Starting $APPNAME: " - daemon --user=$USER "$APPBIN $APPARGS >>$LOGFILE &" - RETVAL=$? - echo - [ $RETVAL -eq 0 ] && touch $LOCKFILE - return $RETVAL -} - -stop() { - echo -n $"Stopping $APPNAME: " - killproc $APPBIN - RETVAL=$? - echo - [ $RETVAL -eq 0 ] && rm -f $LOCKFILE - return $RETVAL -} - -restart() { - stop - start -} - -rh_status() { - status $APPNAME -} - -rh_status_q() { - rh_status >/dev/null 2>&1 -} - -case "$1" in - start) - rh_status_q && exit 0 - $1 - ;; - stop) - rh_status_q || exit 0 - $1 - ;; - restart) - $1 - ;; - status) - rh_status - ;; - *) - echo $"Usage: $0 {start|stop|status|restart}" - exit 2 -esac diff --git a/instruction/chess-tips/chess-tips.md b/instruction/chess-tips/chess-tips.md deleted file mode 100644 index 6cb059c8..00000000 --- a/instruction/chess-tips/chess-tips.md +++ /dev/null @@ -1,302 +0,0 @@ -# Chess Tips - -This is a collection of tips that the TAs have compiled for solving common problems. - -# General - all phases - -## I don't have enough GitHub commits to pass the autograder - -Try to avoid this by following these rules of thumb: - -1. **Work in small chunks.** One common mistake is only committing when you hit a big milestone, like passing an entire test file - this is a sign that you could break the problem into smaller pieces. Commit when you hit small milestones, like finishing a function or passing a test. -2. **Always set a clear goal for your next commit.** Something like "pass this test" or "create this piece of logic." Let the flow of regular commits drive your development process. -3. Commits should **represent your changes in one short sentence.** If your commits are feeling hard to articulate because you don't remember all the things you changed, that's a good indicator that you should be committing more often. -4. **Start working early.** The autograder has a requirement for number of days, so it'll flag you if you do everything on the same day. - -If you turn in your code without enough commits, the autograder will let you know that you need TA approval. We recommend that you bring your number of commits up to the required amount before coming in. You can make further changes to your code by focusing on code quality and organization: analyze your program structure and work on applying principles you're learning in class, like decomposition, abstraction, and encapsulation. - -# Phase 0 - Chess moves - -## These collections look identical to each other, but Java says they aren’t - -Look at the [specification](../../chess/0-chess-moves/chess-moves.md#object-overrides) for mentions of the `equals()` and `hashCode()` methods. It might also be worthwhile to implement a `toString()` method. Additionally, check the promotion piece (null in 99% of cases). Also, review the getters and setters for each class if that doesn’t work. - -## JUnit - No test events received - -Go into File -> Project Structure -> Modules -> Paths and select “Inherit project compile output path” for each module. - -## I can’t run any tests, there is no green button - -First, check if your `test/java` folder is highlighted green. If it isn’t highlighted green, right-click on the `java` folder, then select "Mark Directory As…" and select "Test Sources Root". Now that IntelliJ understands that this is a test folder, there should be an option to run the tests inside of it. - -If that doesn’t work, make sure that the shared folder is a module. You can check this by clicking File -> Project Structure. Then, in Project Structure select the Module option on the left. Here you can see a section of Modules, in which you should see shared, server, and client. If you only see chess or nothing at all, IntelliJ didn’t set it up right, so you should delete everything, reclone the repository, and set it up again. - -## I don't have enough GitHub commits to pass the autograder - -See [previous](/instruction/chess-tips/chess-tips.md#General---all-phases) - -# Phase 1 - Chess Game - -## toString - -If you are struggling to understand how the board is looking during your code, and especially when comparing it with the expected test cases, what you can do is override a toString to your code. This means that instead of printing ChessGame@12345, it will print out the variables, and you can have it print out a mock chess board so you can visually see and understand what the current layout of the chessBoard. - -## `static` keyword - -In most cases you should not be using the `static` keyword for your classes and methods. Static classes and variables mean that there will only be one single instance, making it into a global variable. If you know what you are doing, you can use static, but only use it if you can know what you are using it for. If your IDE is telling you to use static, you should see why it is thinking it should be static, and fix it because 90-100% of your code shouldn't be static. - -## Clone and Copy - -When in your `ChessGame.validMoves`, you may want to create a copy/clone of the ChessBoard so that you can make a piece move and see if you are still in check to know if that is a valid move or not. If you create a shallow copy, the ChessBoard will be the exact same, and will keep any changes you make. This needs to be a DeepCopy or clone so that it can be unique and different, so that if a chance happens on one instance, the other will stay the same. If you would like some explanations on how to incorporate clone and copy, look here for [copying objects](../copying-objects/copying-objects.md). One such method is to have ChessBoard implement Cloneable, then in the override clone method, you loop through the 2d ChessPiece array, and do `Arrays.copyOf` to copy the chess board row by row, then finally putting the 2d array into the cloned ChessBoard. - -## `==` vs `.equals()` comparison - -If you are trying to see if a king is in check by doing `endPosition == kingPosition`, the answer will always return false. Instead, you should use `endPosition.equals(kingPosition)`. To understand why Objects require `.equals()` instead, please refer to [Java Object Class](../java-object-class/java-object-class.md). - -## I don't have enough GitHub commits to pass the autograder - -See [previous](/instruction/chess-tips/chess-tips.md#General---all-phases) - -# Phase 2 - Server Diagram - -# Phase 3 - Web API - -## 5 Pro tips - -5 Pro tips for solving your own coding problems (#4 will surprise you): - -1. **Read the error messages.** The computer doesn’t lie, and it even tells you exactly which line caused the problem! -2. **Read the specs.** The document is long, but it’s not redundant— it’s helpful. All the information has been carefully placed in there to help YOU as a student. -3. **Search Discord.** It’s really to ask a new question, but first try to use the search feature to find a pre-existing answer. -4. **Write your own tests.** Yes, it was convenient in the first phases when we had done that for you, but now we’re expecting you to do this yourself. The Phase 3 tests are intentionally less helpful than before. Rely on manual testing, or write your own tests from the beginning. -5. **Appreciate the learning opportunity.** We (the instructors) designed this course to teach you new things. You are supposed to wrestle with new concepts and challenges, but it is possible. Think through the problems; you can do it! - -## Why is there no distinction between `Unauthorized` and `Unregistered` errors? - -> **Question:** -> Would trying to sign in with an unregistered username generate a 401 error or a 500 error? -> my guess is that it's a 401, since it was a user error, but calling it "Unauthorized" when it's more "Unregistered" doesn't feel quite right - -While the user isn't registered, you still want to return `Unauthorized`, otherwise you would be "leaking" information. - -For example, lets say you return `Unregistered` for users that don't exist and `Unauthorized` for users that do exist but just have the wrong password. If I'm a bad actor and I want to try and log in to someone else's account, if I get an `Unregistered` exception, that tells me that the account I'm trying to log into doesn't exist, and if I get an `Unauthorized` exception that means I have an account that exists, but I don't have the right password. So I could just spam different passwords at accounts I know exist, rather than waste my time with accounts that don't exist. - -Returning `Unauthorized` in both cases doesn't "leak" the information whether an account exists or not. Just think about when you try to log into somewhere, and if you put the wrong password, it usually says "wrong username/password" rather than just saying "wrong password." - -## "Variable is being received by server/tests as null” OR “Variable from the tests is arriving in my server as null” - -A variable in a request/result object is named incorrectly (casing matters with gson: authToken and authtoken are treated differently). Make sure that all class variable names in classes used for serialization exactly match the spec. - -Make sure the resources folder/directory is marked as the main resources root - -## SyntaxError: Unexpected token ‘<’, “ sev.run(8080) and db.properties has a db.port of 3306. - -## Invalid SQL Format - -The last line of the SQL String before the end parentheses should not have a comma, if it does that will throw an error - -```java -String createUserTable = """ -CREATE TABLE IF NOT EXISTS user ( -username VARCHAR(255) NOT NULL, -password VARCHAR(255) NOT NULL, -email VARCHAR(255) NOT NULL, -PRIMARY KEY (username), -)"""; -``` - -As a side note, you don’t need the Engine that is shown in Pet Shop. -Primary Keys mean that it will be unique, and can’t have any duplicates - -## Too Many Connections - -If you are running into this error, that means the connections aren’t being created and then closed. This can be done by simply putting the getConnection call in a try-with-resources block, as it will automatically close the connection afterwards. If you don’t want to use a try-with-resources block for whatever reason, you can instead call close on the connection afterwards. - -## Failing the Database Error Handling Test - -First off, if the test is failing at the line with getDeclaredMethod(“loadProperties”) then they need to update their DatabaseManager so that it has the loadProperties method in it. - -If that is not their problem, this test will basically run through all the endpoints, crash the server in order to have the DatabaseManager throw a DataAccessException either on the createDatabase call or getConnection call. This DataAccessException should be caught to create a 500 server error, and the error message should start with “Error: “. So make sure that the student is catching these DataAccessExceptions, setting the status code to 500, and having the error message start with “Error: ” - -A great way to debug this is to put a breakpoint in the DatabaseTests at line 128 (TestResult result = operation.get();), then pressing the step over button so you can see what is in result. Here you can see the error message (to make sure it has “Error: “ in the front, and if you press the step over button again, it will pass through the Assertions.assertEquals(500, serverFacade.getStatusCode()) and you will know if it did have a 500 status code or not. The order these operations go through are (Clear, Register, Login, Logout, CreateGame, ListGames, then JoinGame) so if they fail the 3rd check, result should have null value for authToken and username, but a message with “Error:”, so you can look into their Logout endpoint to see where there may be an issue. - -If it says “Error: Unauthorized” with a 401 error, that probably means that they have a catch (DataAccessException) into throw new DataAccessException (“Error: Unauthorized”), overriding the error message of failed to connect to the database and changing it into an Unauthorized exception. This makes the student’s code think this is a 401 error instead of a 500 server error. - -# Phase 5 - Pregame - -## I can’t import ServerFacade in the tests - -Your ServerFacade is probably not in a package. Put it in a package (probably not your UI package, is it a UI class?) and you should be able to import it - -## Passoff Frequently Encountered Problems - -Here are a couple of things that students commonly forget to include as part of their code which causes them to fail their passoff. This is not a complete list of everything that your code needs to do in order to pass, just some of the common problems. - -- After registering, you will automatically enter the signed-in state, you don't need to login afterwards. [Prelogin UI Command Descriptions](../../chess/5-pregame/pregame.md#prelogin-ui) -- Make your ListGames numbering be independent of the game IDs. [Postlogin UI Command Descriptions](../../chess/5-pregame/pregame.md#postlogin-ui) -- Make sure your board is printed correctly! [Gameplay UI Description](../../chess/5-pregame/pregame.md#gameplay-ui) -- Print readable errors and make sure your code doesn't crash. For example, make sure you handle trying to join or observe a game with an invalid game number input (`1000`, `-10`, `two`). [UI Requirements](../../chess/5-pregame/pregame.md#ui-requirements) - -## Chess Board UI - -If you want to use the Chess Pieces, but are having some issues with making the board a square, here are some tips - -- Make sure that your spaces are including the unicode for the width of a chess piece "\u2003" and are following the same space configuration - - " ♛ " would have the same width as "\u2003a " because they each have a space on the right, the first example has a space which is the same width as the 'a' in the second example, and they both have the width of a chess piece as well, meaning that each of these square examples would be the same width -- If you are sure that each square should be printing the same as stated above, then you might need to change your font. Go to IntelliJ Settings -> Editor -> Font - - This is because different laptop systems and processors can print the unicode "\u2003" and the actual chess pieces as different widths. Using the correct font will ensure that they are printed as the same width - - Make sure you still use a monospaced font, because monospaced means that a space is the same width as the letter 'a', but if you use a non monospaced font, they will no longer be the same width - -## I don't have enough GitHub commits to pass the autograder - -See [previous](/instruction/chess-tips/chess-tips.md#General---all-phases) - -## AutoGrader can’t find my Unit Tests - -Make sure the unit tests are in client/src/test/java/client and the Class ends with the word `Tests` or `Test`. - -# Phase 6 - Gameplay - -## Unknown opcode: 7 - -If your server is throwing exceptions related to “opcode 7”, try changing your server port away from 8080 (or whatever port you are using). The cause of this is currently not known, but it seems to be more likely to occur on computers running macOS Sonoma. - -## Variable is being received by server/tests as null - -A variable in a ServerMessage/UserCommand object is named incorrectly (casing matters with gson). Make sure that all class variable names in classes used for serialization exactly match the spec. - -## message.toString - -Note, make sure that you just aren’t copying Pet Shop code, but specifically the message.toString method, as Pet Shop will override that and turn it into a Gson.toJson of the class, while your code will just make it a string message of the whole Message class, which isn’t json. - -## Message is sent from Server but doesn’t look like it’s being received in the client - -It’s possible that the code for receiving messages in the client could be throwing an exception (especially if the message isn’t formatted correctly in JSON). Tyrus has a bad habit of just eating those exceptions without logging them anywhere useful. I recommend wrapping the contents of the method with a try/catch block with a catch for any Exception or Throwable. Up to the student what to do in the catch block, but don’t throw a different exception otherwise they’ll be back at square one. - -## Tests are failing because there are too many messages - -This could be from a race condition, if you send a notification that a move was made, then do a mysql check to see if the game is in check, checkmate, or stalemate, the mysql will take too long and send a message as part of the next tests. So do all checking first, then send the websocket messages afterwards to eliminate all race conditions. - -## Running into a ClosedChannelException - -This exception is thrown when you are trying to send a message to a closed channel. Have the student make sure they are checking that the session is open (session.isOpen()) before sending it a message. - -## Passoff Frequently Encountered Problems - -Here are a couple of things that students commonly forget to include as part of their code which causes them to fail their passoff. This is not a complete list of everything that your code needs to do in order to pass, just some of the common problems. - -- Resigning should require a confirmation, and does **not** kick players from the game. [Gameplay Functionality](../../chess/6-gameplay/gameplay.md#gameplay-functionality) -- Anyone can highlight any piece, independent of whose turn it is. In addition, a user trying to highlight a position with no piece shouldn't break your code. [Gameplay Functionality](../../chess/6-gameplay/gameplay.md#gameplay-functionality) -- Make sure you implement pawn promotion. [Pawn Functionality](../../chess/0-chess-moves/the-game-of-chess.md#pawn) -- All messages should contain player usernames. Move messages should have a description of the move such as a2 to a4. [Notifications](../../chess/6-gameplay/gameplay.md#notifications) - -## I don't have enough GitHub commits to pass the autograder - -See [previous](/instruction/chess-tips/chess-tips.md#General---all-phases) diff --git a/instruction/classes-and-objects/classes-and-objects.md b/instruction/classes-and-objects/classes-and-objects.md deleted file mode 100644 index deedb10c..00000000 --- a/instruction/classes-and-objects/classes-and-objects.md +++ /dev/null @@ -1,216 +0,0 @@ -# Classes and Objects - -🖥️ [Slides](https://docs.google.com/presentation/d/17S-Y7Og08S9kRWHZfnH8k2wTBht39aCd/edit?usp=sharing&ouid=114081115660452804792&rtpof=true&sd=true) - -📖 **Required Reading**: Core Java for the Impatient Chapter 2: Object-Oriented Programming - -🖥️ [Lecture Videos](#videos) - -Classes are the primary programming construct for Java. A class contains fields and methods. Fields represent variables within the class and methods represent operations that the class performs. For example, if we had a class that represents a person, we might have a field called `name` that contains the person's name, and a method called `sayName` that outputs the name. An object is an instantiation, or instance, of a class that has been initialized to contain values. A class may also have a constructor that provides the default values for the fields when the class is instantiated into an object. - -```java -public class Person { - // Field - private String name; - - // Constructor - public Person(String name) { - this.name = name; - } - - // Method - public void sayName() { - System.out.println(name); - } -} -``` - -If you wanted to instantiate a `Person` object from the `Person` class, you use the `new` operator and pass the values you want to initialize the object with. The provided values then get passed to the class's constructor. Here is an example of a Java program that uses the `Person` class. - -```java -public class HelloPerson { - public static void main(String[] args) { - var person = new Person("James Gosling"); - person.sayName(); - } -} -``` - -## This Keyword - -When you use the `new` operator to instantiate an object it returns a pointer reference to the new object. You can then use that to call methods and access variables to the object. - -```java -var obj = new Object(); -obj.toString(); -``` - -That works great for code that uses your class, but sometimes you need a reference to the object within the class code. For example, consider the `toString` method. If you want to reference a class field as part of the output of the method then you can use the keyword `this`, as a substitute for the reference to the object. - -```java -public class ThisExample { - String value = "example"; - - public String toString() { - return this.value; - } -} -``` - -In order to keep you from having to use the `this` keyword every time you reference a class field, Java will infer `this` when you reference a class field and there is no other conflicting variable with the same name. That makes it so you only have to use `this` when there is a conflict. This commonly happens in a class constructor method as demonstrated above in the `Person` example. - -## Constructors - -An object constructor receives parameters and executes the code necessary to completely construct an object. A constructor is specified with a method that has the same name as the class. You can have multiple, or overloaded, constructors by defining constructors that take different parameters. This is useful if you want the ability to construct an object with default values, or with explicit values. - -A common pattern with constructors is to create what is called a `copy constructor` that takes an object of the class type, and deep copies all of the object's values to the new instance. - -```java -public class ConstructorExample { - public String value; - - /** Default constructor */ - public ConstructorExample() { - value = "default"; - } - - /** Overloaded explicit constructor */ - public ConstructorExample(String value) { - this.value = value; - } - - /** Copy constructor */ - public ConstructorExample(ConstructorExample copy) { - this(copy.value); - } - - public static void main(String[] args) { - System.out.println(new ConstructorExample().value); - System.out.println(new ConstructorExample("A").value); - System.out.println(new ConstructorExample(new ConstructorExample("B")).value); - } -} -``` - -If you don't provide a constructor then Java provides a default constructor that does nothing. - -## Getters and Setters - -An important concept in object oriented programming is the idea of encapsulation. This basically means that you only expose information on a `need to know basis`. Encapsulation makes it easier to change unexposed code. - -One common design pattern to enable encapsulation is the use of getters and setters methods to access fields instead of publicly exposing the field directly. These methods are often called `accessor methods`. A getter is simply a method that gets the value of the field, and a setter is a method that sets the value of a field. This makes it so you can hide how the field is implemented and protect the data integrity of your fields. - -Here is a simple example of using accessor methods. - -```java -public class GetSetExample { - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - // Keep fields private - private String name; -} -``` - -Initially this may seem like overhead, but when your fields get more complex, or you decide to store your data in a different way, or even a different place, the value of accessor methods becomes clearer. Consider an example where the field type is an array, and you don't want to expose a mutable version of the array with the getter. Additionally, you want to check to make sure all the numbers in the array are less than 100 on the setter. - -```java -public class GetSetExample { - public int[] getScores() { - int[] copy = new int[scores.length]; - System.arraycopy(scores, 0, copy, 0, scores.length); - return copy; - } - - public void setScores(int[] scores) { - for (var i = 0; i < scores.length; i++) { - if (scores[i] > 100) { - return; - } - } - this.scores = scores; - } - - private int[] scores = new int[10]; -} -``` - -If you have accessor methods for your fields then you can make changes like this without having to worry about how the code is being used. - -## Enums - -Enumerations allow you to create textual representations of labeled sets. You can define an enumeration in Java using the `enum` keyword. - -```java -public enum Peak { - NEBO, PROVO, SANTAQUIN, TIMPANOGOS, CASCADE, SPANISH, LONE -} - -``` - -Using enumerations help to make your code more readable, validate parameters, and restrict values to a closed set. Here is an example that uses the `Peak` enumeration to parse command line arguments. - -```java -public static void main(String[] args) { - try { - var e = Enum.valueOf(Peak.class, args[0].toUpperCase()); - - if (e == Peak.LONE) { - System.out.println("You chose Lone Peak"); - } - } catch (IllegalArgumentException ex) { - System.out.println("Unknown peak provided"); - } -} -``` - -## Things to Understand - -- What object references are and why we need them -- The differences between static methods and variables and instance methods and variables -- How constructors work in Java -- What constructor the compiler writes (and when it doesn't write one) -- What code the compiler adds to some constructors and why -- What the 'this' reference is used for -- When the 'this' reference is required and when it is optional -- What an enum is and how to implement one -- The standard order of elements in a Java class - -## Videos - -- 🎥 [Overview (2:47)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=8248d213-ef10-44e1-8dbf-ad5d0143c0f8&start=0) - [[transcript]](https://github.com/user-attachments/files/17756219/CS_240_Classes_and_Objects_Overview.pdf) -- 🎥 [Object References (10:00)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=cd1007ae-04da-4311-9e2d-ad5d0144b41a&start=0) - [[transcript]](https://github.com/user-attachments/files/17756222/CS_240_Object_References.pdf) -- 🎥 [Static Variables and Methods (7:07)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=c2af67a3-d801-4550-bffe-ad5d01493675&start=0) - [[transcript]](https://github.com/user-attachments/files/17756224/CS_240_Static_Variables_and_Methods.pdf) -- 🎥 [Getters and Setters (2:33)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=b9ff467d-a874-4778-9b2a-ad5d014b74ad&start=0) - [[transcript]](https://github.com/user-attachments/files/17756226/CS_240_Getters_and_Setters.pdf) -- 🎥 [Constructor Methods (9:59)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=0d212d67-270d-4775-8ebb-ad5d014c7721&start=0) - [[transcript]](https://github.com/user-attachments/files/17756229/CS_240_Constructor_Methods.pdf) -- 🎥 [Inheritance (4:10)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=74faf0ca-9a24-4800-8ded-ad5d014f9493&start=0) - [[transcript]](https://github.com/user-attachments/files/17756231/CS_240_Inheritance.pdf) -- 🎥 [Method Overriding (9:36)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=d47ce0c1-85e5-45a7-b56d-ad5d01512d78&start=0) - [[transcript]](https://github.com/user-attachments/files/17756232/CS_240_Method_Overriding.pdf) -- 🎥 [Implementing a Hashcode Method (9:46)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=a486e175-a53f-4aed-b436-ad5d015744ac&start=0) - [[transcript]](https://github.com/user-attachments/files/17707561/CS_240_Implementing_a_Hashcode_Method_Transcript.pdf) -- 🎥 [Method Overloading (1:57)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=7bec5f67-10c3-4b19-a0fc-ad640139627a&start=0) - [[transcript]](https://github.com/user-attachments/files/17756235/CS_240_Method_Overloading.pdf) -- 🎥 [The Final Keyword (2:10)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=c8298a1a-b65c-43bd-8928-ad64013a3b89&start=0) - [[transcript]](https://github.com/user-attachments/files/17756237/CS_240_The_Final_Keyword.pdf) -- 🎥 [The `this` Reference (3:21)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=4d34dffd-7fec-4c10-b15a-ad64013b245c&start=0) - [[transcript]](https://github.com/user-attachments/files/17756239/CS_240_The_.this._Reference.pdf) -- 🎥 [Enums (3:23)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=57082049-bdad-4525-a6a1-ad64013e1eab&start=0) - [[transcript]](https://github.com/user-attachments/files/17756242/CS_240_Enums.pdf) -- 🎥 [Object-Oriented Design Overview (5:29)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=77c184e5-8afd-4c56-84c8-ad64013f7a4b&start=0) - [[transcript]](https://github.com/user-attachments/files/17756245/CS_240_Object_Oriented_Design_Overview.pdf) - -## Demonstration code - -📁 [Simple Class Example](example-code/SimpleClassExample) - -📁 [Constructor Example](example-code/ConstructorExample) - -📁 [Enum Example](example-code/EnumExample) - -📁 [Equality Example](example-code/EqualityExample) - -📁 [Override Example](example-code/OverrideExample) - -📁 [Static Example](example-code/StaticExample) - -## Lecture files - -📁 [Lecture Files](lecture-files/) diff --git a/instruction/classes-and-objects/example-code/ConstructorExample/Employee.java b/instruction/classes-and-objects/example-code/ConstructorExample/Employee.java deleted file mode 100644 index aa216e05..00000000 --- a/instruction/classes-and-objects/example-code/ConstructorExample/Employee.java +++ /dev/null @@ -1,31 +0,0 @@ -package ConstructorExamples; - -import java.util.Date; - -public class Employee extends Person { - - private Date hireDate; - - public Employee(String firstName, String lastName) { - this(firstName, lastName, null); - } - - public Employee(String firstName, String lastName, Date birthDate) { - this(firstName, lastName, birthDate, null); - } - - public Employee(String firstName, String lastName, Date birthDate, Date hireDate) { - // What happens if you comment out the super call? Why? - // What happens if you comment out the this calls in the other constructors? - super(firstName, lastName, birthDate); - this.hireDate = hireDate; - } - - public Date getHireDate() { - return hireDate; - } - - public void setHireDate(Date hireDate) { - this.hireDate = hireDate; - } -} diff --git a/instruction/classes-and-objects/example-code/ConstructorExample/Person.java b/instruction/classes-and-objects/example-code/ConstructorExample/Person.java deleted file mode 100644 index e8d55aed..00000000 --- a/instruction/classes-and-objects/example-code/ConstructorExample/Person.java +++ /dev/null @@ -1,58 +0,0 @@ -package ConstructorExamples; - -import java.util.Date; - -public class Person { - - private String firstName; - private String lastName; - private Date birthDate; - - - public Person(String firstName, String lastName) { - this(firstName, lastName, null); - } - - public Person(String firstName, String lastName, Date birthDate) { - this.firstName = firstName; - this.lastName = lastName; - this.birthDate = birthDate; - } - -/* Another way to do the same thing - - public Person(String firstName, String lastName) { - this.firstName = firstName; - this.lastName = lastName; - } - - public Person(String firstName, String lastName, Date birthDate) { - this(firstName, lastName); - this.birthDate = birthDate; - } -*/ - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public Date getBirthDate() { - return birthDate; - } - - public void setBirthDate(Date birthDate) { - this.birthDate = birthDate; - } -} diff --git a/instruction/classes-and-objects/example-code/EnumExample/Gender.java b/instruction/classes-and-objects/example-code/EnumExample/Gender.java deleted file mode 100644 index 7c933b38..00000000 --- a/instruction/classes-and-objects/example-code/EnumExample/Gender.java +++ /dev/null @@ -1,10 +0,0 @@ -package EnumExamples; - -public enum Gender { - Male, Female; - - @Override - public String toString() { - return this == Male ? "m" : "f"; - } -} diff --git a/instruction/classes-and-objects/example-code/EnumExample/Person.java b/instruction/classes-and-objects/example-code/EnumExample/Person.java deleted file mode 100644 index 9eab3d61..00000000 --- a/instruction/classes-and-objects/example-code/EnumExample/Person.java +++ /dev/null @@ -1,32 +0,0 @@ -package EnumExamples; - -public class Person { - private String firstName; - private String lastName; - private String gender; - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public String getGender() { - return gender; - } - - // Problem: Gender can be set to any String, even if we only consider m and f to be valid - public void setGender(String gender) { - this.gender = gender; - } -} diff --git a/instruction/classes-and-objects/example-code/EnumExample/Person2.java b/instruction/classes-and-objects/example-code/EnumExample/Person2.java deleted file mode 100644 index 6778beea..00000000 --- a/instruction/classes-and-objects/example-code/EnumExample/Person2.java +++ /dev/null @@ -1,32 +0,0 @@ -package EnumExamples; - -public class Person2 { - private String firstName; - private String lastName; - private Gender gender; - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public Gender getGender() { - return gender; - } - - // Problem solved. Now gender can only be set to Gender.Male or Gender.Female - public void setGender(Gender gender) { - this.gender = gender; - } -} diff --git a/instruction/classes-and-objects/example-code/EqualityExample/EqualsEqualityExample.java b/instruction/classes-and-objects/example-code/EqualityExample/EqualsEqualityExample.java deleted file mode 100644 index 3b9a39c1..00000000 --- a/instruction/classes-and-objects/example-code/EqualityExample/EqualsEqualityExample.java +++ /dev/null @@ -1,26 +0,0 @@ -package EqualityExamples; - -import SimpleClassExample.Person; - -public class EqualsEqualityExample { - - public static void main(String [] args) { - Person p1 = new Person(); - p1.setFirstName("Jerod"); - p1.setLastName("Wilkerson"); - - Person p2 = p1; - - if(p1.equals(p2)){ - // True or False? - } - - p2 = new Person(); - p2.setFirstName("Jerod"); - p2.setLastName("Wilkerson"); - - if(p1.equals(p2)){ - // True or False? - } - } -} diff --git a/instruction/classes-and-objects/example-code/EqualityExample/ReferenceEqualityExample.java b/instruction/classes-and-objects/example-code/EqualityExample/ReferenceEqualityExample.java deleted file mode 100644 index 93cc5420..00000000 --- a/instruction/classes-and-objects/example-code/EqualityExample/ReferenceEqualityExample.java +++ /dev/null @@ -1,26 +0,0 @@ -package EqualityExamples; - -import SimpleClassExample.Person; - -public class ReferenceEqualityExample { - - public static void main(String [] args) { - Person p1 = new Person(); - p1.setFirstName("Jerod"); - p1.setLastName("Wilkerson"); - - Person p2 = p1; - - if(p1 == p2){ - // True or False? - } - - p2 = new Person(); - p2.setFirstName("Jerod"); - p2.setLastName("Wilkerson"); - - if(p1 == p2){ - // True or False? - } - } -} diff --git a/instruction/classes-and-objects/example-code/OverrideExample/Employee.java b/instruction/classes-and-objects/example-code/OverrideExample/Employee.java deleted file mode 100644 index be44b557..00000000 --- a/instruction/classes-and-objects/example-code/OverrideExample/Employee.java +++ /dev/null @@ -1,57 +0,0 @@ -package OverrideExample; - -import java.text.SimpleDateFormat; -import java.time.Month; -import java.util.Calendar; -import java.util.Date; - -public class Employee extends Person { - - private Date hireDate; - - public static void main(String [] args) { - Calendar birthDate = Calendar.getInstance(); - birthDate.set(1968, Month.JULY.ordinal(), 8); - - Employee emp = new Employee("Jerod", "Wilkerson", birthDate.getTime(), new Date()); - System.out.println(emp); - } - - public Employee(String firstName, String lastName) { - this(firstName, lastName, null); - } - - public Employee(String firstName, String lastName, Date birthDate) { - this(firstName, lastName, birthDate, null); - } - - public Employee(String firstName, String lastName, Date birthDate, Date hireDate) { - // What happens if you comment out the super call? Why? - // What happens if you comment out the this calls in the other constructors? - super(firstName, lastName, birthDate); - this.hireDate = hireDate; - } - - public Date getHireDate() { - return hireDate; - } - - public void setHireDate(Date hireDate) { - this.hireDate = hireDate; - } - - @Override - public String toString() { - String personString = super.toString(); - - personString = personString.replace("Person", "Employee"); - personString = personString + "\b"; - - SimpleDateFormat dateFormat = new SimpleDateFormat("M/d/YYYY"); - String formattedHireDate = dateFormat.format(hireDate); - - return personString + - ", hireDate=" + formattedHireDate + - '}'; - } -} diff --git a/instruction/classes-and-objects/example-code/OverrideExample/Person.java b/instruction/classes-and-objects/example-code/OverrideExample/Person.java deleted file mode 100644 index d2114667..00000000 --- a/instruction/classes-and-objects/example-code/OverrideExample/Person.java +++ /dev/null @@ -1,57 +0,0 @@ -package OverrideExample; - -import java.text.SimpleDateFormat; -import java.util.Date; - -public class Person { - - private String firstName; - private String lastName; - private Date birthDate; - - public Person(String firstName, String lastName) { - this(firstName, lastName, null); - } - - public Person(String firstName, String lastName, Date birthDate) { - this.firstName = firstName; - this.lastName = lastName; - this.birthDate = birthDate; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public Date getBirthDate() { - return birthDate; - } - - public void setBirthDate(Date birthDate) { - this.birthDate = birthDate; - } - - @Override - public String toString() { - SimpleDateFormat dateFormat = new SimpleDateFormat("M/d/YYYY"); - String formattedBirthDate = dateFormat.format(birthDate); - - return "Person{" + - "firstName='" + firstName + '\'' + - ", lastName='" + lastName + '\'' + - ", birthDate=" + formattedBirthDate + - '}'; - } -} diff --git a/instruction/classes-and-objects/example-code/SimpleClassExample/Person.java b/instruction/classes-and-objects/example-code/SimpleClassExample/Person.java deleted file mode 100644 index 12498ae5..00000000 --- a/instruction/classes-and-objects/example-code/SimpleClassExample/Person.java +++ /dev/null @@ -1,34 +0,0 @@ -package SimpleClassExample; - -import java.util.Date; - -public class Person { - - private String firstName; - private String lastName; - private Date birthDate; - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public Date getBirthDate() { - return birthDate; - } - - public void setBirthDate(Date birthDate) { - this.birthDate = birthDate; - } -} diff --git a/instruction/classes-and-objects/example-code/SimpleClassExample/StaticExample/StaticExample3.java b/instruction/classes-and-objects/example-code/SimpleClassExample/StaticExample/StaticExample3.java deleted file mode 100644 index 12e54353..00000000 --- a/instruction/classes-and-objects/example-code/SimpleClassExample/StaticExample/StaticExample3.java +++ /dev/null @@ -1,16 +0,0 @@ -package StaticExamples; - -public class StaticExample3 { - - private int myInstanceVariable; - - public static void main(String [] args) { - StaticExample3 instance = new StaticExample3(); - instance.myInstanceVariable = 10; - instance.myInstanceMethod(); - } - - public void myInstanceMethod() { - - } -} diff --git a/instruction/classes-and-objects/example-code/SimpleClassExample/StaticExample/StaticExampleWrong1.java b/instruction/classes-and-objects/example-code/SimpleClassExample/StaticExample/StaticExampleWrong1.java deleted file mode 100644 index 584d8666..00000000 --- a/instruction/classes-and-objects/example-code/SimpleClassExample/StaticExample/StaticExampleWrong1.java +++ /dev/null @@ -1,15 +0,0 @@ -package StaticExamples; - -public class StaticExampleWrong1 { - - private int myInstanceVariable; - - public static void main(String [] args) { -// myInstanceVariable = 10; -// myInstanceMethod(); - } - - public void myInstanceMethod() { - - } -} diff --git a/instruction/classes-and-objects/example-code/SimpleClassExample/StaticExample/StaticExampleWrong2.java b/instruction/classes-and-objects/example-code/SimpleClassExample/StaticExample/StaticExampleWrong2.java deleted file mode 100644 index ffbd057f..00000000 --- a/instruction/classes-and-objects/example-code/SimpleClassExample/StaticExample/StaticExampleWrong2.java +++ /dev/null @@ -1,15 +0,0 @@ -package StaticExamples; - -public class StaticExampleWrong2 { - - private static int myInstanceVariable; - - public static void main(String [] args) { - myInstanceVariable = 10; - myInstanceMethod(); - } - - public static void myInstanceMethod() { - - } -} diff --git a/instruction/classes-and-objects/lecture-files/rodham-files/Person.java b/instruction/classes-and-objects/lecture-files/rodham-files/Person.java deleted file mode 100644 index 4fad17ca..00000000 --- a/instruction/classes-and-objects/lecture-files/rodham-files/Person.java +++ /dev/null @@ -1,80 +0,0 @@ -package javaclasses; - -public abstract class Person { - - private static int idCounter = 1; - private static int generateId() { - return idCounter++; - } - - private int id; - private String name; - private int age; - - public Person(String name, int age) { - setId(generateId()); - setName(name); - setAge(age); - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getAge() { - return age; - } - - public void setAge(int age) { - this.age = age; - } - - @Override - public String toString() { - return String.format("name: %s, age: %d", name, age); - } - - @Override - public boolean equals(Object o) { - if (o == null) { - return false; - } - - if (o == this) { - return true; - } - - if (o.getClass() != this.getClass()) { - return false; - } - - Person p = (Person)o; - - return (name.equals(p.name) && (age == p.age)); - } - - @Override - public int hashCode() { - return (name.hashCode() * age * id); - } - - public final int getPriority() { - return (agePriority() + categoryPriority()); - } - - protected abstract int agePriority(); - - protected abstract int categoryPriority(); -} diff --git a/instruction/classes-and-objects/lecture-files/rodham-files/Student.java b/instruction/classes-and-objects/lecture-files/rodham-files/Student.java deleted file mode 100644 index 0ebd47a8..00000000 --- a/instruction/classes-and-objects/lecture-files/rodham-files/Student.java +++ /dev/null @@ -1,63 +0,0 @@ -package javaclasses; - -public class Student extends Person { - - private YearinSchool year; - private float gpa; - - - public Student(String name, int age, YearinSchool year, float gpa) { - super(name, age); - - setYear(year); - setGpa(4.0f); - } - - public YearinSchool getYear() { - return year; - } - - public void setYear(YearinSchool year) { - this.year = year; - } - - public float getGpa() { - return gpa; - } - - public void setGpa(float gpa) { - this.gpa = gpa; - } - - @Override - public String toString() { - return String.format("%s, year: %s, gpa; %f", super.toString(), year, gpa); - } - - @Override - public boolean equals(Object o) { - if (!super.equals(o)) { - return false; - } - - Student s = (Student)o; - - return (year.equals(s.year) && gpa == s.gpa); - } - - @Override - public int hashCode() { - int hash = super.hashCode(); - return (hash ^ year.hashCode() * (int)gpa); - } - - @Override - protected int agePriority() { - return getAge() / 10; - } - - @Override - protected int categoryPriority() { - return 5; - } -} diff --git a/instruction/classes-and-objects/lecture-files/rodham-files/YearinSchool.java b/instruction/classes-and-objects/lecture-files/rodham-files/YearinSchool.java deleted file mode 100644 index fe1c86ec..00000000 --- a/instruction/classes-and-objects/lecture-files/rodham-files/YearinSchool.java +++ /dev/null @@ -1,9 +0,0 @@ -package javaclasses; - -public enum YearinSchool { - Freshman, - Sophomore, - Junior, - Senior, - Graduate, -} diff --git a/instruction/code-coverage/code-coverage.md b/instruction/code-coverage/code-coverage.md deleted file mode 100644 index 8b5243d6..00000000 --- a/instruction/code-coverage/code-coverage.md +++ /dev/null @@ -1,37 +0,0 @@ -# Code Coverage - -🖥️ [Slides](https://docs.google.com/presentation/d/14fDhNHsnU-knkVYmfNDsIwZQ027tu_DB/edit?usp=sharing&ouid=114081115660452804792&rtpof=true&sd=true) - -🖥️ [Lecture Videos](#videos) - -Once you begin using test driven development, you start to rely on tests to tell you when something is broken. This can lead to a state of false confidence if your tests don't actually cover all of the paths through your code. This happens when you have tests that only cover some conditional branches, when the tests don't cover the exceptional branches, or when not all of the possible range of inputs are represented. - -Modern integrated development environments (IDEs) often provide tools for determining the amount of code coverage that your tests provide. You can use the code coverage tool built into IntelliJ to see how much you should trust the tests in your project. To access the coverage tool, you choose the `Run test with Coverage` option from the test execution actions. This will pop up a window that shows you how much of your code is being executed by the test. The coverage tool shows a green marker next to all the code that was executed, and a red marker next to lines that were skipped by the test. - -The following video shows a function called `branch` that has three paths. In order to cover all the code of the function, the test must provide a `true`, `false`, and `null` value for the parameter. You can see the coverage increasing to 100% as we successively enable all of the necessary testing code required for all of the branches. - -![Code coverage](codeCoverage.gif) - -## How much coverage? - -The subject of what percentage of coverage is necessary to enable confidence in your code is a very opinionated topic. Some developers feel that anything less that 100% is a problem. Others feel that obtaining 100% creates unmaintainable tests, causes harmful overhead in the actual code, and decrease productivity. The correct answer to this question is dependent on the specifics of the project you are working on. - -You should note that just because you have 100% coverage, does not mean that all paths through the code are fully exercised, or that your code is correct. Consider the case where you have a function that takes an object and references it. - -```java -public static void oneHundredPercentCoverage(Object obj) { - obj.toString(); -} -``` - -You can write a test that calls the function and obtains 100% coverage, but unless the test includes a call where `obj` is null, you will have an unhandled `RuntimeException` waiting to happen to your users. - -Code coverage can also give you a false sense of security if all of your testing is simple unit tests. Many bugs only happen when your application is running from end to end. This includes a front end client, middleware business logic, and data services. Unit tests often stub out, or mock, input and output in order to isolate the test. That means it can easily miss real world parameter values, and failure cases, that occur only when the application is executing in a real world environment. - -With all of that said, code coverage does provide an important indicator of the value your testing is providing. It can also point you to locations in your code that are problematic and need review. This is especially true for code that is highly complex, has a high branching factor, or has paths the rarely get executed. - -## Videos - -- 🎥 [Code Coverage Overview (8:18)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=5fc1d70d-9c34-41f1-b195-b1a001161540&start=0) - [[transcript]](https://github.com/user-attachments/files/17707673/CS_240_Code_Coverage_Overview_Transcript.pdf) -- 🎥 [Code Coverage Tools (1:38)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=c58109b6-ea78-4e98-8554-b1a001187fdb&start=0) - [[transcript]](https://github.com/user-attachments/files/17707688/CS_240_Code_Coverage_Tools_Transcript.pdf) -- 🎥 [Intellij Code Coverage (3:49)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=cbb47ecd-2023-4911-933b-b1a001195835&start=0) - [[transcript]](https://github.com/user-attachments/files/17707699/CS_240_IntelliJ_Code_Coverage_Transcript.pdf) diff --git a/instruction/code-coverage/codeCoverage.gif b/instruction/code-coverage/codeCoverage.gif deleted file mode 100644 index d408f32a..00000000 Binary files a/instruction/code-coverage/codeCoverage.gif and /dev/null differ diff --git a/instruction/collections/collections.md b/instruction/collections/collections.md deleted file mode 100644 index 559c9bfe..00000000 --- a/instruction/collections/collections.md +++ /dev/null @@ -1,137 +0,0 @@ -# Java Collections - -🖥️ [Slides](https://docs.google.com/presentation/d/1yAxwkW1qClRlFBxAokyBvfDhuTI6LXmA/edit?usp=sharing&ouid=114081115660452804792&rtpof=true&sd=true) - -🖥️ [Lecture Videos](#videos) - -📖 **Required Reading**: Core Java for the Impatient - -- Chapter 7: Collections - -The Java Collection library provide several useful utility classes for dealing with data structures. This includes things like lists, sets, and maps. Using the standard collections library makes it so that you don't have to write this code yourself. You can also be confident that the code has been thoroughly tested, is secure, and is multithreaded where appropriate. - -![Collections](collections.png) - -Most of the JDK collection objects are contained in the [java.util](https://docs.oracle.com/javase/8/docs/api/java/util/package-summary.html) package. It is worth the time to browser the JavaDocs for this package and become familiar with what it offers. Some of the more commonly used interfaces include [List](https://docs.oracle.com/javase/8/docs/api/java/util/List.html), [Map](https://docs.oracle.com/javase/8/docs/api/java/util/Map.html), [Set](https://docs.oracle.com/javase/8/docs/api/java/util/Set.html), and [Iterator](https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html). The package also provides various implementations of the interfaces such as [HashMap](https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html), [ArrayList](https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html), and [TreeSet](https://docs.oracle.com/javase/8/docs/api/java/util/TreeSet.html). - -## ArrayList Example - -Here is an example of using the `ArrayList` class. - -```java -import java.util.ArrayList; - -public static class MountainList { - ArrayList mountains = new ArrayList(); - - public MountainList() { - mountains.add("Nebo"); - mountains.add("Timpanogos"); - mountains.add("Lone Peak"); - mountains.add("Cascade"); - mountains.add("Provo"); - mountains.add("Spanish Fork"); - mountains.add("Santaquin"); - } - - public void print() { - for (var m : mountains) { - System.out.println(m); - } - } - - public static void main(String[] args) { - var mountains = new MountainList(); - mountains.print(); - } -} -``` - -## HashMap Example - -Here is an example of using the `HashMap` class. - -```java -import java.util.HashMap; - -public static class MountainMap { - HashMap mountains = new HashMap<>(); - - public MountainMap() { - mountains.put("Nebo", 11928); - mountains.put("Timpanogos", 11750); - mountains.put("Lone Peak", 11253); - mountains.put("Cascade", 10908); - mountains.put("Provo", 11068); - mountains.put("Spanish Fork", 10192); - mountains.put("Santaquin", 10687); - } - - public void print() { - for (var m : mountains.entrySet()) { - System.out.printf("%s, height: %d%n", m.getKey(), m.getValue()); - } - } - - public static void main(String[] args) { - var mountains = new MountainMap(); - mountains.print(); - } -} -``` - -## Equals and HashCode - -When we previously discussed the [Java Object](../java-object-class/java-object-class.md) class we talked about the importance of overriding the equals and hashCode methods. The JDK collection objects make extensive use of these methods and so it is vital that you implement them on any class that you use with collection objects such as a `Map`. - -## Comparable - -If you are going to use your objects with collections and operations that sort your objects, you must also implement the `Comparable` interface. This provides the ability to define the ordering of your object based on the values they contain. - -Comparable returns a negative integer if the object is less, zero if they are equal, or a positive integer if the object is greater than the object provided as a parameter to `compareTo`. - -```java -public class ComparableExample implements Comparable { - final private char value; - - ComparableExample(char value) { - this.value = value; - } - - @Override - public int compareTo(ComparableExample o) { - return value - o.value; - } - - @Override - public String toString() { - return String.format("%c", value); - } - - public static void main(String[] args) { - var items = new ComparableExample[]{ - new ComparableExample('r'), - new ComparableExample('a'), - new ComparableExample('b') - }; - - Arrays.sort(items); - for (var i : items) { - System.out.println(i); - } - // Outputs: a b r - } -} -``` - -## Things to Understand - -- The interfaces and classes that make up the Java collection API -- What each interface and class is used for -- The importance of overriding the `equals(...)` and `hashCode()` methods of classes that will be placed in collections -- The importance of implementing the Comparable interface in classes that will be placed in collections - -## Videos - -- 🎥 [Java Collections (22:57)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=7f2f800e-d46e-4ce4-8839-ad5f011fa7a1&start=0) - [[transcripts]](https://github.com/user-attachments/files/17780595/CS_240_Java_Collections_Overview.pdf) -- 🎥 [Using Collections Correctly (19:26)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=bea26db3-5825-4df2-9ba0-ad5f01260f7e&start=0) - [[transcripts]](https://github.com/user-attachments/files/17780597/CS_240_Java_Collections_Using_Collections_Correctly.pdf) diff --git a/instruction/collections/collections.png b/instruction/collections/collections.png deleted file mode 100644 index 75e1aea7..00000000 Binary files a/instruction/collections/collections.png and /dev/null differ diff --git a/instruction/command-line-builds/buildWithMaven.png b/instruction/command-line-builds/buildWithMaven.png deleted file mode 100644 index ff126d23..00000000 Binary files a/instruction/command-line-builds/buildWithMaven.png and /dev/null differ diff --git a/instruction/command-line-builds/command-line-builds.md b/instruction/command-line-builds/command-line-builds.md deleted file mode 100644 index d1d07a51..00000000 --- a/instruction/command-line-builds/command-line-builds.md +++ /dev/null @@ -1,344 +0,0 @@ -# Command-line Builds - -🖥️ [Slides](https://docs.google.com/presentation/d/1Li3p-74-4LoosHmyB_u2b5kpi_vkNgz6/edit#slide=id.p1) - -🖥️ [Lecture Videos](#videos) - -📖 **Required Reading**: - -- [Maven in 5 Minutes](https://maven.apache.org/guides/getting-started/maven-in-five-minutes.html) - -📖 **Optional Reading**: - -- OPTIONAL: [Maven Getting Started Guide](https://maven.apache.org/guides/getting-started/index.html) - -When developing a software project, you must frequently "build" the software. The "build process" includes activities such as compiling the code, compiling and running automated test cases, packaging the code into distributable files, generating code and test quality reports, etc. IDEs such as IntelliJ are great, but using them to build a project can be a partially manual and error-prone process. For many reasons, it can be advantageous to create a "command-line build" for your project, which allows anyone to compile, run, test, package, deploy, and validate the software using simple shell (ie, command-line) commands. Fortunately, there are many tools available to help create a command-line build for a project, such as Apache Maven. - -## Installing Maven - -To get started with Maven, you need to install it. You can find the installation program at the official download repository. - -> [https://maven.apache.org/download.cgi](https://maven.apache.org/download.cgi) - -> [!NOTE] -> -> When you install IntelliJ, it installed a copy of Maven. If you want to use that installation, then you will have to update your command line path to make it accessible outside of IntelliJ. For example, if you are using a Mac you would include something like the following in your profile file. If you are using Windows then you will need to update the `Environment Variables` in your operating system settings. - -```sh -export PATH="$PATH:/Applications/IntelliJ IDEA CE.app/Contents/plugins/maven/lib/maven3/bin" -``` - -Once you have installed Maven you can verify it is working by opening up a console window and running the following command in order to see what version you are using. - -```sh -➜ mvn --version - -Apache Maven 3.9.2 (c9616018c7a021c1c39be70fb2843d6f5f9b8a1c) -Maven home: /Applications/IntelliJ IDEA CE.app/Contents/plugins/maven/lib/maven3 -``` - -## Creating a Maven Project - -Let's go ahead and create an application that we can use to demonstrate how Maven works. We ill start with the following Main.java code. - -```java -public class Main { - public static void main(String[] args) { - System.out.println("Hello Maven!"); - } -} -``` - -In order to use Maven as our build tool we need to follow a specific directory structure for the project. Our code must be put in a `src/main/java` directory. Any tests that we have must be placed in a `src/test/java` directory. - -We also create a file in the root of our project that is named `pom.xml` that tells Maven how to run. We will discuss what this file contains in a minute. - -When you build your code it will create, and output, to a directory named `target`. - -```txt - -├── pom.xml -├── src -│   ├── main -│   │   └── java -│   │      └── Main.java -│   └── test -│   └── java -│   └── MainTest.java -└── target - ├── classes - │   └── Main.class - └── demo.jar -``` - -## Project Object Model - -The Project Object Model, or `pom.xml`, file defines everything that Maven needs to know in order to build, test, and deploy an artifact. For our purposes, our artifact is our application. A basic `pom.xml` file looks like the following. - -```xml - - - 4.0.0 - - org.example - example - 1.0-SNAPSHOT - - - 21 - 21 - UTF-8 - - -``` - -This defines the name of the artifact and what Java version is required to build the application. - -## Executing a Phase - -With Maven installed, the correct directory structure, and `pom.xml` file we can compile our code by opening a console window and executing Maven (`mvn`) with the `compile` parameter. - -```sh -➜ mvn compile - -[INFO] --< org.example:example >-- -[INFO] Building example 1.0-SNAPSHOT -[INFO] from pom.xml -[INFO] --------------------------- -[INFO] BUILD SUCCESS -``` - -When you run `mvn` you ask it to execute a `phase`. This represents things like compile, clean, test, package, or deploy. When Maven executes a phase, it looks for a `plugin` containing a `goal` that is registered to execute as part of the phase. There are default plugins that deploy with Maven, but you can also download or create your own plugins. - -| Term | Definition | -| --------- | -------------------------------------------------------------------------------------------------------------------- | -| Lifecycle | A collection of phases for building or distributing an artifact. | -| Phase | A specific step in a lifecycle. | -| Goal | The code that actually contributes to the execution of a lifecycle phase. Each Goal is assigned to a specific phase. | -| Plugin | A binary container for goal code. You register one or more plugins to run as part of your artifact lifecycle. | - -Here is a list of some of the commonly used phases that are included in Maven by default. - -| Phase | Plugin:goal | Purpose | -| ------- | ---------------- | ------------------------------------------------ | -| clean | clean:clean | Delete the `target` directory. | -| compile | compiler:compile | Compile the code found in the `src/main/java` | -| test | surefire:test | Run test found in the `src/test/java` directory. | -| package | jar:jar | Create a jar file. | - -### Executing Code - -Once we have built our code with the `mvn compile` command we can execute it using the standard `java` runtime. - -```sh -➜ java -cp target/classes Main -Hello Maven! -``` - -We can also install a custom plugin that knows how to execute java code. We do this by adding the following to our `pom.xml` file. - -```xml - - - - org.codehaus.mojo - exec-maven-plugin - 3.1.1 - - Main - - - - -``` - -Now we can run the `exec:java` goal. - -```sh -➜ mvn exec:java - -[INFO] --< org.example:example >--- -[INFO] Building from pom.xml -[INFO] ------ exec:3.1.1:java ----- -Hello Maven! -``` - -### Jar - -If you want to compile your application into a jar file then you can add the following to your `pom.xml` file. The `packaging` element specifies that we want to output to a jar file. The `finalName` element specifies the name of the jar file. - -```xml - jar - - - demo - - - org.apache.maven.plugins - maven-assembly-plugin - 3.6.0 - - - package - - single - - - - - - Main - - - - - jar-with-dependencies - - - - - - - -``` - -Now we can run the `package` goal. - -```sh -➜ mvn package - -[INFO] --< org.example:example >--- -[INFO] Building jar: demo.jar -[INFO] ---------------------------- -[INFO] BUILD SUCCESS -``` - -### Dependencies - -Maven also helps manage our application dependencies. To include a dependency in your project you just need to add the information about the dependency to your `pom.xml`. For example, if you wanted to include JUnit and Gson to your project you would add the following. - -```xml - - - org.junit.jupiter - junit-jupiter - 5.10.0 - - - com.google.code.gson - gson - 2.10.1 - - -``` - -By default, Maven will pull these dependencies from the central public repository hosted at [https://repo.maven.apache.org/maven2/](https://repo.maven.apache.org/maven2/). You can search and explore the repository using [mvnRepository.com](https://mvnrepository.com/). - -![mvnRepository](mvnRepository.png) - -After you have searched and found a package you want to include as a dependency you can select the desired version and it will display the Maven XML that you need to copy into your `pom.xml`. - -![JUnit dependency](junitDependency.png) - -With the dependency in your project file you can immediately begin using it in your code. We can demonstrate this by modifying our main function to use Gson. - -```java -import com.google.gson.Gson; -import java.util.Map; - -public class Main { - public static void main(String[] args) { - var greeting = Map.of("greeting", "Hello", "object", "Maven"); - var serializer = new Gson(); - String json = serializer.toJson(greeting); - - System.out.println(json); - } -} -``` - -We can build and run our code by executing `mvn exec:java`. Notice now that it outputs Json now instead of a simple string. - -```sh -➜ mvn exec:java - -[INFO] --< org.example:example >--- -[INFO] Building from pom.xml -[INFO] ------ exec:3.1.1:java ----- -{"object":"Maven","greeting":"Hello"} -``` - -Since we also install JUnit, we can write a unit test and add it to a file in the `src/test/java` directory. - -```java -import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; - -class MainTest { - @Test - void testMain() { - assertDoesNotThrow(() -> Main.main(new String[]{"cow"})); - } -} -``` - -We can run the test by executing `mvn test`. - -```sh -➜ mvn test - -[INFO] --< org.example:example >--- -[INFO] Building from pom.xml -[INFO] ------ exec:3.1.1:java ----- -[INFO] -[INFO] ------------------------------------------------------- -[INFO] T E S T S -[INFO] ------------------------------------------------------- -[INFO] Running MainTest -{"greeting":"Hello","object":"Maven"} -[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.038 s -- in MainTest -``` - -## IntelliJ integration - -Configuring you build, testing, and deployment process to run from the command line is great for automated processes, but it is also nice to use an IDE, like IntelliJ, for your development work. For this reason, IntelliJ includes the ability to use Maven for building, testing, and packaging jar files. - -To create a project that uses Maven you select `Maven` as the build system when you create a new project. You can also select a `Maven Archetype`. This allows you to select a set of application templates that help bootstrap your efforts. - -![New Maven Project](newMavenProject.png) - -This will create a `pom.xml` file along with the directory structure that Maven requires. - -Once you have created your project you need to tell IntelliJ that you want to use Maven for the building and running your code. This is found in the application settings. - -![Build with Maven](buildWithMaven.png) - -You can also find and insert dependencies directly into your `pom.xml` using IntelliJ's dependency generation functionality. To do this, you open the `pom.xml` file, right click, and select the Generate|Dependency option. - -![generate dependency](generateDependency.png) - -This will display a search dialog at queries [mvnRepository.com](https://mvnrepository.com/) to help you find the package you are looking for. - -![Maven Artifact Search](mavenArtifactSearch.png) - -Once you press `Add` your `pom.xml` file will be updated and you are ready to go. - -## Things to Understand - -- The benefits of using command-line builds -- All popular language environments have tools for creating command-line builds -- How to run a command-line build -- Typical features of command-line build tools, such as dependency management -- Have a general understanding of how Maven can be used to create a command-line build for a Java project -- Have a general understanding of how Maven can be used with IntelliJ - -## Videos - -- 🎥 [Command-line Builds (5:45)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=96027f51-b4f0-4d5b-8f32-b19a015a9d4b) - [[transcript]](https://github.com/user-attachments/files/17707795/CS_240_Command_line_Builds_Transcript.pdf) -- 🎥 [Maven (7:10)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=f64c2663-19d9-411d-9f65-b19a015d6350) - [[transcript]](https://github.com/user-attachments/files/17707798/CS_240_Maven_Transcript.pdf) -- 🎥 [Maven Project Structure (8:45)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=e282502e-0b40-4c40-99c1-b19a015ff622) - [[transcript]](https://github.com/user-attachments/files/17707802/CS_240_Maven_Project_Structure_Transcript.pdf) -- 🎥 [IDE + Automated Builds (4:04)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=98bcf610-19d1-46ef-bd61-b19a0162f956) - [[transcript]](https://github.com/user-attachments/files/17707804/CS_240_IDE_Automated_Builds_Transcript.pdf) - -## Demonstration code - -📁 [Building Chess with Maven](example-code/) diff --git a/instruction/command-line-builds/example-code/chess/client/pom.xml b/instruction/command-line-builds/example-code/chess/client/pom.xml deleted file mode 100644 index 5db7557f..00000000 --- a/instruction/command-line-builds/example-code/chess/client/pom.xml +++ /dev/null @@ -1,134 +0,0 @@ - - - - - 4.0.0 - - - edu.byu.cs240 - chess - 1.0 - - - edu.byu.cs240 - client - 1.0 - - client - - jar - - - - com.google.code.gson - gson - compile - - - edu.byu.cs240 - shared - compile - - - org.junit.jupiter - junit-jupiter - test - - - org.glassfish.tyrus.bundles - tyrus-standalone-client - compile - - - - - - - org.apache.maven.plugins - maven-clean-plugin - - - org.apache.maven.plugins - maven-resources-plugin - - - org.apache.maven.plugins - maven-compiler-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - @{surefireArgLine} - true - 1 - true - - - - org.apache.maven.plugins - maven-jar-plugin - - - org.apache.maven.plugins - maven-install-plugin - - - org.apache.maven.plugins - maven-deploy-plugin - - - org.apache.maven.plugins - maven-assembly-plugin - - - package - - single - - - - - ui.Client - - - - jar-with-dependencies - - - - - - - org.codehaus.mojo - exec-maven-plugin - - ui.Client - - - - org.jacoco - jacoco-maven-plugin - - - - - - - - org.apache.maven.plugins - maven-site-plugin - - - org.apache.maven.plugins - maven-project-info-reports-plugin - - - org.apache.maven.plugins - maven-checkstyle-plugin - - - - - diff --git a/instruction/command-line-builds/example-code/chess/pom.xml b/instruction/command-line-builds/example-code/chess/pom.xml deleted file mode 100644 index 4269ce43..00000000 --- a/instruction/command-line-builds/example-code/chess/pom.xml +++ /dev/null @@ -1,173 +0,0 @@ - - - 4.0.0 - - edu.byu.cs240 - chess - 1.0 - - chess - - pom - - - shared - server - client - - - - http://www.example.com - - - UTF-8 - 16 - 16 - - - - - - com.google.code.gson - gson - 2.10.1 - - - edu.byu.cs240 - shared - 1.0 - - - org.junit.jupiter - junit-jupiter - 5.9.0 - - - org.glassfish.tyrus.bundles - tyrus-standalone-client - 1.15 - - - mysql - mysql-connector-j - 9.4.0 - - - org.slf4j - slf4j-simple - 2.0.13 - - - io.javalin - javalin - 6.4.0 - - - edu.byu.cs240 - passoff-dependencies - 1.0 - - - - - - - - - org.apache.maven.plugins - maven-clean-plugin - 3.1.0 - - - org.apache.maven.plugins - maven-resources-plugin - 3.0.2 - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.0 - - - org.apache.maven.plugins - maven-surefire-plugin - 2.22.1 - - - org.apache.maven.plugins - maven-jar-plugin - 3.0.2 - - - org.apache.maven.plugins - maven-install-plugin - 2.5.2 - - - org.apache.maven.plugins - maven-deploy-plugin - 2.8.2 - - - org.apache.maven.plugins - maven-assembly-plugin - 3.6.0 - - - org.codehaus.mojo - exec-maven-plugin - 3.1.0 - - - org.jacoco - jacoco-maven-plugin - 0.8.10 - - - chess-prepare-agent - - prepare-agent - - - ${project.build.directory}/jacoco.exec - surefireArgLine - - - - chess-report - - report - - - ${project.build.directory}/jacoco.exec - ${project.reporting.outputDirectory}/jacoco - - - - - - - - - - - - org.apache.maven.plugins - maven-site-plugin - 3.7.1 - - - org.apache.maven.plugins - maven-project-info-reports-plugin - 3.0.0 - - - org.apache.maven.plugins - maven-checkstyle-plugin - 3.3.0 - - - - - diff --git a/instruction/command-line-builds/example-code/chess/server/libs/passoff-dependencies.jar b/instruction/command-line-builds/example-code/chess/server/libs/passoff-dependencies.jar deleted file mode 100644 index dba4d889..00000000 Binary files a/instruction/command-line-builds/example-code/chess/server/libs/passoff-dependencies.jar and /dev/null differ diff --git a/instruction/command-line-builds/example-code/chess/server/pom.xml b/instruction/command-line-builds/example-code/chess/server/pom.xml deleted file mode 100644 index 0caf7a75..00000000 --- a/instruction/command-line-builds/example-code/chess/server/pom.xml +++ /dev/null @@ -1,158 +0,0 @@ - - - - - 4.0.0 - - - edu.byu.cs240 - chess - 1.0 - - - edu.byu.cs240 - server - 1.0 - - server - - jar - - - - com.google.code.gson - gson - compile - - - mysql - mysql-connector-j - runtime - - - org.slf4j - slf4j-simple - compile - - - io.javalin - javalin - compile - - - edu.byu.cs240 - shared - compile - - - org.junit.jupiter - junit-jupiter - test - - - edu.byu.cs240 - passoff-dependencies - test - - - org.glassfish.tyrus.bundles - tyrus-standalone-client - test - - - - - - - org.apache.maven.plugins - maven-clean-plugin - - - org.apache.maven.plugins - maven-resources-plugin - - - org.apache.maven.plugins - maven-compiler-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - @{surefireArgLine} - true - 1 - true - - - - - org.apache.maven.plugins - maven-jar-plugin - - - org.apache.maven.plugins - maven-install-plugin - - - org.apache.maven.plugins - maven-deploy-plugin - - - org.apache.maven.plugins - maven-assembly-plugin - - - package - - single - - - - - server.Server - - - - jar-with-dependencies - - - - - - - org.codehaus.mojo - exec-maven-plugin - - server.Server - - - - org.jacoco - jacoco-maven-plugin - - - - - - - - org.apache.maven.plugins - maven-site-plugin - - - org.apache.maven.plugins - maven-project-info-reports-plugin - - - org.apache.maven.plugins - maven-checkstyle-plugin - - - - - diff --git a/instruction/command-line-builds/example-code/chess/server/web/favicon.ico b/instruction/command-line-builds/example-code/chess/server/web/favicon.ico deleted file mode 100644 index 813400d1..00000000 Binary files a/instruction/command-line-builds/example-code/chess/server/web/favicon.ico and /dev/null differ diff --git a/instruction/command-line-builds/example-code/chess/server/web/index.css b/instruction/command-line-builds/example-code/chess/server/web/index.css deleted file mode 100644 index c05750fd..00000000 --- a/instruction/command-line-builds/example-code/chess/server/web/index.css +++ /dev/null @@ -1,91 +0,0 @@ -html { - font-family: sans-serif; - background: #f7f0e0; - color: #343434; -} -body { - max-width: 80em; -} -table { - border-spacing: 0.5em; -} -.chess-icon { - font-size: 2em; -} -td { - background: #dad6bf; - padding: 1em; - border-radius: 5px; -} -.endpoint { - background: #b8b5a2; - color: rgb(84 84 68); - text-decoration: none; - font-weight: 600; - padding: 0 1em; - text-align: left; - cursor: pointer; -} -.endpoint:hover { - background: #a3a08f; - color: rgb(236, 236, 236); -} -.method { -font-size:smaller; -padding-bottom:.5em; - color: #7076bf; -} -.description { - font-weight: 800; - display: block; - padding: 0 0 0.25em 0; -} -label { - color: #694d01; -} -input, -textarea { - display: block; - width: 90%; - max-width: 70em; - margin: 0.5em 0 0 0; - padding: 0.25em; -} -textarea { - height: 20em; - padding: 1em; -} -.input { - margin: 1em 0; -} -.box { - border-radius: 5px; - background: #dad6bf; - padding: 0.5em 2em 2em; - margin: 1em; -} -button { - background-color: #786907; - border-radius: 5px; - border-style: none; - color: #fff; - cursor: pointer; - font-size: 16px; - height: 30px; - width: 60px; - margin-left: -4px; -} -button:hover { - opacity: 0.8; -} -button:active { - background-color: #373003; -} -#response { - color: #4e3e15; -} -code { - background-color: #e8e0cb; - border-radius: 5px; - padding: 0.05em; -} diff --git a/instruction/command-line-builds/example-code/chess/server/web/index.html b/instruction/command-line-builds/example-code/chess/server/web/index.html deleted file mode 100644 index 9dffd06c..00000000 --- a/instruction/command-line-builds/example-code/chess/server/web/index.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - CS 240 Chess Server - - - - - - - -

CS 240 Chess Server

-

- The CS 240 Chess Server Web API is described below. Some of the APIs require a request body to be sent (like - /user/login and /user/register), while others require an Authorization authToken - (received at login). To view the required JSON format, click on a command below and look at the example request - body. To try out an API, modify the request as needed, and press Send. -

- -

Endpoints

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
[POST]
-
/user
-
- Register a user If successful, an authorization authToken is returned. You - may use the authToken with future requests that require authorization. No authorization authToken is - required - to call this endpoint. -
-
[POST]
-
/session
-
- Log in a user If successful, an authorization authToken is returned. You - may - use the authToken with future requests that require authorization. No authorization authToken is required to - call this endpoint. -
-
[DELETE]
-
/session
-
- Logs out an authenticated user An authToken is required to call this - endpoint. -
-
[GET]
-
/game
-
- Lists all the games in the database This API does not take a request body. - The response JSON lists all the games, including the board. An authToken is required to call this endpoint. -
-
[POST]
-
/game
-
- Create a new Chess Game The request body must contain a name for the game. - The response JSON contains the ID of created game, or if failed, an error message describing the reason. An - authToken is required to call this endpoint. -
-
[PUT]
-
/game
-
- Join a Chess Game The request body must contain the game ID and a color. An - authToken is required to call this endpoint. -
-
[DELETE]
-
/db
-
- Clear ALL data from the database This includes users and all game data. No - authorization authToken is required. -
-

Execute

-
-

Request

-
- -
- -
- -
- -
- -
- -
- - -
-
-

Response

-

-
- - diff --git a/instruction/command-line-builds/example-code/chess/server/web/index.js b/instruction/command-line-builds/example-code/chess/server/web/index.js deleted file mode 100644 index 511988ba..00000000 --- a/instruction/command-line-builds/example-code/chess/server/web/index.js +++ /dev/null @@ -1,66 +0,0 @@ -function submit() { - document.getElementById('response').value = ''; - const method = document.getElementById('method').value; - const endpoint = document.getElementById('handleBox').value; - const requestBody = document.getElementById('requestBox').value; - const authToken = document.getElementById('authToken').value; - - if (endpoint && method) { - send(endpoint, requestBody, method, authToken); - } - - return false; -} - -function send(path, params, method, authToken) { - params = !!params ? params : undefined; - let errStr = ''; - fetch(path, { - method: method, - body: params, - headers: { - Authorization: authToken, - 'Content-Type': 'application/json', - }, - }) - .then((response) => { - if (!response.ok) errStr = response.status + ': ' + response.statusText + '\n'; - return response.json(); - }) - .then((data) => { - document.getElementById('authToken').value = data.authToken || authToken || 'none'; - document.getElementById('response').innerText = errStr + JSON.stringify(data, null, 2); - }) - .catch((error) => { - document.getElementById('response').innerText = error; - }); -} - -function displayRequest(method, endpoint, request) { - document.getElementById('method').value = method; - document.getElementById('handleBox').value = endpoint; - const body = request ? JSON.stringify(request, null, 2) : ''; - document.getElementById('requestBox').value = body; -} - -function clearAll() { - displayRequest('DELETE', '/db', null); -} -function register() { - displayRequest('POST', '/user', { username: 'username', password: 'password', email: 'email' }); -} -function login() { - displayRequest('POST', '/session', { username: 'username', password: 'password' }); -} -function logout() { - displayRequest('DELETE', '/session', null); -} -function gamesList() { - displayRequest('GET', '/game', null); -} -function createGame() { - displayRequest('POST', '/game', { gameName: 'gameName' }); -} -function joinGame() { - displayRequest('PUT', '/game', { playerColor: 'WHITE/BLACK', gameID: 0 }); -} diff --git a/instruction/command-line-builds/example-code/chess/shared/pom.xml b/instruction/command-line-builds/example-code/chess/shared/pom.xml deleted file mode 100644 index 8333e2f3..00000000 --- a/instruction/command-line-builds/example-code/chess/shared/pom.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - - 4.0.0 - - - edu.byu.cs240 - chess - 1.0 - - - edu.byu.cs240 - shared - 1.0 - - shared - - jar - - - - com.google.code.gson - gson - compile - - - - - - - org.apache.maven.plugins - maven-clean-plugin - - - org.apache.maven.plugins - maven-resources-plugin - - - org.apache.maven.plugins - maven-compiler-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - org.apache.maven.plugins - maven-jar-plugin - - - org.apache.maven.plugins - maven-install-plugin - - - org.apache.maven.plugins - maven-deploy-plugin - - - - - - - - org.apache.maven.plugins - maven-site-plugin - - - org.apache.maven.plugins - maven-project-info-reports-plugin - - - org.apache.maven.plugins - maven-checkstyle-plugin - - - - - diff --git a/instruction/command-line-builds/generateDependency.png b/instruction/command-line-builds/generateDependency.png deleted file mode 100644 index 2d3e361b..00000000 Binary files a/instruction/command-line-builds/generateDependency.png and /dev/null differ diff --git a/instruction/command-line-builds/junitDependency.png b/instruction/command-line-builds/junitDependency.png deleted file mode 100644 index 3dc02285..00000000 Binary files a/instruction/command-line-builds/junitDependency.png and /dev/null differ diff --git a/instruction/command-line-builds/mavenArtifactSearch.png b/instruction/command-line-builds/mavenArtifactSearch.png deleted file mode 100644 index 3199876d..00000000 Binary files a/instruction/command-line-builds/mavenArtifactSearch.png and /dev/null differ diff --git a/instruction/command-line-builds/mvnRepository.png b/instruction/command-line-builds/mvnRepository.png deleted file mode 100644 index 9732b4fa..00000000 Binary files a/instruction/command-line-builds/mvnRepository.png and /dev/null differ diff --git a/instruction/command-line-builds/newMavenProject.png b/instruction/command-line-builds/newMavenProject.png deleted file mode 100644 index 5dcc807d..00000000 Binary files a/instruction/command-line-builds/newMavenProject.png and /dev/null differ diff --git a/instruction/computer-security/asymmetric.png b/instruction/computer-security/asymmetric.png deleted file mode 100644 index 8ca3fb94..00000000 Binary files a/instruction/computer-security/asymmetric.png and /dev/null differ diff --git a/instruction/computer-security/computer-security.md b/instruction/computer-security/computer-security.md deleted file mode 100644 index e371d7d6..00000000 --- a/instruction/computer-security/computer-security.md +++ /dev/null @@ -1,490 +0,0 @@ -# Computer Security - -🖥️ [Slides](https://docs.google.com/presentation/d/1pUU4DDACUndgj_ij7bbKOUY8cxmGinZq/edit#slide=id.p1) - -🖥️ [Lecture Videos](#videos) - -📖 **Required Reading**: None - -Software systems conduct trillions of dollars in daily transactions, and manage access to billions of personal records. This makes these systems a valuable target for attack. Bad actors try to compromise systems in a variety of ways. They may try to gain unauthorized access to data and computers for the purposes of stealing, monitoring, damaging, or otherwise misusing these assets. In order to mitigate their efforts you must include security as a primary design criteria, understand historical and current attack vectors, vigilantly monitor for intrusion, and continually enhance your systems as new threats evolve. - -This topic focuses on the core concepts and technologies necessary to securely store and transmit data. The core concepts of computer security include the following. - -- **Authentication**: Verifying the identity of an actor (e.g. user or system) -- **Authorization**: Enforcing the rights that an actor has to access data or perform restricted operations -- **Data Integrity**: Verifying that data has not been modified from its original form -- **Non-Repudiation**: Verifying, or not rejecting, the origin or authorship of data - -Cryptography plays a key technological role in supporting these security concepts. Cryptography is used to authenticate users, represent their rights and identity, encrypt their data, and digitally sign messages. Without cryptography it would be very difficult to securely exchange money or information in digital form. - -## Cryptographic Hash Functions - -Let's take a look at our first cryptographic tool, hash functions. A hash function is a mathematical function that converts data of arbitrary size into a fixed-size value. The value returned by a hash function are often called a hash value, hash code, digest, or simply a hash. - -Desirable features of a hash function include: - -- **Fixed-Size**: The digest (or output) is always the same size (e.g., 160 bits), regardless of the input size -- **Deterministic**: Given the same input, it produces the same digest -- **One-Way**: Given the digest, you cannot recover the original text -- **Resistance to collisions**: It should be difficult to find two different input values that produce the same digest -- **Preimage resistance:** It should be difficult to find an input value that produces a given digest - -There are many algorithms for computing digests. Here is a list of some of the more common ones along with their limitations and benefits. - -| Hash function | Benefits | Limitations | -| ------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | -| **MD5** | Simple, fast, widely used, widely available | Collision attacks have been found, considered insecure for cryptographic applications | -| **SHA-1** | More secure than MD5, widely used, widely available | Collision attacks have been found, considered insecure for cryptographic applications | -| **SHA-256** | Secure against known attacks, widely used, widely available | Slower than MD5 and SHA-1, not as widely supported as MD5 and SHA-1 | -| **Bcrypt** | Password hashing function, secure against known attacks, widely used, widely available | Slower than SHA-256 | - -If you are using macOS or linux you can use the `shasum` command console utility to generate a hash using the **SHA-256** algorithm. - -```sh -➜ echo -n "Fox" | shasum -a 256 -f55bd2cdfae7972827638f3691a5bc189199d7cff7188d5ead489afdea0e5403 -``` - -The following demonstrates doing the same thing with Java code. - -```java -package demo; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.nio.charset.StandardCharsets; - - -public class CryptoHashFunctionDemo { - - public static void main(String[] args) throws NoSuchAlgorithmException { - - String[] allInputs = new String[]{ - "Fox", - "Fox", - "The red fox jumps over the blue dog", - "The red fox jumps oѵer the blue dog", - }; - - for (String input : allInputs) { - // Convert character string to array of bytes - byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8); - - // Calculate message digest - MessageDigest md = MessageDigest.getInstance("SHA-256"); - byte[] digestBytes = md.digest(inputBytes); - - System.out.println(input); - System.out.println(bytesToHex(digestBytes)); - System.out.println(); - } - } - - public static String bytesToHex(byte[] bytes) { - byte[] hexChars = new byte[bytes.length * 2]; - for (int j = 0; j < bytes.length; j++) { - int v = bytes[j] & 0xFF; - hexChars[j * 2] = HEX_ARRAY[v >>> 4]; - hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; - } - return new String(hexChars, StandardCharsets.UTF_8); - } -} -``` - -Using either method should generate the same output for the word `Fox`. You can experiment with either the code or console command to see what happens with different inputs. Notice that changing the case of the text or including whitespace will produce different results. - -### Creating Signatures - -One primary use for a hash function is to create a unique, short, fixed size signature that can represent data blocks of arbitrary length. With a signature you can use it as a compact representation of the data, and to determine equality to other data blocks. - -The key properties of a hash function that is used for generating signatures include speed, fixed size, determinism, and resistance to collisions. Therefore algorithms such as MD5 and SHA-1 work well for this purpose. As an example, Git uses SHA-1 to generate a unique signature for all the data in a given commit. - -### Securing Passwords - -If a hash function is one-way and preimage resistant, then it is a good candidate for representing passwords. Under this model you would hash the user's password when they register and then store it in the database. When you want to authenticate a user's password you simply hash the password at login, and compare it to the previously stored hashed value. - -In order to understand why hashing passwords is valuable, consider the case where you simply store plain text representations of passwords in a database column. - -| User | Password | -| ----- | -------------- | -| sally | toomanysecrets | -| juan | p@33w0r6 | -| pat | qwerty1 | - -> Plain text passwords - -If your database is ever compromised then the attacker now has all of the credentials for all of your users. That might allow them access to valuable monetary, proprietary, or confidential data. Even if your application has little value to compromise, it is common for passwords to be reused on different websites. For example, if Juan reused his super secret password `p@33w0r6` on his school account, bank application, and his shopping websites. - -By hashing the passwords the attacker cannot simply read the password from the database and use it to log in to an account. - -| User | HashedPassword | -| ----- | ---------------------------------------- | -| sally | fc80b22ff203a1a88470b19ab19228044d066d66 | -| juan | adb4c36db0466b9750a7a298ef39f98159eb219d | -| pat | ad70ab97ae1376e656002641cfb067c9c94906a2 | - -> Hashed passwords using SHA-1 - -However, even with a hashed version of the passwords a determined attacker can still succeed in revealing the credentials for your users by using what is known as a `rainbow table attack`. A `rainbow` table is a large database with an index of precomputed hash codes for common passwords and a specific hashing algorithm such as `SHA-256`. With such a table the hacker simply searches for the hashed password, and if there is a match then they know what the original password was and that `SHA-256` was used to hash it. - -In order to combat a rainbow table attack, it is common to combine the password with a random sequence of characters, called a `salt`, for each hashed password. By combining the salt with the password plain text the combination becomes unique and therefore no longer vulnerable to a rainbow table attack because the attacker would have to compute a database for every possible password, salt value, and algorithm. - -| User | SaltedHashedPassword | -| ----- | ---------------------------------------------- | -| sally | 37581:a67d83d2f75f240fe223ea899757a6980dee7d50 | -| juan | 92734:79241300a93bdda742159f1902db461b55be3982 | -| pat | 84723:fdfa32ac48e82803daa5b2a0849fb3c080b09cec | - -> Hashed passwords using SHA-1 and salt - -The following diagram demonstrates the flow necessary to use salted passwords. - -![Salting](salting.png) - -Note that the salt is not encrypted. It can be simply stored in your database along with the hashed password. The idea is to simply make it difficult for the attacker to precompute the hashed value. With the salt you are making each hash unique. To do a brute force attack against that representation an attacker would have to compute a rainbow table against each salted password. - -| Representation | Benefit | -| ----------------- | --------------------------------------------------------------------------------- | -| Plain text | The password is kept safe in a non-public database | -| Hashed | The password in not immediately usable if the database is compromised | -| Hashed and salted | Each individual password must be analyzed in order to be successfully compromised | - -### Bcrypt - -As an additional protection for our user's passwords we want to use a hash algorithm that is expensive to calculate. That way it is difficult to create a table of precomputed passwords. With modern hardware that utilizes graphical processing units (GPUs), it is possible to try millions of possible hashes per second with the `SHA-256` algorithm. For this reason, algorithms such as `Bcrypt` were created to make it computationally expensive to generate a hash, while still maintaining all of the other desirable characteristics of a password hashing algorithm. That means that while `SHA-256` can create millions of hashes per second, `Bcrypt` will only generate a few thousand when running on the same hardware. The cost of generation makes it very difficult for an attacker to create a large rainbow table, and extremely difficult to do so with salted data. - -You can experiment with `Bcrypt` using the following library. - -``` -org.mindrot:jbcrypt:0.4 -``` - -This implementation of Bcrypt makes it so you can hash and salt a password with one line of code, and then later compare the hash to a candidate password with another line of code. The following example first hashes the password `toomanysecrets` and then compares it to three possible candidates. - -```java -import org.mindrot.jbcrypt.BCrypt; - -public class PasswordExample { - - public static void main(String[] args) { - String secret = "toomanysecrets"; - String hash = BCrypt.hashpw(secret, BCrypt.gensalt()); - - String[] passwords = {"cow", "toomanysecrets", "password"}; - for (var pw : passwords) { - var match = BCrypt.checkpw(pw, hash) ? "==" : "!="; - - System.out.printf("%s %s %s%n", pw, match, secret); - } - } -} -``` - -Here are the results of running the program. - -```txt -cow != toomanysecrets -toomanysecrets == toomanysecrets -password != toomanysecrets -``` - -## Encryption and Decryption - -In Cryptography, `encryption` is the process of encoding data so that it is unreadable. Decryption is the process of decoding data back to its original form. - -Unlike hashing passwords, many applications need to both encrypt and decrypt information. For example, when you have to save confidential information such as a user's medical or financial records, you want to encrypt that data so that it is difficult to compromise, but you also need to be able to decrypt it so that it can be returned to the user on request. - -In the world of cryptography, the unencrypted text is called plain text. The encrypted text is called a cipher. Algorithms that both encrypt and decrypt data utilize a sequence of bytes, called a key, that enable conversion. Typically, the longer the key size, the more difficult it will be to defeat the encryption. - -| Term | Purpose | Example | -| ----------- | -------------------------------------- | ------------------- | -| Plain text | unencrypted data | toomanysecrets | -| Key | value used to encrypt and decrypt data | 9012434289054653828 | -| Key size | The length of the key | 1024 bits | -| Cipher text | encrypted data | 88338012387532 | - -### Simple Example - -Consider a simple encryption algorithm that adds a number from one to 16, to each character of text. This would be easy to encrypt and decrypt text and only require a key size of four bits. - -| Value | Value | -| ----------- | -------------- | -| Plain text | toomanysecrets | -| Key | 1 | -| Key size | 4 bits | -| Cipher text | uppoboztfdsfut | - -You could implement this algorithm for both encryption and decryption with the following code. - -```java -public class SimpleExample { - public static void main(String[] args) { - var key = 1; - var plainText = "toomanysecrets".toCharArray(); - - // encrypt - var cipherText = new char[plainText.length]; - for (var i = 0; i < plainText.length; i++) { - cipherText[i] = (char) (plainText[i] + key); - } - - // decrypt - for (var i = 0; i < cipherText.length; i++) { - plainText[i] = (char) (cipherText[i] - key); - } - - System.out.println(plainText); - System.out.println(cipherText); - } -} -``` - -However, our simple encryption algorithm would be easy to defeat because you could simply try all `16` possible values of the key to decrypt any cipher text. In order for an algorithm to be viable, it needs to have a large key and an algorithm that exploits complex mathematics. For example, a key size of 1024 bits could require as many as `2^1024` attempts, or: - -``` -1,797,693,134,862,315,907,729,305,190,789,024,733,617,976,978,942,306,572,734,300,811,577,326,758,055,009,631,327,084,773,224,075,360,211,201,138,798,713,933,576,587,897,688,144,166,224,928,474,306,394,741,243,777,678,934,248,652,763,022,196,012,460,941,194,530,829,520,850,057,688,381,506,823,424,628,814,739,131,105,408,272,371,633,505,106,845,862,982,399,472,459,384,797,163,048,353,563,296,242,241,372,160 -``` - -This number is significantly larger than the number of atoms in the observable universe, which is estimated to be around 10^80. - -## Symmetric Key Encryption - -The `SimpleExample` encryption code that was demonstrated above is an example of a symmetric key encryption algorithm. Symmetric algorithms use the same key to both encryption and decryption. Symmetric encryption algorithms are attractive because they are very quick to compute and difficult to attack assuming that you have an appropriately sized key. - -As we mentioned above, a good encryption algorithm will use complex mathematics to make it difficult to encrypt or decrypt without the proper key. One commonly used symmetric key algorithm is Advanced Encryption Standard (`AES`). This algorithm shifts blocks of characters around, across multiple rounds of manipulation, while applying a key size of 128, 192, or 256 bits. It also applies an `initialization vector` to create a unique cipher value for each `plain text`/`initialization vector` combination. The use of the initialization vector makes it so that the same plain text does not result in the same cipher representation. Without that, you would be able to determine the encrypted data by brute forcing an attack that guessed what the plain text was. - -![symmetric encryption](symmetric.png) - -The following code demonstrates the use of `AES` to encrypt and decrypt data. The code begins by generating an appropriately sized key and then creating an initialization vector. These are then used to first encrypt and then decrypt the message. - -```java -import javax.crypto.*; -import javax.crypto.spec.IvParameterSpec; -import java.security.SecureRandom; -import java.io.*; - -public class SymmetricKeyExample { - public static void main(String[] args) throws Exception { - SecretKey key = createAesKey(); - IvParameterSpec initVector = createAesInitVector(); - - var secretMessage = "toomanysecrets"; - - var plainTextIn = new ByteArrayInputStream(secretMessage.getBytes()); - var cipherBytes = runAes(Cipher.ENCRYPT_MODE, plainTextIn, key, initVector); - - var cipherTextIn = new ByteArrayInputStream(cipherBytes); - var plainTextBytes = runAes(Cipher.DECRYPT_MODE, cipherTextIn, key, initVector); - - System.out.printf("%s == %s%n", secretMessage, new String(plainTextBytes)); - } - - static SecretKey createAesKey() throws Exception { - KeyGenerator keyGen = KeyGenerator.getInstance("AES"); - keyGen.init(256); - return keyGen.generateKey(); - } - - static IvParameterSpec createAesInitVector() { - var ivBytes = new byte[16]; - new SecureRandom().nextBytes(ivBytes); - return new IvParameterSpec(ivBytes); - } - - static byte[] runAes(int cipherMode, InputStream in, SecretKey key, IvParameterSpec initVector) throws Exception { - Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - cipher.init(cipherMode, key, initVector); - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - byte[] inputBytes = new byte[64]; - int bytesRead; - while ((bytesRead = in.read(inputBytes)) != -1) { - out.write(cipher.update(inputBytes, 0, bytesRead)); - } - - out.write(cipher.doFinal()); - return out.toByteArray(); - } -} -``` - -### Asymmetric Key Encryption - -An alternative to symmetric key encryption is `asymmetric key encryption`. With this algorithm, two keys have a certain mathematical relationship to each other, and are generated at the same time as a `key pair`. The pair consists of a `public` key and a `private` key. Given one key you cannot determine the other key, but you can decrypt data that was encrypted by the other key. With a key pair you can publicly distribute the public key and then any party that has the public key can encrypt data that can only be decrypted by a party that has the private key. - -1. Generate a key pair -1. Keep one of the keys secret. This is the `private key`. -1. Give the other key to anyone who wants to send you data. This is the `public key`. There is no need to keep it secret. -1. When sending you data, the sender encrypts the data with the public key -1. When you receive the data, you decrypt the data with the private key - -![asymmetric encryption](asymmetric.png) - -In order for this exchange to work it is very important that you keep the private key secret. If the private key is ever publicly released then the pair becomes worthless. - -There are several implementations of asymmetric key encryption. Here are the two most popular ones. - -- **Rivest–Shamir–Adleman (RSA)**: This is a mature and well-respected algorithm that is widely used in a variety of applications, including secure communication, digital signatures, and certificate authorities. -- **Elliptic curve cryptography (ECC)**: This is a newer algorithm that is more efficient than RSA and offers comparable security. ECC is becoming increasingly popular in a variety of applications, including mobile devices and lightweight devices. - -Asymmetric key encryption is built directly into the JDK `crypto` and `security` packages. The following code demonstrates how to create a key pair and then use it to encrypt and decrypt data. - -```java -import javax.crypto.Cipher; -import java.io.*; -import java.security.*; - -public class AsymmetricKeyExample { - public static void main(String[] args) throws Exception { - KeyPair key = createRsaKeyPair(); - - final String secretMessage = "toomanysecrets"; - - var plainTextIn = new ByteArrayInputStream(secretMessage.getBytes()); - var cipherTextOut = new ByteArrayOutputStream(); - runRsa(Cipher.ENCRYPT_MODE, plainTextIn, cipherTextOut, key.getPublic()); - - var cipherTextIn = new ByteArrayInputStream(cipherTextOut.toByteArray()); - var plainTextOut = new ByteArrayOutputStream(); - runRsa(Cipher.DECRYPT_MODE, cipherTextIn, plainTextOut, key.getPrivate()); - - System.out.printf("%s == %s%n", secretMessage, plainTextOut); - } - - private static KeyPair createRsaKeyPair() throws Exception { - var keyPairGen = KeyPairGenerator.getInstance("RSA"); - keyPairGen.initialize(2048); - return keyPairGen.generateKeyPair(); - } - - private static void runRsa(int cipherMode, InputStream inputStream, OutputStream outputStream, Key key) throws Exception { - Cipher cipher = Cipher.getInstance("RSA"); - cipher.init(cipherMode, key); - - byte[] inputBytes = new byte[64]; - int bytesRead; - while ((bytesRead = inputStream.read(inputBytes)) != -1) { - outputStream.write(cipher.update(inputBytes, 0, bytesRead)); - } - - outputStream.write(cipher.doFinal()); - } -} -``` - -You can also generate an asymmetric key pair using the console command line tool `ssh-keygen`. The following command uses the RSA algorithm to generate a key pair with a length of 4096 bits. - -```sh -ssh-keygen -t rsa -b 4096 -``` - -### Disadvantages of Asymmetric Key Encryption - -While asymmetric key cryptography is one of the most important inventions in the history of computing, asymmetric key encryption has several disadvantages when compared with symmetric key encryption. - -1. **Size restriction** - You can only encrypt a small amount of data. With RSA, you can only encrypt data less than the key size (e.g., 2048 bits, 4096 bits, etc.) -1. **Performance** - Asymmetric encryption is much slower than symmetric encryption. - -## Secure Key Exchange - -While symmetric encryption is good at quickly providing secure encryption, it has one significant drawback. The key must be known to both the encryption and decryption software. That means if you are trying to transmit encrypted data to remote parties, you must also securely transmit the key. Either the key must be supplied in advance of the remote communication, or delivered with some other secure channel such as in-person communication. Using any means that also uses symmetric encryption simply creates another layer to the problem. - -One common way to solve this problem is to use `asymmetric key encryption` to exchange an encrypted `symmetric key`. Once both parties have the symmetric key they can use it to transmit large amounts of data. With this pattern you would do the following: - -1. Client generates an asymmetric key pair. -1. Client publicly posts the public key. -1. Server generates a symmetric key and encrypts it using the public key provided by Client. -1. Server sends the encrypted key to Client. -1. Client decrypts the encrypted key using her private key. -1. Client sends a message back to Server that is encrypted using Server's symmetric key. -1. Communication then continues using Server's symmetric key. - -![Key exchange](keyExchange.png) - -## Digital Signatures - -Asymmetric encryption also helps us solve the problems of `Non-Repudiation` and `Data Integrity`. Non-Repudiation is the task of guaranteeing that the party sending a message is actually who they say they are. Data Integrity guarantees that the data has not been tampered with since it left the sender. The basic idea is to create a `digital signature` that represents both the author of the data and the data sent in the message. This is done using the following steps: - -1. Sally generates an asymmetric key pair. -1. Sally publicly posts the public key. -1. Sally generates a message. -1. Sally hashes the message using SHA-1. This is called the `signer digest`. -1. Sally encrypts the signer digest using her private key. This creates the `signature`. -1. Sally posts the message and the signature publicly. -1. Juan obtains the message and hashes it using the same algorithm Sally used. This is called the `receiver digest`. -1. Juan uses Sally's public key to decrypt the signature. This returns the `signer digest` in a way that provides non-repudiation by guaranteeing it was created by Sally. -1. Juan compares the `signer digest` to the `receiver digest`. If they match then that provides data integrity because the message has not changed since Sally signed it. - -![Digital Signatures](digitalCert.png) - -Digital signatures are used to sign emails, contracts, crypto currency transactions, and web certificates. - -## Web Certificates and Secure Communication (HTTPS) - -Let's move to an example that demonstrates everything we have learned about encryption including using digital signatures, symmetric keys, asymmetric keys, and key exchanges. - -An important feature of the world wide web is knowing that the website you are talking to is actually the website you believe it to be. This is solved by gaining a web certificate, from an authority, called a certificate authority (`CA`), that is trusted by both the website owner and the website browser. A web certificate contains information about the website identity, a public asymmetric key, and a digital signature signed by the CA. The web certificate is used to demonstrate non-repudiation of the website owner using the following steps. - -1. The website is granted a web certificate and key pair from the CA. -1. The web certificate contains a public asymmetric key. The website keeps the private key secure. -1. A web browser makes a connection to the website. -1. The website provides the certificate as part of the connection process. -1. The browser verifies that the certificate was signed by the CA. - -Once a web browser has verified that the certificate is valid, it then attempts to create a secure connection to the website. The browser uses the asymmetric public key that was provided in the certificate to begin a secure key exchange. - -1. The browser creates a symmetric key. -1. The browser encrypts the key using the public key provided in the certificate. -1. The browser sends the encrypted key to the website. -1. The website decrypts the key using the certificate's private key. -1. The website responds with data encrypted using the browser's symmetric key. - -If the website cannot decrypt the symmetric key then that means the website is not actually the owner of the validated certificate and it terminates communication. That is why the website must be very careful to never publicly release their web certificate private key. - -![web certs](webCert.png) - -This demonstrates how modern cryptography forms the foundation of web security by providing user authentication, authorization, non-repudiation, data integrity, and secure communication. - -## Things to Understand - -- High-level goals of computer security - - Data confidentiality - - Authentication - - Data integrity - - Non-Repudiation -- Fundamental security concepts and technologies - - Cryptographic hash functions - - Symmetric encryption - - Asymmetric encryption with public and private keys - - Secure key exchange - - Digital signatures - - Public key certificates -- Secure password storage and verification -- Secure network communication using HTTPS - -## Videos - -- 🎥 [Computer Security Overview (7:49)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=f60bd2e6-9aec-44ba-8e48-b1a8014a2efe) - [[transcript]](https://github.com/user-attachments/files/17736619/CS_240_Computer_Security_Overview_Transcript.pdf) -- 🎥 [Cryptographic Hash Functions (10:05)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=e54b188b-89a4-4f51-be13-b1a8014d0a7b) - [[transcript]](https://github.com/user-attachments/files/17736652/CS_240_Cryptographic_Hash_Functions_Transcript.pdf) -- 🎥 [Cryptographic Hashing Applications (5:29)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=44f59163-ab0a-410b-a8bb-b1a8015012bf) - [[transcript]](https://github.com/user-attachments/files/17736656/CS_240_Cryptographic_Hashing_Applications_Transcript.pdf) -- 🎥 [Secure Password Storage (15:06)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=f977577d-6fec-45a9-8e80-b1a80151efc1) - [[transcript]](https://github.com/user-attachments/files/17736661/CS_240_Secure_Password_Storage_Transcript.pdf) -- 🎥 [Data Encryption (4:27)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=bd28a2d9-adec-4c2b-b78f-b1a8015667b9) - [[transcript]](https://github.com/user-attachments/files/17736672/CS_240_Data_Encryption_Transcript.pdf) -- 🎥 [Symmetric Key Encryption (11:37)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=0537f4f0-5ef2-4534-9564-b1a80157e780) - [[transcript]](https://github.com/user-attachments/files/17736680/CS_240_Symmetric_Key_Encryption_Transcript.pdf) -- 🎥 [Asymmetric Key Encryption (15:01)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=aad832e9-0621-4a6d-b389-b1a8015b6ffc) - [[transcript]](https://github.com/user-attachments/files/17736687/CS_240_Asymmetric_Key_Encryption_Transcript.pdf) -- 🎥 [Encryption Applications (6:28)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=cb8ef70e-52fd-4390-9ae9-b1a8015fcac1) - [[transcript]](https://github.com/user-attachments/files/17736710/CS_240_Encryption_Applications_Transcript.pdf) -- 🎥 [Secure Key Exchange (4:51)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=a466805a-7a15-4859-b84e-b1af0148e79d) - [[transcript]](https://github.com/user-attachments/files/17736726/CS_240_Secure_Key_Exchange_Transcript.pdf) -- 🎥 [Secure Communication with HTTPS (14:17)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=f02e79ed-fcca-4549-a8b7-b1af014aa782) - [[transcript]](https://github.com/user-attachments/files/17736732/CS_240_Secure_Communication_using_HTTPS_Transcript.pdf) -- 🎥 [Digital Signatures (8:10)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=93205b28-04ef-4e11-b939-b1af014ef686) - [[transcript]](https://github.com/user-attachments/files/17736735/CS_240_Digital_Signatures_Transcript.pdf) - -## Demonstration code - -📁 [Cryptographic Hash Function Example](example-code/src/demo/CryptoHashFunctionDemo.java) - -📁 [Password Hashing and Verification Example](example-code/src/demo/PBKDF2WithHmacSHA1Hashing.java) - -📁 [Symmetric Key Encryption Example](example-code/src/demo/SymmetricKeyEncryptionDemo.java) - -📁 [Public Key Encryption Example](example-code/src/demo/PublicKeyEncryptionDemo.java) - -📁 [Security Utilities](example-code/src/demo/Utils.java) diff --git a/instruction/computer-security/diagrams.uml b/instruction/computer-security/diagrams.uml deleted file mode 100644 index a66d8633..00000000 --- a/instruction/computer-security/diagrams.uml +++ /dev/null @@ -1,25 +0,0 @@ -sequenceDiagram - participant Juan - Sally-->>Sally: Generate key pair - Juan-->>Juan: Generate symmetric key - Juan->>Sally: Get public key - Juan-->>Juan: Encrypt symmetric key - Juan->>Sally: Send encrypted key - Sally-->>Sally: Decrypt symmetric key - loop Send data - Sally->>Juan: send ecrypted message - Juan->>Sally: send ecrypted message - - end - - -sequenceDiagram - participant Juan - Sally-->>Sally: Generate asymmetric key pair - Juan->>Sally: Get public key - Juan-->>Juan: Encrypt data with public key - loop Send data - Juan->>Sally: Send encrypted data - Sally-->>Sally: Decrypt data with private key - end - \ No newline at end of file diff --git a/instruction/computer-security/digitalCert.png b/instruction/computer-security/digitalCert.png deleted file mode 100644 index 9adf023a..00000000 Binary files a/instruction/computer-security/digitalCert.png and /dev/null differ diff --git a/instruction/computer-security/example-code/.idea/.gitignore b/instruction/computer-security/example-code/.idea/.gitignore deleted file mode 100644 index 26d33521..00000000 --- a/instruction/computer-security/example-code/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/instruction/computer-security/example-code/.idea/libraries/springframework_security_spring_core.xml b/instruction/computer-security/example-code/.idea/libraries/springframework_security_spring_core.xml deleted file mode 100644 index 85c17545..00000000 --- a/instruction/computer-security/example-code/.idea/libraries/springframework_security_spring_core.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/instruction/computer-security/example-code/.idea/misc.xml b/instruction/computer-security/example-code/.idea/misc.xml deleted file mode 100644 index 24965408..00000000 --- a/instruction/computer-security/example-code/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/instruction/computer-security/example-code/.idea/modules.xml b/instruction/computer-security/example-code/.idea/modules.xml deleted file mode 100644 index a37cdc9a..00000000 --- a/instruction/computer-security/example-code/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/instruction/computer-security/example-code/.idea/vcs.xml b/instruction/computer-security/example-code/.idea/vcs.xml deleted file mode 100644 index c2365ab1..00000000 --- a/instruction/computer-security/example-code/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/instruction/computer-security/example-code/Security.iml b/instruction/computer-security/example-code/Security.iml deleted file mode 100644 index d8dc1707..00000000 --- a/instruction/computer-security/example-code/Security.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/instruction/computer-security/example-code/src/demo/BcryptPasswordHashingDemo.java b/instruction/computer-security/example-code/src/demo/BcryptPasswordHashingDemo.java deleted file mode 100644 index aeec1a9b..00000000 --- a/instruction/computer-security/example-code/src/demo/BcryptPasswordHashingDemo.java +++ /dev/null @@ -1,20 +0,0 @@ -package demo; - -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; - -public class BcryptPasswordHashingDemo { - - public static void main(String[] args) { - BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); - String secret = "toomanysecrets"; - String hash = encoder.encode(secret); - System.out.println("hash = " + hash); - - String[] passwords = {"cow", "toomanysecrets", "password"}; - for (var pw : passwords) { - var match = encoder.matches(pw, hash) ? "==" : "!="; - - System.out.printf("%s %s %s%n", pw, match, secret); - } - } -} diff --git a/instruction/computer-security/example-code/src/demo/CryptoHashFunctionDemo.java b/instruction/computer-security/example-code/src/demo/CryptoHashFunctionDemo.java deleted file mode 100644 index d8d690d7..00000000 --- a/instruction/computer-security/example-code/src/demo/CryptoHashFunctionDemo.java +++ /dev/null @@ -1,40 +0,0 @@ -package demo; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.nio.charset.StandardCharsets; - - -public class CryptoHashFunctionDemo { - - public static void main(String[] args) throws NoSuchAlgorithmException { - - String[] allInputs = new String[]{ - "Fox", - "Fox", - "The red fox jumps over the blue dog", - "The red fox jumps ouer the blue dog", - }; - - for (String input : allInputs) { - // Convert character string to array of bytes - byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8); - - // Calculate message digest - byte[] digestBytes = hashData(inputBytes); - - System.out.println(input); - System.out.println(Utils.bytesToHex(digestBytes)); - System.out.println(); - } - } - - public static byte[] hashData(byte[] data) throws NoSuchAlgorithmException { - - MessageDigest md = MessageDigest.getInstance("SHA-256"); - - byte[] digest = md.digest(data); - - return digest; - } -} diff --git a/instruction/computer-security/example-code/src/demo/PublicKeyEncryptionDemo.java b/instruction/computer-security/example-code/src/demo/PublicKeyEncryptionDemo.java deleted file mode 100644 index 4362e939..00000000 --- a/instruction/computer-security/example-code/src/demo/PublicKeyEncryptionDemo.java +++ /dev/null @@ -1,101 +0,0 @@ -package demo; - -import javax.crypto.Cipher; -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.security.*; - - -public class PublicKeyEncryptionDemo { - - public static void main(String[] args) throws Exception { - - // Create and save RSA key pair - KeyPair keyPair = createRsaKeyPair(); - - PublicKey publicKey = keyPair.getPublic(); - PrivateKey privateKey = keyPair.getPrivate(); - - String pubFormat = publicKey.getFormat(); - String prvFormat = privateKey.getFormat(); - Files.write(Paths.get("public-key"), publicKey.getEncoded()); - Files.write(Paths.get("private-key"), privateKey.getEncoded()); - - Key encryptionKey = publicKey; - Key decryptionKey = privateKey; -// Key encryptionKey = privateKey; -// Key decryptionKey = publicKey; - - final String PLAIN_TEXT = "Four score and seven years ago our fathers brought forth, upon this continent," + - " a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal."; - - byte[] plainTextBytes = PLAIN_TEXT.getBytes(StandardCharsets.UTF_8); - - ByteArrayInputStream inputStream = null; - ByteArrayOutputStream outputStream = null; - - // Encrypt data - inputStream = new ByteArrayInputStream(plainTextBytes); - outputStream = new ByteArrayOutputStream(); - rsaEncrypt(inputStream, outputStream, encryptionKey); - - byte[] cipherTextBytes = outputStream.toByteArray(); - System.out.println(Utils.bytesToHex(cipherTextBytes)); - System.out.println(); - - // Decrypt data - inputStream = new ByteArrayInputStream(cipherTextBytes); - outputStream = new ByteArrayOutputStream(); - rsaDecrypt(inputStream, outputStream, decryptionKey); - - byte[] decryptedPlainTextBytes = outputStream.toByteArray(); - String decryptedPlainText = new String(decryptedPlainTextBytes, StandardCharsets.UTF_8); - System.out.println(decryptedPlainText); - System.out.println(); - } - - private static KeyPair createRsaKeyPair() throws Exception - { - var keyPairGen = KeyPairGenerator.getInstance("RSA"); - keyPairGen.initialize(2048); - KeyPair keyPair = keyPairGen.generateKeyPair(); - return keyPair; - } - - private static void rsaEncrypt(InputStream inputStream, OutputStream outputStream, Key key) throws Exception { - - runRsa(Cipher.ENCRYPT_MODE, inputStream, outputStream, key); - } - - private static void rsaDecrypt(InputStream inputStream, OutputStream outputStream, Key key) throws Exception { - - runRsa(Cipher.DECRYPT_MODE, inputStream, outputStream, key); - } - - private static void runRsa(int cipherMode, InputStream inputStream, OutputStream outputStream, - Key key) throws Exception { - - Cipher cipher = Cipher.getInstance("RSA"); - cipher.init(cipherMode, key); - - byte[] inputBytes = new byte[64]; - byte[] outputBytes = null; - - int bytesRead; - while ((bytesRead = inputStream.read(inputBytes)) != -1) { - outputBytes = cipher.update(inputBytes, 0, bytesRead); - if (outputBytes != null) { - outputStream.write(outputBytes); - } - } - - outputBytes = cipher.doFinal(); - if (outputBytes != null) { - outputStream.write(outputBytes); - } - - outputStream.flush(); - } -} diff --git a/instruction/computer-security/example-code/src/demo/SymmetricKeyEncryptionDemo.java b/instruction/computer-security/example-code/src/demo/SymmetricKeyEncryptionDemo.java deleted file mode 100644 index 06e4813d..00000000 --- a/instruction/computer-security/example-code/src/demo/SymmetricKeyEncryptionDemo.java +++ /dev/null @@ -1,90 +0,0 @@ -package demo; - -import javax.crypto.Cipher; -import javax.crypto.KeyGenerator; -import javax.crypto.SecretKey; -import javax.crypto.spec.IvParameterSpec; -import java.security.SecureRandom; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; - - -public class SymmetricKeyEncryptionDemo { - - public static void main(String[] args) throws Exception { - - // Create AES key and initialization vector - SecretKey aesKey = createAesKey(); - IvParameterSpec aesInitVector = createAesInitVector(); - - // Encrypt file - try (FileInputStream inputStream = new FileInputStream(args[0]); - FileOutputStream outputStream = new FileOutputStream("encrypted-file")) { - - aesEncrypt(inputStream, outputStream, aesKey, aesInitVector); - } - - // Decrypt file - try (FileInputStream inputStream = new FileInputStream("encrypted-file"); - FileOutputStream outputStream = new FileOutputStream("decrypted-file")) { - - aesDecrypt(inputStream, outputStream, aesKey, aesInitVector); - } - } - - private static SecretKey createAesKey() throws Exception - { - // Generate a pseudo-random AES encryption key (here we use a 256-bit key) - KeyGenerator keyGen = KeyGenerator.getInstance("AES"); - keyGen.init(256); - SecretKey key = keyGen.generateKey(); - return key; - } - - private static IvParameterSpec createAesInitVector() throws Exception - { - // Generate a pseudo-random AES "initialization vector" (128 bits) - var ivBytes = new byte[16]; - new SecureRandom().nextBytes(ivBytes); - return new IvParameterSpec(ivBytes); - } - - private static void aesEncrypt(InputStream inputStream, OutputStream outputStream, - SecretKey key, IvParameterSpec initVector) throws Exception { - - runAes(Cipher.ENCRYPT_MODE, inputStream, outputStream, key, initVector); - } - - private static void aesDecrypt(InputStream inputStream, OutputStream outputStream, - SecretKey key, IvParameterSpec initVector) throws Exception { - - runAes(Cipher.DECRYPT_MODE, inputStream, outputStream, key, initVector); - } - - private static void runAes(int cipherMode, InputStream inputStream, OutputStream outputStream, - SecretKey key, IvParameterSpec initVector) throws Exception { - - Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - cipher.init(cipherMode, key, initVector); - - byte[] inputBytes = new byte[64]; - byte[] outputBytes = null; - - int bytesRead; - while ((bytesRead = inputStream.read(inputBytes)) != -1) { - outputBytes = cipher.update(inputBytes, 0, bytesRead); - if (outputBytes != null) { - outputStream.write(outputBytes); - } - } - - outputBytes = cipher.doFinal(); - if (outputBytes != null) { - outputStream.write(outputBytes); - } - - outputStream.flush(); - } -} diff --git a/instruction/computer-security/example-code/src/demo/Utils.java b/instruction/computer-security/example-code/src/demo/Utils.java deleted file mode 100644 index 6339579c..00000000 --- a/instruction/computer-security/example-code/src/demo/Utils.java +++ /dev/null @@ -1,20 +0,0 @@ -package demo; - -public class Utils { - - private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); - - public static String bytesToHex(byte[] bytes) { - - char[] hexChars = new char[bytes.length * 2]; - - for (int j = 0; j < bytes.length; j++) { - int v = bytes[j] & 0xFF; - hexChars[j * 2] = HEX_ARRAY[v >>> 4]; - hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; - } - - return new String(hexChars); - } - -} diff --git a/instruction/computer-security/keyExchange.png b/instruction/computer-security/keyExchange.png deleted file mode 100644 index a1410f1b..00000000 Binary files a/instruction/computer-security/keyExchange.png and /dev/null differ diff --git a/instruction/computer-security/salting.png b/instruction/computer-security/salting.png deleted file mode 100644 index e77d95f9..00000000 Binary files a/instruction/computer-security/salting.png and /dev/null differ diff --git a/instruction/computer-security/symmetric.png b/instruction/computer-security/symmetric.png deleted file mode 100644 index 8de20de4..00000000 Binary files a/instruction/computer-security/symmetric.png and /dev/null differ diff --git a/instruction/computer-security/webCert.png b/instruction/computer-security/webCert.png deleted file mode 100644 index acc1da35..00000000 Binary files a/instruction/computer-security/webCert.png and /dev/null differ diff --git a/instruction/concurrency/concurrency.md b/instruction/concurrency/concurrency.md deleted file mode 100644 index cfadff09..00000000 --- a/instruction/concurrency/concurrency.md +++ /dev/null @@ -1,548 +0,0 @@ -# Concurrency and Multi-threaded Programming - -🖥️ [Slides](https://docs.google.com/presentation/d/1ibtqBjYEzx45Nh9eLP5xq6jWKfVjVMpv/edit#slide=id.p1) - -📖 **Optional Reading**: OPTIONAL: Core Java for the Impatient, Chapter 10: Concurrent Programming - -🖥️ [Lecture Videos](#videos) - -In order to understand the value of concurrent programming it is helpful to examine a process that executes discrete tasks. Imagine a pizza shop that takes orders and makes pizzas. A shop that only has one worker can only take one order at a time and make one pizza at a time. - -![Single thread](singleThread.gif) - -> _1_ - One worker, one customer - -This is fine if you only have one customer at a time, but you run into trouble if multiple customers want pizzas all at the same time. Like during a lunch hour rush. With only one employee, the customers will need to wait for each previous customer to be served. This leads to unhappy customers and eventually to a decrease in profit. - -![Single thread queued](singleThreadQueue.gif) - -> _2_ - One worker, multiple customers - -We can solve this problem by hiring more workers so we can serve multiple customers at the same time, or **concurrently**. With two workers we can make pizzas twice as fast. If we add a third worker then we can make pizzas three times as fast. - -![Single thread queued](multiThreaded.gif) - -> _3_ - Multiple workers, multiple customers - -The pattern of concurrently executing tasks is a foundational principle in computer science that enables increased throughput and performance. - -## Parallel vs Concurrent vs Sequential - -When you have multiple tasks and a single CPU, the operating system will swap which task is executing so that each task gets a chance to run. This allows the tasks to run concurrently. If you have multiple CPUs then the operating system can actually run the tasks at the **same time**, or in parallel. If each task has to run to completion before another task can start then you are running sequentially. When running sequentially you don't need to worry about data corruption, starvation, or deadlock because nothing can interrupt a partial execution of a task. - -The following diagram shows two tasks, one yellow and one blue, that need to execute. Depending how you write your code and what device your code runs on, it may run under any of the following models. - -![Models](models.png) - -## Concurrency at the System Level - -When your computer runs, it has hundreds of tasks that it needs to execute. This includes each program you start, sending and receiving network communication, receiving input from your keyboard, rendering to your display, and storing information. A computer usually has multiple processing units (CPUs). Each CPU can process one task at a time. When a CPU periodically switches tasks they are running concurrently and it gives the appearance that everything is running at the same time. If you have multiple CPUs, then the tasks are actually running in parallel. However no computer has enough CPUs for every task to run in parallel, and so the operating system spends much of its time scheduling and swapping tasks so that they run concurrently and in parallel. - -## Concurrency Complexities - -Implementing concurrency doesn't come for free. If an operating system only executed a single task at a time, it would be more simple than an operating system that can execute on multiple processors. In our pizza shop example, it is more complex to hire and manage multiple workers than to have a single worker. Additionally, if the workers cannot execute as a team, then you may lose all of the benefits that concurrency provides and end up with a shop that is less efficient than a shop with a single worker. These complexities introduce operational overhead, resource synchronization, starvation, and deadlock. Let's look at each one of these complexities individually. - -### Overhead - -With our pizza example, we can keep hiring workers in an attempt to increase **throughput**, but at some point the shop will be too small to allow the workers to efficiently move around. When that happens, adding more workers just increases the time each worker spends walking around each other. The cost of hiring workers and moving them around is all **overhead**. This will decrease the productivity of each worker and cause pizzas to be created at a slower rate. If we continue adding workers, then eventually none of them will be able to move and no pizzas will be created. - -In computer systems, overhead is determined by how expensive it is to create and manage tasks. If the CPU spends all of its time creating, deleting, and switching between tasks it will get little or no actual work done. - -### Resource synchronization - -You can also run into trouble when the workers need to **synchronize** their work on resources that cannot be shared concurrently. In our pizza shop there is only one cash register. Imagine what would happen if two workers tried to take an order at the same time using the single cash register. This might result in one customer paying for another customer's pizza, or both customers getting their pizzas for free. - -In a computer system, memory is a resource that is shared by all tasks. If multiple tasks try to write to memory at the same time they will overwrite each other or create duplicate entries. - -### Starvation - -Next we consider when one worker is monopolizing a resource. For example, If a worker starts taking an order on the cash register, but then decides to go on break before completing the order. Now, no other worker can take any orders. The result is no more pizzas and everyone is unhappy. When workers cannot operate because a necessary resource is not available it is called resource **starvation**. - -Most computers only have one network card. If one task monopolizes the use of the network then no other task can send or receive data. - -### Deadlock - -In the pizza shop you need to have the paddle to pull a pizza out of the oven and use the box maker to create a pizza box to put it in. If one worker is holding the box maker while a different worker is holding the oven paddle, neither one can actually complete the pizza making process. When two workers each hold a resource that the other worker needs to get a job done, you end up with **deadlock** in your system. One of the workers must temporarily release the resource so that the work can move forward. - -If we look back to our computer example, we have two resources, memory and the network. When two processes want to read from memory and write to the network, the operating system must make sure that they are sharing nicely. If one process grabs the network, and the other process grabs the access to the memory, neither one will be able to complete their tasks. The operating system must step in and require one of them to release a resource. - -## Concurrent Programming in Java - -Now that we have an idea of what concurrency is and what some of the complexities are, let's turn our attention to how we can take advantage of concurrency in our Java programs. First let's look at how you can create and execute multiple tasks. - -The primary mechanisms that enable concurrent programming in Java are `Processes` and `Threads`. A process is created when you run the Java Virtual Machine and point it at a class that has a `main` function. Once the main process has started it can span other processes using the [ProcessBuilder](https://docs.oracle.com/javase/8/docs/api/java/lang/ProcessBuilder.html) object. Each process runs as a separate application that can coordinate with other processes using the main function's arguments, standard input, standard output, or inter-process communication. - -Each process has a main thread of execution, and can create additional threads to process concurrent tasks. A Thread is a form of light weight process that runs under the context of a parent process. Threads in the same process can share memory, as variables or parameters, in order to communicate with each other. - -You create a Java thread by extending the [Thread](https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html) abstract class and providing a `run` method. You then allocate a new object from your class and call the `start` method. This will create a branch in the execution of your code. One branch will start executing your `run` method and the other branch with start executing the code listed after the `start` call. - -Each process and thread is assigned a unique identifier by the operating system. The ID is used to control which thread is currently executing and what resources it owns. - -### Thread Example - -The following program demonstrates creating two threads that print out the thread's ID 10 times. The `CountingThread` class extends the `Thread` abstract class by implementing a for loop in the `run` method. - -Form the main method we allocate two new instances of `CountingThread` and call the `start` method to begin their execution. - -```java -public class ThreadExample { - public static void main(String[] args) { - - new CountingThread().start(); - new CountingThread().start(); - - System.out.println("\nExit Main Thread"); - } - - static class CountingThread extends Thread { - public void run() { - var id = this.threadId(); - for (int i = 0; i != 10; i++) { - System.out.printf("%s:%d ", id, i); - } - System.out.printf("%nExit thread %s%n", id); - } - } -} -``` - -Note that as this program runs, we actually have three threads. Our main process thread, and two counting threads. If your computer has three processors, then each of the threads run concurrently. - -What this program outputs will be different every time you run it because it relies on the operating system's scheduler to determine when threads run. However, one possible output is demonstrated below. Notice that the output for the two threads are intermingled with each other, and that the main process thread exits before the other two threads. This demonstrates the concurrent nature of the execution. - -```txt -Exit Main Thread -22:0 22:1 22:2 22:3 22:4 23:0 23:1 23:2 23:3 22:5 22:6 22:7 22:8 22:9 -Exit thread 22 -23:4 23:5 23:6 23:7 23:8 23:9 -Exit thread 23 -``` - -### Runnable - -As an alternative to extending `Thread`, you can implement the `Runnable` functional interface in order to execute a thread. This allows you to compactly represent your thread implementation with a lambda function. - -```java -public class RunnableExample { - public static void main(String[] args) { - - new Thread(() -> { - var id = Thread.currentThread().threadId(); - for (int i = 0; i != 10; i++) { - System.out.printf("%s:%d ", id, i); - } - }).start(); - - System.out.println("\nLeaving Main Thread"); - } -} -``` - -The above is functionally equivalent to running one of the counting threads from the previous example. - -### Join - -Sometimes you want to wait for one or more threads to complete before you continue executing your main process thread. You can do this by calling the `join` method on the Thread object. - -```java -public class JoinExample { - public static void main(String[] args) throws Exception { - var t = new Thread(() -> System.out.println("Thread done")); - - t.start(); - t.join(); - - System.out.println("Exiting Main Thread"); - } -} -``` - -In the above example, "Thread done" will always output before "Exiting Main Thread" because the `join` method will block the main thread until the thread exits. - -### Callable and Executors - -When you want to return a result from a thread you can do this by creating an [ExecutorService](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html). You can then start a thread by calling the ExecutorService's `submit` method with an implementation of the `Callable` functional interface. Callable is similar to Runnable, except that it returns a result. When you call `submit`, it returns a `Future` object that will eventually contain the result of the Callable once the thread exits. - -You can wait for the Callable to complete, and thus get the return value, by calling the `get` method on the future object. This is similar to the `join` function described above, but `get` will return the thread's result. - -The use of an ExecutorService, Futures, and blocking on the `get` method is demonstrated by the code below. Calling the `submit` method causes the thread to branch but the main thread will block on the call to the Future's `get` method until the thread completes. - -```java -public class CallableExample { - public static void main(String[] args) throws Exception { - try (ExecutorService executorService = Executors.newSingleThreadExecutor()) { - Future future = executorService.submit(() -> { - return "Callable result"; - }); - System.out.println(future.get()); - } - } -} -``` - -### Thread Pools - -In addition to returning `Future` objects from the execution of a `Callable`, the ExecutorService can efficiently manage multiple threads as a group, or pool. If you are not careful with how you create and execute threads, the overhead of the thread management can quickly decrease the value of concurrent execution. - -In our example above we created a pool using the ExecutorService's factory `newSingleThreadExecutor` method. This creates a single thread and gives each Callable an equal chance to execute. You can also create a thread pool that allocates a fixed number of threads using the `newFixedThreadPool` method. This executor will block newly submitted tasks if there are no available threads in the pool. The `newCachedThreadPool` will grow the pool of threads when a new task is submitted if all of the current threads are in use. - -![Executor](executor.png) - -With all of the executors defined above, the threads in the pool are reused for each of the submitted tasks. This helps to decrease the overhead involved with creating and deleting threads. The following is a list of executors that are provided in the JDK concurrency package. - -| Pool Type | Description | -| ----------------------- | ----------------------------------------------------------------------------------------------------------------- | -| newSingleThreadExecutor | Uses a single thread and switches the callable task. Good for removing thread context switching overhead. | -| newFixedThreadPool | Reuses threads. Good for saving on thread creation overhead. | -| newCachedThreadPool | Reuses threads. Good for saving on thread creation overhead where the maximum number of needed thread is unknown. | -| newScheduledThreadPool | Runs threads periodically. Good for scheduled tasks without creating a new thread every time. | - -## Synchronizing Threads - -Supporting concurrency in your application will significantly increase the complexity of your code. Because of that complexity, multithreaded programs are a major source of bugs that can corrupt the integrity of your data or cause your application to fail entirely. - -### Race Conditions - -One common threading bug results from multiple threads racing to use a shared resource at the same time. Consider the following code where you have one thread taking pizza orders and multiple threads racing to make the pizzas. They coordinate their work by sharing a list of pizza orders. One thread puts the order on the list, and the other threads check to see if there is a pizza on the list and then attempt to remove it and make the pizza. - -```java -public class PizzaRaceExample { - final static ArrayList orders = new ArrayList<>(); - - public static void main(String[] args) throws Exception { - new Thread(() -> takeOrders()).start(); - - for (var i = 0; i < 10; i++) { - new Thread(() -> makePizzas()).start(); - } - } - - static void takeOrders() { - for (var i = 1; i < 1000; i++) { - var order = "Pizza-" + i; - System.out.printf("Ordering %s%n", order); - orders.add(order); - } - } - - static void makePizzas() { - while (true) { - if (!orders.isEmpty()) { - var order = orders.remove(0); - System.out.printf("%s served%n", order); - } - } - } -} - -``` - -On the surface this code looks simple enough, but if you run this code, you will likely get the following result: - -``` -Ordering Pizza-1 -Ordering Pizza-2 -Ordering Pizza-3 -Pizza-3 served -Pizza-2 served -Pizza-1 served - -Exception in thread "Thread-7" Exception in thread "Thread-6" java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0 -``` - -This happens because a thread running the `makePizzas` function checks to see if there is a pizza in the list, but before it can pull it out of the list, another `makePizzas` thread pulls it out of the list and the first thread gets an array out of bounds exception when it tries to grab the order that is no longer in the list. Any piece of code that accesses a resource that can be manipulated by multiple threads is called a `critical section`. Usually this involves code that **reads** and **modifies** a resource over multiple non-atomic statements. - -In the pizza shop case, the critical sections are when we add to the order list, - -```java -// modify -orders.add(order); -``` - -and when we read and remove from the order list. - -```java -// read -if (!orders.isEmpty()) { - // modify - var order = orders.remove(0); -} -``` - -### Synchronization - -To solve our race condition bug, we need to protect our critical sections by synchronizing their access so that only one thread can use the shared resource at a time. This can be done by creating a `synchronized` code block around any critical section. - -A `synchronized` code block begins with the `synchronized` statement and takes a synchronization object as a parameter. The synchronization object can be any object, but you need to use the same synchronization object for each critical section you are trying to protect. When your code executes and hits the synchronization block it will call the `wait` and `notify` methods that your synchronization object inherits from the base `Object` class in order to block multiple threads from entering the critical section at the same time. The synchronization code block is defined by the curly braces that surround the entire critical section. - -The syntax looks like the following. - -```java -synchronized (object) { - // code that reads or modifies a shared resource -} -``` - -For our pizza shop, we need to identify any critical sections. We only have one shared resource, the order list, and so we look for any place where it is read or modified. This includes where we add to the list, where we check its length, and also when we remove from the list. - -We use the `orders` object as the object for the synchronized statement. You can use any object, but it must be the same exact object used in all critical sections that you want to synchronize. It is common to use the resource object, an object specifically created for synchronization (e.g. `Object lock = new Object()`, the `this` pointer of the class, a static object (e.g. `static Object lock = new Object()`, or the class object (e.g. `this.class`) depending on the scope of the resource you are trying to synchronize. - -We can make our pizza shop thread safe by adding a critical section to both the `takeOrders` function and the `makePizzas` function. - -```java -public class PizzaSyncExample { - final static ArrayList orders = new ArrayList<>(); - - public static void main(String[] args) throws Exception { - new Thread(() -> takeOrders()).start(); - - for (var i = 0; i < 10; i++) { - new Thread(() -> makePizzas()).start(); - } - } - - static void takeOrders() { - for (var i = 1; i < 1000; i++) { - var order = "Pizza-" + i; - System.out.printf("Ordering %s%n", order); - synchronized (orders) { - orders.add(order); - } - } - } - - static void makePizzas() { - while (true) { - synchronized (orders) { - if (!orders.isEmpty()) { - var order = orders.remove(0); - System.out.printf("%s served%n", order); - } - } - } - } -} -``` - -Alternatively, if a function represents the entire critical section, you can use the `synchronized` keyword on the function signature. This syntax: - -```java -synchronized void func() { - // critical section -} -``` - -is equivalent to this syntax: - -```java -void func() { - synchronized(this) { - // critical section - } -} -``` - -## Multithreaded HTTP Requests - -It is important to recognize that if you create an HTTP server, you have created a multithreaded application. That is because multiple web browsers may connect to your server and make requests concurrently and the server code will automatically create a thread for each request. Consider the following code. - -```java -public class MultithreadedServerExample { - static int sum = 0; - - public static void main(String[] args) { - var javalin = Javalin.create() - .get("/add/{value}", (ctx) -> { - int value = Integer.parseInt(ctx.pathParam("value")); - sum += value; - ctx.result(" " + sum); - }) - .start(8080); - } -} -``` - -In this example, the `sum` variable is read and modified in the endpoint handler. If you execute the the following commands from your command console, it will rapidly send 100 add requests and 100 subtract requests to the server. The requests may not fire at exactly the same rate so the intermediate values may fluctuate. By the end of the operation, once all the operations have completed, we would expect for the sum to be back at 0. - -```sh -for i in {1..100}; do curl localhost:8080/add/1; print ""; done & -for i in {1..100}; do curl localhost:8080/add/-1; print ""; done & -wait -``` - -However, because the `sum += ...` command executes as separate read and write statements, a race condition exists which results in one of the thread's values being overwritten by another value. This effectively discards the change and causes our system to lose information; these losses accumulate and vary from run to run based on the way the requests are received from the network and scheduled by the kernel. Repeatedly testing this sample provided final sums between -30 and +24 (when the answer should always be _zero_). That's a lot of variance for a system that people expect to "just work." - -We can solve this by synchronizing the access to the critical section of code. - -```java -public class SynchronizedMultithreadedServerExample { - static int sum = 0; - static Object lock = new Object(); - - public static void main(String[] args) { - var javalin = Javalin.create() - .get("/add/{value}", (ctx) -> { - synchronized (lock) { - int value = Integer.parseInt(ctx.pathParam("value")); - sum += value; - ctx.result(" " + sum); - } - }) - .start(8080); - } -} -``` - -## Atomic Concurrency - -The Java concurrency package also includes several classes that make it so that you don't create critical sections that have to be protected with a synchronization object. One of these classes is `AtomicInteger`. Remember that you only need to protect resources that take several steps to modify (e.g. read/modify/write). By modifying a resource over multiple statements, you allow another thread to slip in between and change the resource you are working with. If you can read/modify/write a resource in on statement, or atomically, then there is no need to synchronize the object across threads. We can rewrite our server example to use an `AtomicInteger` instead of the simple `int` type. Then instead of reading the value and modifying it, we simply call the `AtomicInteger.addAndGet` method to do do both in one atomic step. This makes things completely thread safe. - -```java -public class AtomicServerExample { - static AtomicInteger sum = new AtomicInteger(0); - - public static void main(String[] args) { - var javalin = Javalin.create() - .get("/add/{value}", (ctx) -> { - int value = Integer.parseInt(ctx.pathParam("value")); - int newValue = sum.addAndGet(value); - ctx.result(" " + newValue); - }) - .start(8080); - } -} -``` - -There are other atomic classes in the JDK that you might find useful in order to support concurrency. This includes the following. - -| Class | Description | -| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| AtomicInteger | Atomically add to the value of an integer. | -| AtomicBoolean | Atomically change a boolean value if it is the given value. | -| BlockingQueue | A thread-safe queue that allows threads to add and remove elements without worrying about synchronization. It is useful for implementing producer-consumer patterns. | -| LinkedBlockingQueue | An implementation of the BlockingQueue interface that uses a linked list to store its elements. It is a good choice for applications that require high throughput and low latency. | -| ArrayBlockingQueue | An implementation of the BlockingQueue interface that uses an array to store its elements. It is a good choice for applications that require bounded capacity and fast access times. | -| ConcurrentHashMap | A thread-safe implementation of the HashMap class. It is a good choice for applications that require a high-performance map that can be safely accessed by multiple threads. | -| CopyOnWriteArrayList | A thread-safe implementation of the ArrayList class. It is a good choice for applications that require a read-heavy list that can be occasionally modified. | - -## Database Transactions - -Memory is not the only resource that might be corrupted by non-synchronized thread access. It is common to have multiple threads accessing a database at the same time. If your application needs to read something from the database, modify it, and then write back to the database then you have an opportunity for corruption. - -Consider an example where you have a table that stores a unique username along with their email address. When you try to add a new user, you first check to see if the username is already in the table. If it is then it returns an error, otherwise it writes the user to the table. Notice that this is the classic read/modify pattern that causes a problem for multithreaded applications. As long as only one thread can write to the database at a time then everything will be fine, but if you allow multiple users to make HTTP endpoint requests then you have the possibility of corruption. - -```java -public static void main(String[] args) throws Exception { - var username = args[0]; - var email = args[1]; - configureDatabase(); - - try (var conn = getConnection()) { - if (!userExists(conn, username)) { - insertUser(conn, username, email); - } - } -} - -static void insertUser(Connection conn, String username, String email) throws SQLException { - try (var preparedStatement = conn.prepareStatement("INSERT INTO pet_store.user (username, email) VALUES(?, ?)")) { - preparedStatement.setString(1, username); - preparedStatement.setString(2, email); - preparedStatement.executeUpdate(); - } -} - -static boolean userExists(Connection conn, String username) throws SQLException { - try (var preparedStatement = conn.prepareStatement("SELECT username FROM pet_store.user WHERE username=?")) { - preparedStatement.setString(1, username); - try (var rs = preparedStatement.executeQuery()) { - return rs.next(); - } - } -} -``` - -To solve this problem you can tell the database to consider all requests made on a connection as a single transaction. Using a transaction makes it so that if any database requests fails, then all the requests fail and are reversed. It also makes it so all requests are executed atomically. That means that no other connection can modify the database resources used by the transaction while the transaction is executing. To create a transaction we would modify the above code to first create a transaction by turning off the automatic commitment of each statement as it executes by calling `setAutoCommit(false)`. We then execute multiple queries, insert, update, or delete statements. We then commit all the statements atomically by calling `commit`, or if we want to discard all the work that the statements did we call `rollback`. - -```java -public static void main(String[] args) throws Exception { - var username = args[0]; - var email = args[1]; - configureDatabase(); - - try (var conn = getConnection()) { - conn.setAutoCommit(false); - - try { - if (!userExists(conn, username)) { - insertUser(conn, username, email); - conn.commit(); - } - } catch (SQLException e) { - conn.rollback(); - } - } -} -``` - -### Database Transaction Alternatives - -One of the major problems with using concurrency to increase the throughput of your application, is that the coding complexity and processing overhead can create new problems. When synchronizing threads you can deadlock the application, or create too many threads and cause thread starvation. Likewise, database transactions significantly impact the performance of your database if used incorrectly or excessively. - -Instead of using transactions you can use other methods to make things execute concurrently. One solution to the problem that we defined above, is to make the username a unique key for the table. That way if you try to insert two rows with the same username, the database will enforce the uniqueness and reject the second request. - -Database Management Systems (DBMS) often contain clauses that make statements atomic. You can use the `INSERT IGNORE` syntax to not execute the statement if the row already has the value you are attempting to set. If you are trying to do an insert if something doesn't exist, or an update if it does exist, you can use the `INSERT … ON DUPLICATE KEY UPDATE` syntax. - -Any of these options will increase the performance of your database if you are attempting to modify a single table. That leaves the use of transactions for when you need to execute multiple statements, such as when you are modifying multiple tables that are related with foreign keys. - -## Concurrency in the Chess Application - -Now that we understand the power and complexity of concurrent programming we can look at the chess application and decide if we already have concurrency bugs, or if we could increase the performance of the application by introducing concurrency. - -The client program itself only allows one player at a time. However, it can receive asynchronous WebSocket messages on a thread that is different from the main UI thread. This means there is the possibility of our shared client state becoming corrupted. - -1. If a user leaves a game and the server concurrently receives a MAKE_MOVE message that could put the user back into the game. - -Additionally, our HTTP server allows multiple clients to communicate with the server, and so we need to consider every shared memory access or database interaction. At this point in our development there shouldn't be any shared memory resources, and so that only leaves the database requests. - -An obvious problem results from storing game state in a serialized representation. The database has no visibility into what the game object represents. That means that you cannot use the database to provide synchronization and therefore must synchronize the access in your server code. - -There are several possible corruptions that we need to consider. - -1. Two users can both claim the same color if both request the color concurrently. The server will return affirmatively to both, but only record one player as claiming the color. -1. A request to claim a color can be lost if another user concurrently claims the other color. -1. A single user can make multiple moves if executed from multiple threads. For example, a quick execution of concurrent requests could move all of the pawns. - -All of these problems can be mitigated by using atomic operations or thread synchronization to protect critical sections. The important first step is to recognize that you have a multithreaded application and to consider all of the ways your shared data needs to be protected. - -## Things to Understand - -- What is a thread? -- Creating and executing a simple thread in Java -- Using a thread pool (ExecutorService in Java) to run multiple threads -- What is a race condition (or race hazard)? -- How to use database transactions to avoid race conditions -- How to use "synchronized" methods and code blocks in Java to avoid race conditions -- How to avoid race conditions in the Chess server and client programs - -## Videos - -- 🎥 [Concurrency Overview (12:12)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=4a305382-e8a4-4c69-a7d6-b1aa010e1c9b&start=0) - [[transcript]](https://github.com/user-attachments/files/17736816/CS_240_Concurrency_Overview_Transcript.pdf) -- 🎥 [Thread Synchronization (3:13)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=c095f9f7-b0d9-42ea-9e9c-b1aa0111ddfb&start=0) - [[transcript]](https://github.com/user-attachments/files/17736824/CS_240_Thread_Synchronization_Transcript.pdf) -- 🎥 [Thread Pools (12:48)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=fb5eda11-a69c-4b37-b1ec-b1aa011313f5&start=0) - [[transcript]](https://github.com/user-attachments/files/17736836/CS_240_Thread_Pools_Transcript.pdf) -- 🎥 [Race Conditions (14:14)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=701222ac-dfd5-4117-bed0-b1aa0116d8e9&start=0) - [[transcript]](https://github.com/user-attachments/files/17736864/CS_240_Race_Conditions_Transcript.pdf) -- 🎥 [Writing Threadsafe Code Part 1: Database Transactions (5:52)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=49333b55-7fb3-4a6c-b109-b1aa011b00b3&start=0) - [[transcript]](https://github.com/user-attachments/files/17736871/CS_240_Writing_Thread_Safe_Code_Part_1_Database_Transactions_Transcript.pdf) -- 🎥 [Writing Threadsafe Code Part 2: Synchronized Methods (4:13)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=76b856ae-054c-43d9-9ca6-b1aa011d0b9a&start=0) - [[transcript]](https://github.com/user-attachments/files/17736877/CS_240_Writing_Thread_Safe_Code_Part_2_Synchronized_Methods_Transcript.pdf) -- 🎥 [Writing Threadsafe Code Part 3: Synchronized Code Blocks(5:44)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=bae2b472-34bb-4da6-87a4-b1aa011e7b2e&start=0) - [[transcript]](https://github.com/user-attachments/files/17736903/CS_240_Writing_Thread_Safe_Code_Part_3_Synchronized_Code_Blocks_Transcript.pdf) -- 🎥 [Writing Threadsafe Code Part 4: Atomic Variables (13:21)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=24d88711-3841-4494-b0b4-b1aa01207780&start=0) - [[transcript]](https://github.com/user-attachments/files/17736907/CS_240_Writing_Thread_Safe_Code_Part_4_Atomic_Variables_Transcript.pdf) -- 🎥 [Race Conditions in Chess (5:38)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=40f625da-e37e-4b91-8dbd-b1aa0124d6ff&start=0) - [[transcript]](https://github.com/user-attachments/files/17736920/CS_240_Race_Conditions_in_Chess_Transcript.pdf) - -## Demonstration code - -📁 [Java Thread Example](example-code/src/demo/JavaThreadExample.java) - -📁 [Java Thread Pool Example](example-code/src/demo/JavaThreadPoolExample.java) - -📁 [File Race Condition Example](example-code/src/demo/FileRaceConditionExample.java) - -📁 [Synchronized Stack Example](example-code/src/demo/Stack.java) diff --git a/instruction/concurrency/example-code/.idea/.gitignore b/instruction/concurrency/example-code/.idea/.gitignore deleted file mode 100644 index 26d33521..00000000 --- a/instruction/concurrency/example-code/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/instruction/concurrency/example-code/.idea/misc.xml b/instruction/concurrency/example-code/.idea/misc.xml deleted file mode 100644 index 24965408..00000000 --- a/instruction/concurrency/example-code/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/instruction/concurrency/example-code/.idea/modules.xml b/instruction/concurrency/example-code/.idea/modules.xml deleted file mode 100644 index fc53374c..00000000 --- a/instruction/concurrency/example-code/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/instruction/concurrency/example-code/.idea/uiDesigner.xml b/instruction/concurrency/example-code/.idea/uiDesigner.xml deleted file mode 100644 index 2b63946d..00000000 --- a/instruction/concurrency/example-code/.idea/uiDesigner.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/instruction/concurrency/example-code/code.iml b/instruction/concurrency/example-code/code.iml deleted file mode 100644 index c90834f2..00000000 --- a/instruction/concurrency/example-code/code.iml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/instruction/concurrency/example-code/src/demo/FileRaceConditionExample.java b/instruction/concurrency/example-code/src/demo/FileRaceConditionExample.java deleted file mode 100644 index f35ffad8..00000000 --- a/instruction/concurrency/example-code/src/demo/FileRaceConditionExample.java +++ /dev/null @@ -1,78 +0,0 @@ -package demo; - -import java.io.*; -import java.util.*; -import java.util.concurrent.*; - - -public class FileRaceConditionExample { - - public static void main(String[] args) throws InterruptedException { - - final File FILE_PATH = new File("count"); - final int ITERATIONS = 100; - - try (var output = new PrintWriter(FILE_PATH)) { - output.print(0); - } catch (IOException ex) { - ex.printStackTrace(); - } - - ExecutorService threadPool = Executors.newCachedThreadPool(); - - for (int i = 0; i < 2; ++i) { - threadPool.submit(new FileCounter(i, FILE_PATH, ITERATIONS)); - } - - threadPool.shutdown(); - - threadPool.awaitTermination(1, TimeUnit.MINUTES); - - System.out.println("Leaving Main Thread"); - } -} - - -class FileCounter implements Runnable { - - private static Object lockObject = new Object(); - - private int _threadNumber; - private File _filePath; - private int _iterations; - - public FileCounter(int threadNumber, File filePath, int iterations) { - _threadNumber = threadNumber; - _filePath = filePath; - _iterations = iterations; - } - - public void run() { - for (int i = 0; i < _iterations; ++i) { - try { - incrementCount(); - } catch (Exception ex) { - ex.printStackTrace(); - } - } - } - - private void incrementCount() throws IOException { - synchronized (lockObject) { - int count; - - try (var input = new Scanner(_filePath)) { - count = input.nextInt(); - } - - ++count; - - try (var output = new PrintWriter(_filePath)) { - output.print(count); - } - - System.out.println("Thread_" + _threadNumber + ": " + count); - } - } - -} \ No newline at end of file diff --git a/instruction/concurrency/example-code/src/demo/JavaThreadExample.java b/instruction/concurrency/example-code/src/demo/JavaThreadExample.java deleted file mode 100644 index a90ad2e4..00000000 --- a/instruction/concurrency/example-code/src/demo/JavaThreadExample.java +++ /dev/null @@ -1,40 +0,0 @@ -package demo; - - -public class JavaThreadExample { - - public static void main(String[] args) { - - CountingThread countUp = new CountingThread("UP", 0, 50, 1); - CountingThread countDown = new CountingThread("DOWN", 50, 0, -1); - - countUp.start(); - countDown.start(); - - System.out.println("Leaving Main Thread"); - } -} - - -class CountingThread extends Thread { - - private String _name; - private int _start; - private int _stop; - private int _increment; - - public CountingThread(String name, int start, int stop, int increment) { - _name = name; - _start = start; - _stop = stop; - _increment = increment; - } - - public void run() { - for (int i = _start; i != _stop; i += _increment) { - System.out.println(_name + ": " + i); - } - } -} - - diff --git a/instruction/concurrency/example-code/src/demo/JavaThreadPoolExample.java b/instruction/concurrency/example-code/src/demo/JavaThreadPoolExample.java deleted file mode 100644 index d112232a..00000000 --- a/instruction/concurrency/example-code/src/demo/JavaThreadPoolExample.java +++ /dev/null @@ -1,47 +0,0 @@ -package demo; - -import java.util.concurrent.*; - - -public class JavaThreadPoolExample { - - public static void main(String[] args) throws InterruptedException { - - ExecutorService threadPool = Executors.newFixedThreadPool(5); - - for (int i = 0; i < 10; ++i) { - threadPool.submit(new Counter("UP_" + i, 0, 50, 1)); - threadPool.submit(new Counter("DOWN_" + i, 50, 0, -1)); - } - - threadPool.shutdown(); - - threadPool.awaitTermination(1, TimeUnit.MINUTES); - - System.out.println("Leaving Main Thread"); - } -} - - -class Counter implements Runnable { - - private String _name; - private int _start; - private int _stop; - private int _increment; - - public Counter(String name, int start, int stop, int increment) { - _name = name; - _start = start; - _stop = stop; - _increment = increment; - } - - public void run() { - for (int i = _start; i != _stop; i += _increment) { - System.out.println(_name + ": " + i); - } - } -} - - diff --git a/instruction/concurrency/example-code/src/demo/Stack.java b/instruction/concurrency/example-code/src/demo/Stack.java deleted file mode 100644 index 543f638f..00000000 --- a/instruction/concurrency/example-code/src/demo/Stack.java +++ /dev/null @@ -1,24 +0,0 @@ -package demo; - -import java.util.LinkedList; -import java.util.NoSuchElementException; - -public class Stack { - private LinkedList values; - - public Stack() { - values = new LinkedList(); - } - - public synchronized void push(T value) { - values.addFirst(value); - } - - public synchronized T pop() throws NoSuchElementException { - return values.removeFirst(); - } - - public synchronized int size() { - return values.size(); - } -} diff --git a/instruction/concurrency/executor.png b/instruction/concurrency/executor.png deleted file mode 100644 index af52916e..00000000 Binary files a/instruction/concurrency/executor.png and /dev/null differ diff --git a/instruction/concurrency/models.png b/instruction/concurrency/models.png deleted file mode 100644 index d02e47f8..00000000 Binary files a/instruction/concurrency/models.png and /dev/null differ diff --git a/instruction/concurrency/multiThreaded.gif b/instruction/concurrency/multiThreaded.gif deleted file mode 100644 index 2ee7f901..00000000 Binary files a/instruction/concurrency/multiThreaded.gif and /dev/null differ diff --git a/instruction/concurrency/singleThread.gif b/instruction/concurrency/singleThread.gif deleted file mode 100644 index c645fc0a..00000000 Binary files a/instruction/concurrency/singleThread.gif and /dev/null differ diff --git a/instruction/concurrency/singleThreadQueue.gif b/instruction/concurrency/singleThreadQueue.gif deleted file mode 100644 index bd1a6530..00000000 Binary files a/instruction/concurrency/singleThreadQueue.gif and /dev/null differ diff --git a/instruction/console-ui/Midnight_Commander_(2005)_en.png b/instruction/console-ui/Midnight_Commander_(2005)_en.png deleted file mode 100644 index 46e1dfc5..00000000 Binary files a/instruction/console-ui/Midnight_Commander_(2005)_en.png and /dev/null differ diff --git a/instruction/console-ui/Vim-(logiciel)-console.png b/instruction/console-ui/Vim-(logiciel)-console.png deleted file mode 100644 index 4b3f2edf..00000000 Binary files a/instruction/console-ui/Vim-(logiciel)-console.png and /dev/null differ diff --git a/instruction/console-ui/calculator.png b/instruction/console-ui/calculator.png deleted file mode 100644 index 06dc1b54..00000000 Binary files a/instruction/console-ui/calculator.png and /dev/null differ diff --git a/instruction/console-ui/console-ui.md b/instruction/console-ui/console-ui.md deleted file mode 100644 index e060cc12..00000000 --- a/instruction/console-ui/console-ui.md +++ /dev/null @@ -1,202 +0,0 @@ -# Console User Interface (UI) - -🖥️ [Slides](https://docs.google.com/presentation/d/1zHBDEdB6xhvnA12m3VliBaOQj7yZOxjT/edit#slide=id.p1) - -🖥️ [Lecture Videos](#videos) - -Typically, when a program prints output to the console (or terminal), the text is plain and without much formatting. However, it is possible to create fairly nice console user interfaces that include formatted, colored text, and use character-based graphics. This lecture explains how to create a text-based console user interface, with an emphasis on how to implement the Chess client user interface. - -![Console User Interface]() - -## Processing Application Arguments - -When the Java runtime executes your application, it passes any arguments that were specified on the command line in the `args` parameter of your `main` function. - -```java -public class ArgsExample { - public static void main(String[] args) { - for (var i = 0; i < args.length; i++) { - System.out.printf("%d. %s%n", i+1, args[i]); - } - } -} -``` - -If you run this code with the following command you will see how the arguments are output. - -```sh -➜ java ArgsExample.java a b c -1. a -2. b -3. c -``` - -Using application arguments is a convenient way to customize how your application operates. For example, with your chess client application you could allow the user to provide the URL of your chess server. The code below specifies a default URL, but allows the user to override it with a provided value. - -```java -public class ClientMain { - public static void main(String[] args) { - var serverUrl = "http://localhost:8080"; - if (args.length == 1) { - serverUrl = args[0]; - } - - new Repl(serverUrl).run(); - } -} -``` - -## Writing to Standard Out - -The `System.out` object is an output stream that is associated with whatever your operating system has decided is the output device. Usually this is the command line console that launched your application. You can use the `System.out` object to print out text to the command line and communicate with the user of your application. We can combine the use of application arguments and `System.out` to create a rudimentary calculator that does simple addition. - -```java -public class CalculatorExample { - public static void main(String[] args) { - int result = 0; - for (var arg : args) { - result += Integer.parseInt(arg); - } - var equation = String.join(" + ", args); - System.out.printf("%s = %d", equation, result); - } -} -``` - -```sh -➜ java CalculatorExample.java 1 2 3 - -1 + 2 + 3 = 6 -``` - -## Outputting in Color - -Most command line consoles support a common set of escape codes that allow you to change the background and foreground colors of the characters that are output. You control the color changes by outputting a sequence of special escape characters. For example, if you run the following command in your console window you will see that the text `red on blue` is output with red text and a blue background. - -```sh -echo -e "\u001b[31;44;1m red on blue " -``` - -The color command begins the escape sequence `\u001b[`. This tells the console that you are using unicode characters. If you only plan on using ANSI characters then you can use the code `\033[`. You then supply sequence commands separated with a semicolon (`;`). `31` specifies that we are setting the foreground color to red. `44` sets the background color to blue. `1` turns on bold. The sequence is terminated with `m`. - -### Color Options - -| Color | Foreground | Background | -| ---------------- | ---------- | ---------- | -| Black | 30 | 40 | -| Red | 31 | 41 | -| Green | 32 | 42 | -| Orange | 33 | 43 | -| Blue | 34 | 44 | -| Magenta | 35 | 45 | -| Cyan | 36 | 46 | -| Light gray | 37 | 47 | -| Fallback default | 39 | 49 | -| Dark gray | | 100 | -| Light red | | 101 | -| Light green | | 102 | -| Yellow | | 103 | -| Light blue | | 104 | -| Light purple | | 105 | -| Teal | | 106 | -| White | | 107 | - -### Modifiers - -| Modification | Code | -| ------------ | ---- | -| none | 0 | -| bold | 1 | -| underscore | 4 | -| blink | 5 | -| reverse | 7 | -| concealed | 8 | - -## Coloring With Java - -We can enhance our calculator to use different colors by printing out the correct control colors before we print the text. We do this by providing the escape sequences for the different foreground and background colors we want to use to `System.out` before we print any text. - -```java -public class FancyCalculatorExample { - - public static void main(String[] args) { - int result = 0; - for (var arg : args) { - result += Integer.parseInt(arg); - } - - System.out.print("\u001b[35;100m"); - System.out.printf(" %s = ", String.join(" + ", args)); - System.out.print("\u001b[107m"); - System.out.printf(" %d ", result); - } -} -``` - -Now when we run our calculator, we see the color changes. - -![calculator](calculator.png) - -## Reading from Standard In - -In order to create a complete console based application you need to also receive input from your user. When your java program executes, the operating system usually streams the buttons pressed on a keyboard to the `System.in` object. - -To demonstrate reading from the keyboard, we can modify our calculator to read our numbers from what the user is typing instead of reading it from the application arguments. To do this we wrap `System.in` with the `Scanner` class so that we can read from the user's input a line at a time. Once the user presses `Enter` we can parse out the numbers and output the result. - -```java -import java.util.Scanner; - -public class InteractiveCalculatorExample { - public static void main(String[] args) throws Exception { - while (true) { - System.out.printf("Type your numbers%n>>> "); - Scanner scanner = new Scanner(System.in); - String line = scanner.nextLine(); - var numbers = line.split(" "); - - int result = 0; - for (var number : numbers) { - result += Integer.parseInt(number); - } - var equation = String.join(" + ", numbers); - System.out.printf("%s = %d%n", equation, result); - } - } -} -``` - -```sh -➜ java InteractiveCalculatorExample.java - -Input your numbers ->>> 1 2 3 -1 + 2 + 3 = 6 -``` - -## Things to Understand - -- How to use command line arguments -- How to write to the standard out -- How to read from standard in -- How to use terminal control codes to clear the terminal, set background and text colors, and text attributes such as bold, faint, italic, underline, and blinking -- How to use Unicode characters to draw the chess board and pieces for the Chess project - -## Videos - -- 🎥 [Console User Interfaces (3:02)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=363561fc-a6f6-49ad-8d10-b19a0149fe26) - [[transcript]](https://github.com/user-attachments/files/17736991/CS_240_Console_User_Interfaces_Transcript.pdf) -- 🎥 [Terminal Control Codes (10:53)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=46e4a217-ef9c-4950-8b35-b19a014b2881) - [[transcript]](https://github.com/user-attachments/files/17737000/CS_240_Terminal_Control_Codes_Transcript.pdf) -- 🎥 [Drawing the Chess Board (3:54)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=35f1e7b0-1ff0-4e59-932b-b19a014e9192) - [[transcript]](https://github.com/user-attachments/files/17737013/CS_240_Drawing_The_Chess_Board_Transcript.pdf) - -## Demonstration code - -The following demonstration code uses escape sequences to draw a tic tac toe board. This is similar to the concepts you will need in order to implement the rendering of the chess board. The `EscapeSequences.java` file contains many standard codes that you might find useful in your programming. - -![tic tac toe](tictactoe.png) - -📁 [Tic-Tac-Toe](example-code/src/ui/TicTacToe.java) - -📁 [Escape Sequences](example-code/src/ui/EscapeSequences.java) - -``` - -``` diff --git a/instruction/console-ui/example-code/.idea/.gitignore b/instruction/console-ui/example-code/.idea/.gitignore deleted file mode 100644 index 26d33521..00000000 --- a/instruction/console-ui/example-code/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/instruction/console-ui/example-code/.idea/misc.xml b/instruction/console-ui/example-code/.idea/misc.xml deleted file mode 100644 index 958e7fe5..00000000 --- a/instruction/console-ui/example-code/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/instruction/console-ui/example-code/.idea/modules.xml b/instruction/console-ui/example-code/.idea/modules.xml deleted file mode 100644 index fc53374c..00000000 --- a/instruction/console-ui/example-code/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/instruction/console-ui/example-code/.idea/uiDesigner.xml b/instruction/console-ui/example-code/.idea/uiDesigner.xml deleted file mode 100644 index 2b63946d..00000000 --- a/instruction/console-ui/example-code/.idea/uiDesigner.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/instruction/console-ui/example-code/code.iml b/instruction/console-ui/example-code/code.iml deleted file mode 100644 index c90834f2..00000000 --- a/instruction/console-ui/example-code/code.iml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/instruction/console-ui/example-code/src/ui/EscapeSequences.java b/instruction/console-ui/example-code/src/ui/EscapeSequences.java deleted file mode 100644 index ad9070ce..00000000 --- a/instruction/console-ui/example-code/src/ui/EscapeSequences.java +++ /dev/null @@ -1,78 +0,0 @@ -package ui; - -/** - * This class contains constants and functions relating to ANSI Escape Sequences that are useful in the Client display - */ -public class EscapeSequences { - - private static final String UNICODE_ESCAPE = "\u001b"; - private static final String ANSI_ESCAPE = "\033"; - - public static final String ERASE_SCREEN = UNICODE_ESCAPE + "[H" + UNICODE_ESCAPE + "[2J"; - public static final String ERASE_LINE = UNICODE_ESCAPE + "[2K"; - - public static final String SET_TEXT_BOLD = UNICODE_ESCAPE + "[1m"; - public static final String SET_TEXT_FAINT = UNICODE_ESCAPE + "[2m"; - public static final String RESET_TEXT_BOLD_FAINT = UNICODE_ESCAPE + "[22m"; - public static final String SET_TEXT_ITALIC = UNICODE_ESCAPE + "[3m"; - public static final String RESET_TEXT_ITALIC = UNICODE_ESCAPE + "[23m"; - public static final String SET_TEXT_UNDERLINE = UNICODE_ESCAPE + "[4m"; - public static final String RESET_TEXT_UNDERLINE = UNICODE_ESCAPE + "[24m"; - public static final String SET_TEXT_BLINKING = UNICODE_ESCAPE + "[5m"; - public static final String RESET_TEXT_BLINKING = UNICODE_ESCAPE + "[25m"; - - private static final String SET_TEXT_COLOR = UNICODE_ESCAPE + "[38;5;"; - private static final String SET_BG_COLOR = UNICODE_ESCAPE + "[48;5;"; - - public static final String SET_TEXT_COLOR_BLACK = SET_TEXT_COLOR + "0m"; - public static final String SET_TEXT_COLOR_LIGHT_GREY = SET_TEXT_COLOR + "242m"; - public static final String SET_TEXT_COLOR_DARK_GREY = SET_TEXT_COLOR + "235m"; - public static final String SET_TEXT_COLOR_RED = SET_TEXT_COLOR + "160m"; - public static final String SET_TEXT_COLOR_GREEN = SET_TEXT_COLOR + "46m"; - public static final String SET_TEXT_COLOR_YELLOW = SET_TEXT_COLOR + "226m"; - public static final String SET_TEXT_COLOR_BLUE = SET_TEXT_COLOR + "12m"; - public static final String SET_TEXT_COLOR_MAGENTA = SET_TEXT_COLOR + "5m"; - public static final String SET_TEXT_COLOR_WHITE = SET_TEXT_COLOR + "15m"; - public static final String RESET_TEXT_COLOR = SET_TEXT_COLOR + "0m"; - - public static final String SET_BG_COLOR_BLACK = SET_BG_COLOR + "0m"; - public static final String SET_BG_COLOR_LIGHT_GREY = SET_BG_COLOR + "242m"; - public static final String SET_BG_COLOR_DARK_GREY = SET_BG_COLOR + "235m"; - public static final String SET_BG_COLOR_RED = SET_BG_COLOR + "160m"; - public static final String SET_BG_COLOR_GREEN = SET_BG_COLOR + "46m"; - public static final String SET_BG_COLOR_DARK_GREEN = SET_BG_COLOR + "22m"; - public static final String SET_BG_COLOR_YELLOW = SET_BG_COLOR + "226m"; - public static final String SET_BG_COLOR_BLUE = SET_BG_COLOR + "12m"; - public static final String SET_BG_COLOR_MAGENTA = SET_BG_COLOR + "5m"; - public static final String SET_BG_COLOR_WHITE = SET_BG_COLOR + "15m"; - public static final String RESET_BG_COLOR = SET_BG_COLOR + "0m"; - - public static final String WHITE_KING = " K "; - public static final String WHITE_QUEEN = " Q "; - public static final String WHITE_BISHOP = " B "; - public static final String WHITE_KNIGHT = " N "; - public static final String WHITE_ROOK = " R "; - public static final String WHITE_PAWN = " P "; - public static final String BLACK_KING = " K "; - public static final String BLACK_QUEEN = " Q "; - public static final String BLACK_BISHOP = " B "; - public static final String BLACK_KNIGHT = " N "; - public static final String BLACK_ROOK = " R "; - public static final String BLACK_PAWN = " P "; - public static final String EMPTY = " "; - -// public static final String WHITE_KING = " ♔ "; //" \u2654 "; -// public static final String WHITE_QUEEN = " ♕ "; //" \u2655 "; -// public static final String WHITE_BISHOP = " ♗ "; //" \u2656 "; -// public static final String WHITE_KNIGHT = " ♘ "; //" \u2657 "; -// public static final String WHITE_ROOK = " ♖ "; //" \u2658 "; -// public static final String WHITE_PAWN = " ♙ "; //" \u2659 "; -// public static final String BLACK_KING = " ♚ "; //" \u265A "; -// public static final String BLACK_QUEEN = " ♛ "; //" \u265B "; -// public static final String BLACK_BISHOP = " ♝ "; //" \u265C "; -// public static final String BLACK_KNIGHT = " ♞ "; //" \u265D "; -// public static final String BLACK_ROOK = " ♜ "; //" \u265E "; -// public static final String BLACK_PAWN = " ♟ "; //" \u265F "; -// public static final String EMPTY = " \u2003 "; - -} diff --git a/instruction/console-ui/example-code/src/ui/TicTacToe.java b/instruction/console-ui/example-code/src/ui/TicTacToe.java deleted file mode 100644 index 5aa1f797..00000000 --- a/instruction/console-ui/example-code/src/ui/TicTacToe.java +++ /dev/null @@ -1,153 +0,0 @@ -package ui; - -import java.io.PrintStream; -import java.nio.charset.StandardCharsets; -import java.util.Random; - -import static ui.EscapeSequences.*; - -public class TicTacToe { - - // Board dimensions. - private static final int BOARD_SIZE_IN_SQUARES = 3; - private static final int SQUARE_SIZE_IN_PADDED_CHARS = 3; - private static final int LINE_WIDTH_IN_PADDED_CHARS = 1; - - // Padded characters. - private static final String EMPTY = " "; - private static final String X = " X "; - private static final String O = " O "; - - private static Random rand = new Random(); - - - public static void main(String[] args) { - var out = new PrintStream(System.out, true, StandardCharsets.UTF_8); - - out.print(ERASE_SCREEN); - - drawHeaders(out); - - drawTicTacToeBoard(out); - - out.print(SET_BG_COLOR_BLACK); - out.print(SET_TEXT_COLOR_WHITE); - } - - private static void drawHeaders(PrintStream out) { - - setBlack(out); - - String[] headers = { "TIC", "TAC", "TOE" }; - for (int boardCol = 0; boardCol < BOARD_SIZE_IN_SQUARES; ++boardCol) { - drawHeader(out, headers[boardCol]); - - if (boardCol < BOARD_SIZE_IN_SQUARES - 1) { - out.print(EMPTY.repeat(LINE_WIDTH_IN_PADDED_CHARS)); - } - } - - out.println(); - } - - private static void drawHeader(PrintStream out, String headerText) { - int prefixLength = SQUARE_SIZE_IN_PADDED_CHARS / 2; - int suffixLength = SQUARE_SIZE_IN_PADDED_CHARS - prefixLength - 1; - - out.print(EMPTY.repeat(prefixLength)); - printHeaderText(out, headerText); - out.print(EMPTY.repeat(suffixLength)); - } - - private static void printHeaderText(PrintStream out, String player) { - out.print(SET_BG_COLOR_BLACK); - out.print(SET_TEXT_COLOR_GREEN); - - out.print(player); - - setBlack(out); - } - - private static void drawTicTacToeBoard(PrintStream out) { - - for (int boardRow = 0; boardRow < BOARD_SIZE_IN_SQUARES; ++boardRow) { - - drawRowOfSquares(out); - - if (boardRow < BOARD_SIZE_IN_SQUARES - 1) { - // Draw horizontal row separator. - drawHorizontalLine(out); - setBlack(out); - } - } - } - - private static void drawRowOfSquares(PrintStream out) { - - for (int squareRow = 0; squareRow < SQUARE_SIZE_IN_PADDED_CHARS; ++squareRow) { - for (int boardCol = 0; boardCol < BOARD_SIZE_IN_SQUARES; ++boardCol) { - setWhite(out); - - if (squareRow == SQUARE_SIZE_IN_PADDED_CHARS / 2) { - int prefixLength = SQUARE_SIZE_IN_PADDED_CHARS / 2; - int suffixLength = SQUARE_SIZE_IN_PADDED_CHARS - prefixLength - 1; - - out.print(EMPTY.repeat(prefixLength)); - printPlayer(out, rand.nextBoolean() ? X : O); - out.print(EMPTY.repeat(suffixLength)); - } - else { - out.print(EMPTY.repeat(SQUARE_SIZE_IN_PADDED_CHARS)); - } - - if (boardCol < BOARD_SIZE_IN_SQUARES - 1) { - // Draw vertical column separator. - setRed(out); - out.print(EMPTY.repeat(LINE_WIDTH_IN_PADDED_CHARS)); - } - - setBlack(out); - } - - out.println(); - } - } - - private static void drawHorizontalLine(PrintStream out) { - - int boardSizeInSpaces = BOARD_SIZE_IN_SQUARES * SQUARE_SIZE_IN_PADDED_CHARS + - (BOARD_SIZE_IN_SQUARES - 1) * LINE_WIDTH_IN_PADDED_CHARS; - - for (int lineRow = 0; lineRow < LINE_WIDTH_IN_PADDED_CHARS; ++lineRow) { - setRed(out); - out.print(EMPTY.repeat(boardSizeInSpaces)); - - setBlack(out); - out.println(); - } - } - - private static void setWhite(PrintStream out) { - out.print(SET_BG_COLOR_WHITE); - out.print(SET_TEXT_COLOR_WHITE); - } - - private static void setRed(PrintStream out) { - out.print(SET_BG_COLOR_RED); - out.print(SET_TEXT_COLOR_RED); - } - - private static void setBlack(PrintStream out) { - out.print(SET_BG_COLOR_BLACK); - out.print(SET_TEXT_COLOR_BLACK); - } - - private static void printPlayer(PrintStream out, String player) { - out.print(SET_BG_COLOR_WHITE); - out.print(SET_TEXT_COLOR_BLACK); - - out.print(player); - - setWhite(out); - } -} diff --git a/instruction/console-ui/tictactoe.png b/instruction/console-ui/tictactoe.png deleted file mode 100644 index 38acee95..00000000 Binary files a/instruction/console-ui/tictactoe.png and /dev/null differ diff --git a/instruction/copying-objects/copying-objects.md b/instruction/copying-objects/copying-objects.md deleted file mode 100644 index 4e25b6a7..00000000 --- a/instruction/copying-objects/copying-objects.md +++ /dev/null @@ -1,152 +0,0 @@ -# Copying Objects - -🖥️ [Slides](https://docs.google.com/presentation/d/1TAl9a41zLMyQmuQTYgxmYct6gsWgWopc/edit?usp=sharing&ouid=114081115660452804792&rtpof=true&sd=true) - -🖥️ [Lecture Videos](#videos) - -## Copy Constructors - -An easy way to provide the ability to make a copy of your object is to create a constructor that takes an object you want to copy. This is commonly called a `Copy Constructor`. - -Here is an example of a class that has a default constructor, and a copy constructor. Both constructors create the object, but with the default constructor you supply all the fields. With the copy constructor all the fields are copied out of the provided object. - -```java -public class MyClass { - String name; - - public MyClass(String name) { - this.name = name; - } - - public MyClass(MyClass copy) { - this.name = new String(copy.name); - } -} -``` - -## Shallow and Deep Copies - -When you make a copy of an object you must consider the important difference between making a copy of the data and making a copy of a pointer to the data. When you make a copy of the data you make an independent duplicate of the data. When you copy a pointer to data, the copy can change when the data that the pointer references changes. - -A copy that only copies the references is called a `shallow copy`. A copy that copies all of the data values is called a `deep copy`. It is fine to do a shallow copy if all of the fields in the object are immutable (i.e. cannot change), but if the data can change, then you need to copy all of the fields.That makes it so the values in the copy cannot be changed by manipulating the source object fields. - -Here is an example of a shallow copy. Notice that it only copies the reference to the `data` array. That means that if the values in that array are changed, then it will also change the values in the copy. - -```java -public class ShallowCopy { - String[] data; - - public ShallowCopy() { - data = new String[]{"a", "b", "c"}; - } - - public ShallowCopy(ShallowCopy copy) { - data = copy.data; - } - - public static void main(String[] args) { - var source = new ShallowCopy(); - var copy = new ShallowCopy(source); - - // Change the source data - source.data[0] = "x"; - - // ERROR: The copy outputs 'x' - System.out.println(copy.data[0]); - } -} -``` - -To correct this problem, we do a deep copy of all the object fields. That makes it so we can modify the source object without modifying the copy. - -```java -public class DeepCopy { - String[] data; - - public DeepCopy() { - data = new String[]{"a", "b", "c"}; - } - - public DeepCopy(DeepCopy copy) { - data = Arrays.copyOf(copy.data, copy.data.length); - } - - public static void main(String[] args) { - var source = new DeepCopy(); - var copy = new DeepCopy(source); - - // Change the source data - source.data[0] = "x"; - - // Copy is independent from source - // outputs 'a' - System.out.println(copy.data[0]); - } -} -``` - -## Clone - -As an alternative to writing a copy constructor, you can override the `clone` operation of the Java `Object` class. - -```java -public static class CloneCopy implements Cloneable { - String[] data; - - public CloneCopy() { - data = new String[]{"a", "b", "c"}; - } - - @Override - protected Object clone() throws CloneNotSupportedException { - var clone = new CloneCopy(); - clone.data = Arrays.copyOf(data, data.length); - return clone; - } - - public static void main(String[] args) throws CloneNotSupportedException { - var source = new CloneCopy(); - var copy = (CloneCopy) source.clone(); - - System.out.println(copy.data[0]); - } -} -``` - -However, overriding `clone` requires that you implement the `Cloneable` marker interface, do a typecasting on the result, and handle the possibility of a `CloneNotSupportedException`. - -## Things to Understand - -- The difference between a shallow copy and a deep copy -- How to use `copy constructors` to implement deep copies -- How to use `clone` methods to implement deep copies - -## Videos - -- 🎥 [Copying Objects - Overview (6:54)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=cfdfab1b-0c5b-4cdc-b40f-b19c011ca4cc) - [[transcript]](https://github.com/user-attachments/files/17737115/CS_240_Copying_Objects_Overview_Transcript.pdf) -- 🎥 [Making a Shallow Copy (7:24)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=eb6a8c67-9f61-4741-a099-b19c011ebcfe) - [[transcript]](https://github.com/user-attachments/files/17737145/CS_240_Copying_Objects_Shallow_Copy_Example_Transcript.pdf) -- 🎥 [Making a Deep Copy (8:32)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=3e36cfa7-d993-4460-a24b-b19c0121c62a) - [[transcript]](https://github.com/user-attachments/files/17737161/CS_240_Copying_Objects_Deep_Copy_Examples_Transcript.pdf) - -## Demonstration code - -### Copy - -📁 [Course](example-code/Course.java) - -📁 [Faculty](example-code/Faculty.java) - -📁 [Person](example-code/Person.java) - -📁 [Student](example-code/Student.java) - -📁 [Test](example-code/Test.java) - -📁 [YearInSchool](example-code/YearInSchool.java) - -### Clone - -📁 [Person](example-code/clone/Person.java) - -📁 [Person2](example-code/clone/Person2.java) - -📁 [Team](example-code/clone/Team.java) diff --git a/instruction/copying-objects/example-code/Course.java b/instruction/copying-objects/example-code/Course.java deleted file mode 100644 index 5485ec2c..00000000 --- a/instruction/copying-objects/example-code/Course.java +++ /dev/null @@ -1,48 +0,0 @@ -package school; - -public class Course { - - private String name; - - public Course(String name) { - setName(name); - } - - public Course(Course other) { - setName(other.name); - } - - // This is needed to change "clone" from protected to public - - @Override - protected Course clone() { - return new Course(this); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public boolean equals(Object o) { - if (o == this) - return true; - - if (o == null) { - return false; - } - - if (getClass() != o.getClass()) { - return false; - } - - Course other = (Course)o; - - return name.equals(other.name); - } - -} diff --git a/instruction/copying-objects/example-code/Faculty.java b/instruction/copying-objects/example-code/Faculty.java deleted file mode 100644 index 32ce6404..00000000 --- a/instruction/copying-objects/example-code/Faculty.java +++ /dev/null @@ -1,62 +0,0 @@ -package school; - -import java.util.*; - -public class Faculty extends Person { - - private ArrayList courses; - private ArrayList students; - - public Faculty(int id, String name) { - super(id, name); - courses = new ArrayList(); - students = new ArrayList(); - } - - public Faculty(Faculty other) { - super(other); - - courses = new ArrayList(); - for (Course c : other.courses) { - courses.add(new Course(c)); - } - - students = new ArrayList(); - for (Student s : other.students) { - students.add(new Student(s)); - } - } - - public Faculty clone() { - return new Faculty(this); - } - - // Instructor methods - - public void addCourse(Course c) { - courses.add(c); - } - - public void removeCourse(Course c) { - courses.remove(c); - } - - public Course[] getCourses() { - return courses.toArray(new Course[courses.size()]); - } - - // Advisor methods - - public void addStudent(Student s) { - students.add(s); - } - - public void removeStudent(Student s) { - students.remove(s); - } - - public Student[] getStudents() { - return students.toArray(new Student[students.size()]); - } - -} diff --git a/instruction/copying-objects/example-code/Person.java b/instruction/copying-objects/example-code/Person.java deleted file mode 100644 index bf1751e8..00000000 --- a/instruction/copying-objects/example-code/Person.java +++ /dev/null @@ -1,57 +0,0 @@ -package school; - -public class Person { - - private int id; - private String name; - - public Person(int id, String name) { - setId(id); - setName(name); - } - - public Person(Person other) { - setId(other.id); - setName(other.name); - } - - @Override - public Person clone() { - return new Person(this); - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public boolean equals(Object o) { - if (o == this) - return true; - - if (o == null) { - return false; - } - - if (getClass() != o.getClass()) { - return false; - } - - Person other = (Person)o; - - return (id == other.id && name.equals(other.name)); - } - -} diff --git a/instruction/copying-objects/example-code/Student.java b/instruction/copying-objects/example-code/Student.java deleted file mode 100644 index 1b2db117..00000000 --- a/instruction/copying-objects/example-code/Student.java +++ /dev/null @@ -1,31 +0,0 @@ -package school; - -public class Student extends Person { - - private YearInSchool year; - - public Student(int id, String name, YearInSchool year) { - super(id, name); - setYear(year); - } - - public Student(Student other) { - - super(other); - - setYear(other.year); - } - - public Student clone() { - return new Student(this); - } - - public YearInSchool getYear() { - return year; - } - - public void setYear(YearInSchool year) { - this.year = year; - } - -} diff --git a/instruction/copying-objects/example-code/Test.java b/instruction/copying-objects/example-code/Test.java deleted file mode 100644 index 28141b7c..00000000 --- a/instruction/copying-objects/example-code/Test.java +++ /dev/null @@ -1,38 +0,0 @@ -package school; - -public class Test { - - public static void main(String[] args) throws CloneNotSupportedException { - - Course physics900 = new Course("Physics 900"); - Course biology350 = new Course("Biology 350"); - - Student bob = new Student(1, "Bob", YearInSchool.SENIOR); - Student kathy = new Student(2, "Kathy", YearInSchool.SENIOR); - - Faculty prof = new Faculty(3, "Einstein"); - prof.addCourse(physics900); - prof.addCourse(biology350); - prof.addStudent(bob); - prof.addStudent(kathy); - - Faculty profCopy = new Faculty(prof); - - prof.removeCourse(physics900); - prof.removeStudent(kathy); - - Faculty profCopy2 = prof.clone(); - - prof.removeCourse(biology350); - prof.removeStudent(bob); - - System.out.println(prof.getCourses().length); - System.out.println(prof.getStudents().length); - System.out.println(profCopy.getCourses().length); - System.out.println(profCopy.getStudents().length); - System.out.println(profCopy2.getCourses().length); - System.out.println(profCopy2.getStudents().length); - - } - -} diff --git a/instruction/copying-objects/example-code/YearInSchool.java b/instruction/copying-objects/example-code/YearInSchool.java deleted file mode 100644 index 8a1a4b76..00000000 --- a/instruction/copying-objects/example-code/YearInSchool.java +++ /dev/null @@ -1,8 +0,0 @@ -package school; - -public enum YearInSchool { - FRESHMAN, - SOPHOMORE, - JUNIOR, - SENIOR -} diff --git a/instruction/copying-objects/example-code/clone/Person.java b/instruction/copying-objects/example-code/clone/Person.java deleted file mode 100644 index c5a563cb..00000000 --- a/instruction/copying-objects/example-code/clone/Person.java +++ /dev/null @@ -1,38 +0,0 @@ -public class Person implements Cloneable { - - private String firstName; - private String lastName; - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - @Override - public String toString() { - return "Person{" + - "firstName='" + firstName + '\'' + - ", lastName='" + lastName + '\'' + - '}'; - } - - /** - * Overridden to make it public. Always call super.clone(). Makes a shallow copy. OK in this case because all - * instance variables are immutable. - */ - @Override - public Object clone() throws CloneNotSupportedException { - return super.clone(); - } -} diff --git a/instruction/copying-objects/example-code/clone/Person2.java b/instruction/copying-objects/example-code/clone/Person2.java deleted file mode 100644 index 85b2535d..00000000 --- a/instruction/copying-objects/example-code/clone/Person2.java +++ /dev/null @@ -1,47 +0,0 @@ -import java.util.Date; - -public class Person2 implements Cloneable { - - private String firstName; - private String lastName; - private Date birthdate; - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public Date getBirthdate() { - return birthdate; - } - - public void setBirthdate(Date birthdate) { - this.birthdate = birthdate; - } - - @Override - public Person2 clone() { - try { - Person2 clone = (Person2) super.clone(); - - // Clone / copy the birthdate. Not safe to share because it's mutable. - Date clonedBirthdate = (Date) getBirthdate().clone(); - clone.setBirthdate(clonedBirthdate); - - return clone; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } -} diff --git a/instruction/copying-objects/example-code/clone/Team.java b/instruction/copying-objects/example-code/clone/Team.java deleted file mode 100644 index b892e4f1..00000000 --- a/instruction/copying-objects/example-code/clone/Team.java +++ /dev/null @@ -1,79 +0,0 @@ -import java.util.ArrayList; -import java.util.List; - -public class Team implements Cloneable { - - private String name; - private List members; - - public static void main(String [] args) throws CloneNotSupportedException { - Person p = new Person(); - p.setFirstName("Original First Name"); - p.setLastName("Original Last Name"); - - Team t = new Team("Original Team", List.of(p)); - System.out.println("Original Team:\n\t" + t); - - Team t2 = t.clone(); - t2.setName("Cloned Team"); - List cloneMembers = t2.getMembers(); - cloneMembers.get(0).setFirstName("Changed First Name"); - cloneMembers.get(0).setLastName("Changed Last Name"); - - System.out.println("Original Team after making and changing clone:\n\t" + t); - System.out.println("Cloned Team:\n\t" + t2); - } - - public Team(String name, List members) { - this.name = name; - this.members = members; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public List getMembers() { - return members; - } - - public void addMember(Person person) { - members.add(person); - } - - public void removeMember(Person person) { - members.remove(person); - } - - @Override - public String toString() { - return "Team{" + - "name='" + name + '\'' + - ", members=" + members + - '}'; - } - - @Override - public Team clone() { - try { - Team clone = (Team) super.clone(); - - // Comment these lines out to see what happens with a shallow copy that contains a mutable instance variable - List cloneMembers = new ArrayList<>(); - for(Person person : members) { - Person personClone = person.clone(); - cloneMembers.add(personClone); - } - - clone.members = cloneMembers; - - return clone; - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } -} diff --git a/instruction/curl/curl.md b/instruction/curl/curl.md deleted file mode 100644 index c1040d2f..00000000 --- a/instruction/curl/curl.md +++ /dev/null @@ -1,71 +0,0 @@ -# cURL - -🖥️ [Slides](https://docs.google.com/presentation/d/1pM_tUVD7c6kWpHkEwuRpbWmoBFss3GuK/edit?usp=sharing&ouid=114081115660452804792&rtpof=true&sd=true) - -🖥️ [Lecture Videos](#videos) - -Curl (technically `cURL`) is essentially a command line web browser. It allows you to see, debug, and execute HTTP requests from the command line console window of any operating system. This makes Curl a valuable tool for any software engineer. - -The most basic syntax of curl is to simply provide a URL to the Curl application. - -```sh -➜ curl byu.edu - - - -301 Moved Permanently - -

Moved Permanently

-

The document has moved here.

- -``` - -This will return the HTML page located at the URL. You can see the details of the HTTP connection and request by including the `-v` parameter. This is helpful for debugging HTTP headers and security interactions. - -```sh -➜ curl -v byu.edu - -* Connected to byu.edu (128.187.16.184) port 80 (#0) -> GET / HTTP/1.1 -> Host: byu.edu -> User-Agent: curl/7.87.0 -> Accept: */* -> -< HTTP/1.1 301 Moved Permanently -< Date: Thu, 03 Aug 2023 16:52:23 GMT -< Server: Apache/2.5.37 (Red Hat Enterprise Linux) OpenSSL/1.1.1k -< Location: https://www.byu.edu/ -< Expires: Thu, 03 Aug 2023 17:52:23 GMT -< Content-Length: 228 -< Content-Type: text/html; charset=iso-8859-1 -< - - -... -``` - -If you want to make a Curl request that explicitly provides the HTTP method, headers, or body, you can use the following syntax. - -| Purpose | Syntax | Example | -| ------- | --------- | ---------------------------------- | -| Method | -X method | -X PUT | -| Header | -H header | -H "content-type:application/json" | -| Body | -d body | -d '{"name":"berners-lee"}' | - -Putting this all together in a single request would look like the following if you were trying to create a new chess game using a server running locally. - -```sh -➜ curl -X POST localhost:8080/game -d '{ "gameName": "speed"}' -H "Authorization:607b0857" -``` - -Take some time to get familiar with Curl. You can use it to test your server, programmatically make batch requests, or to probe and debug how other web services work. - -> [!NOTE] -> -> Note that when running under Windows Powershell `curl` is mapped to the `Invoke-WebRequest` command. You don't want to use that. Instead type `curl.exe` to actually access Curl. - -## Videos - -- 🎥 [cURL: Client for URLs (9:17)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=16506fca-9d4b-4f5e-89ad-b185015d13e5) - [[transcript]](https://github.com/user-attachments/files/17737197/CS_240_cURL_Client_for_URLs_Transcript.pdf) -- 🎥 [cURL for Chess (4:24)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=07ab3fff-d972-45b1-9f9f-b185015fdf9f) - [[transcript]](https://github.com/user-attachments/files/17737202/CS_240_cURL_for_Chess_Transcript.pdf) -- 🎥 [cURL Alternatives (5:45)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=10dd7fb8-74c3-4b05-a2db-b18501615517) - [[transcript]](https://github.com/user-attachments/files/17737211/CS_240_cURL_Alternatives_Transcript.pdf) diff --git a/instruction/db-jdbc/db-jdbc.md b/instruction/db-jdbc/db-jdbc.md deleted file mode 100644 index 606c5b10..00000000 --- a/instruction/db-jdbc/db-jdbc.md +++ /dev/null @@ -1,357 +0,0 @@ -# Relational Databases - JDBC - -🖥️ [Slides - JDBC](https://docs.google.com/presentation/d/12XS7en64-oQYivKayGyNGueWphiL6mm5) - -🖥️ [Lecture Videos](#videos) - -Now that we have covered what relational databases are and how to use SQL to interact with them, it is time to discuss how to use SQL from a Java program. Java uses a standard interface library called Java Database Connector (JDBC). This library provides you with classes to connect to a database, execute SQL queries, and process the results. - -We also discuss using the popular open source relational database software MySQL. You will install a MySQL server in your development environment and use it as the persistent data store for your chess program. - -To actually create a connection to your database you must first download the MySQL JDBC driver jar. You can then use the standard JDK JDBC classes as shown in the following example: - -```java -import java.sql.DriverManager; - -public class DatabaseExample { - public static void main(String[] args) throws Exception { - try (var conn = DriverManager.getConnection("jdbc:mysql://localhost:3306", "root", "monkeypie")) { - conn.setCatalog("pet_store"); - - try (var preparedStatement = conn.prepareStatement("SELECT id, name, type from pet")) { - try (var rs = preparedStatement.executeQuery()) { - while (rs.next()) { - var id = rs.getInt("id"); - var name = rs.getString("name"); - var type = rs.getString("type"); - - System.out.printf("id: %d, name: %s, type: %s%n", id, name, type); - } - } - } - } - } -} -``` - -## Database Connectors - -The JDK `java.sql` package contains interfaces and abstract classes for connecting to a RDBMS. However, you need to download a specific database connector that implements the interfaces for the RDBMS that you are using. For this course, we use the `mysql.connector`. Here is an example of using IntelliJ to import the MySQL connection into a project. - -![MySQL connector](mysql-connector.png) - -Most modern connector packages don't require you to initialize the connector. The act of including it in your classpath will do that automatically. Once you have installed the package for your project you are good to create connections with it. - -## Obtaining a Connection - -With the database specific connector installed, you are ready to use the JDK `DriverManager` class to get a connection to the database specified by a given URL. The DriverManager inspects the URL and passes the connection request over appropriate database connector. In the example below, the DriverManager will pass the request to the MySQL connector that registered itself when the connector package was loaded. - -If the connector exists, and the RDBMS specified by the URL is available then you will get back a connection object. - -Note that we use the Java `try-with-resource` syntax so that the connection will be released as soon as the try block exits. This is important, because the number of available connections is limited by the database server. If you don't release connections then any request for new connections will fail and you will no longer be able to use the database. - -```java - -Connection getConnection() throws SQLException { - return DriverManager.getConnection("jdbc:mysql://localhost:3306", "root", "monkeypie"); -} - -void makeSQLCalls() throws SQLException { - try (var conn = getConnection()) { - // Execute SQL statements on the connection here - } -} -``` - -## Creating Databases and Tables - -Once you have a connection you can use it to create databases and tables. It is a good idea to create Java code that create your databases and tables if they don't exist either when your application starts up, or with an explicit initialization operation. This allows you to define all of the infrastructure that your code depends upon in the code that actually uses the infrastructure. That way you can always assume that the required databases and tables exist instead of managing and initializing that infrastructure as some sort of external manual executed process. - -We can fully configure a theoretical pet store application by doing the following. - -1. Get a connection to the RDBMS. -1. Create the pet store database if it doesn't exist. -1. Create the pet table if it doesn't exist. - -```java -void configureDatabase() throws SQLException { - try (var conn = getConnection()) { - var createDbStatement = conn.prepareStatement("CREATE DATABASE IF NOT EXISTS pet_store"); - createDbStatement.executeUpdate(); - - conn.setCatalog("pet_store"); - - var createPetTable = """ - CREATE TABLE IF NOT EXISTS pet ( - id INT NOT NULL AUTO_INCREMENT, - name VARCHAR(255) NOT NULL, - type VARCHAR(255) NOT NULL, - PRIMARY KEY (id) - )"""; - - - try (var createTableStatement = conn.prepareStatement(createPetTable)) { - createTableStatement.executeUpdate(); - } - } -} -``` - -We execute SQL statements by first creating a `PreparedStatement`. You can think of a prepared statement as a SQL statement template. In the above code we create two prepared statements. One to create the database and one to create the table. Both of the statements are created with hard coded strings that represent the desired SQL to execute. - -In the same way that you had to use a try-with-resource block to close our connection, you also need to make sure you close the prepared statement when we are done with it. - -Make sure you note the use of the `setCatalog` call. We call this after we have made sure that the pet store database is created. Setting the catalog tells the connection that all subsequent calls should be done in the context of the given database. In the example, we are creating the `pet` table in the context of the `pet_store` database. - -## Inserting Data - -Once you have created your database and tables, you can now start inserting data. The following is an example of how to insert a new row in the `pet` table. - -```java -int insertPet(Connection conn, String name, String type) throws SQLException { - try (var preparedStatement = conn.prepareStatement("INSERT INTO pet (name, type) VALUES(?, ?)", RETURN_GENERATED_KEYS)) { - preparedStatement.setString(1, name); - preparedStatement.setString(2, type); - - preparedStatement.executeUpdate(); - - var resultSet = preparedStatement.getGeneratedKeys(); - var ID = 0; - if (resultSet.next()) { - ID = resultSet.getInt(1); - } - - return ID; - } -} -``` - -This code starts by creating a new prepared statement that contains the `INSERT` command. Note however that instead of concatenating the pet name and type directly into the command, we parameterize the prepared statement by putting question marks (`?`) into the statement syntax. We then supply the values of the parameter with the `setString` method on the prepared statement. - -The first parameter to setString tells the position of the parameter to set and the second parameter is the value to set. This corresponds to the position of the question marks in the prepared statement. - -```java -preparedStatement.setString(1, name); -``` - -There are `set` methods for all the SQL types (e.g. `setInt`, `setDate`, `setBoolean`, ...). Make sure you use the one that conforms with the schema of the table field you are populating. - -Once you have created the statement and populated the parameters you then execute the statement by calling `executeUpdate`. If this doesn't throw an exception then the data was successfully inserted. - -### Generating Primary Keys - -Our insertPet function does one more thing. If you look at the table schema that we defined when we created the pet table, you will see that we set the `id` column to `AUTO_INCREMENT` the value. - -```sql -CREATE TABLE IF NOT EXISTS pet ( - id INT NOT NULL AUTO_INCREMENT, - name VARCHAR(255) NOT NULL, - type VARCHAR(255) NOT NULL, - PRIMARY KEY (id) -) -``` - -We use this to let the database handle the assignment of the primary key for the pet record. That means that we don't have to provide that as a field when when insert a new pet, but we do potentially want to know what ID was generated by the database. To get the generated value we specify the parameter `RETURN_GENERATED_KEYS` when we create the prepared statement. We then call `getGeneratedKeys` after we called `executeUpdate`. This returns an iterator, but we are only interested in the first value and so we advance the iterator with `next` and the call `getInt` to get the new ID - -```java -var resultSet = preparedStatement.getGeneratedKeys(); -var ID = 0; -if (resultSet.next()) { - ID = resultSet.getInt(1); -} -``` - -### Protecting Against SQL Injections - -![XKCD SQL Injection](xkcd-sql-injection.png) - -> Source: _Randall Munroe. Exploits of a Mom. xkcd. (CC BY-NC 2.5)_ - -Using the `set` functions on a prepared statement helps prevent against what is know as a SQL injection. A SQL injection allows an attacker to inject unexpected SQL syntax into a statement. Consider the case where we simplify the `insertPet` function to the following. - -```java -void insertPet(String name) throws SQLException { - var conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/pet_store?allowMultiQueries=true", "root", "monkeypie"); - - var statement = "INSERT INTO pet (name) VALUES('" + name + "')"; - System.out.println(statement); - try (var preparedStatement = conn.prepareStatement(statement)) { - preparedStatement.executeUpdate(); - } -} -``` - -This makes the code smaller and would actually work fine in the normal case. The problem occurs when someone supplies the following name: - -```java -name = "joe','cat'); DROP TABLE pet; -- "; -``` - -This will result in execution the following SQL. This first inserts a bogus pet record, and then deletes the entire pet table. - -```sql -INSERT INTO pet (name, type) VALUES('joe','cat'); DROP TABLE pet; -- 'rat') -``` - -In addition to using the database connection prepared statements properly you also want to sanitize any input that comes from a user to make sure it only contains patterns that you expect. A more secure insert pet method would look like the following. - -```java -void insertPet(String name) throws SQLException { - var conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/pet_store", "root", "monkeypie"); - - if (name.matches("[a-zA-Z]+")) { - var statement = "INSERT INTO pet (name) VALUES(?)"; - try (var preparedStatement = conn.prepareStatement(statement)) { - preparedStatement.setString(1, name); - preparedStatement.executeUpdate(); - } - } -} -``` - -This does the following to help prevent a SQL injection. - -1. Validates the input is of the expected format. -1. Uses the prepared statement `set` functions which also validates the format. -1. Does not allow multiple statements to execute in a single `executeUpdate` request by removing the `allowMultiQueries` from the connection string. - -## Updates - -You can update data using JDBC code similar to what you used for inserting data. You just need to change the SQL statement that you execute. - -```java -void updatePet(Connection conn, int petID, String name) throws SQLException { - try (var preparedStatement = conn.prepareStatement("UPDATE pet SET name=? WHERE id=?")) { - preparedStatement.setString(1, name); - preparedStatement.setInt(2, petID); - - preparedStatement.executeUpdate(); - } -} -``` - -Make sure that you include a `WHERE` clause in your statement. Otherwise you will update every row in the table. - -## Deleting Data - -You delete data by specifying a `DELETE` SQL statement along with a `WHERE` clause that describes the rows to delete. - -```java -void deletePet(Connection conn, int petID) throws SQLException { - try (var preparedStatement = conn.prepareStatement("DELETE FROM pet WHERE id=?")) { - preparedStatement.setInt(1, petID); - preparedStatement.executeUpdate(); - } -} -``` - -If no clause is specified then all of the table data will be deleted. However, it is usually more efficient to use a `TRUNCATE tableNameHere` statement instead. - -## Queries - -In order to get things out of a database you need to call the `executeQuery` method on the prepared statement. The `executeQuery` method returns a `java.sql.ResultSet` object that represents the resulting rows that match the query. - -You can parameterize the `SELECT` statement with a `WHERE` clause, or you can leave out the clause if you want to return all rows in the table. - -```java -void queryPets(Connection conn, String findType) throws SQLException { - try (var preparedStatement = conn.prepareStatement("SELECT id, name, type FROM pet WHERE type=?")) { - preparedStatement.setString(1, findType); - try (var rs = preparedStatement.executeQuery()) { - while (rs.next()) { - var id = rs.getInt("id"); - var name = rs.getString("name"); - var type = rs.getString("type"); - - System.out.printf("id: %d, name: %s, type: %s%n", id, name, type); - } - } - } -} -``` - -When you call the result set `next` method it will advance the result to the next row. If it ever returns `false` then it means you have read all the matching rows. You can read the fields of the row with the result set `get` methods. There are methods for all of the basic SQL types. Make sure that the fields you getting are represented in the fields that your `SELECT` statement requested. - -Make sure that your wrap the result set returned from the query with a `try-with-resource` block so that you release the resources associated with the result once you are done with them. - -## Text and Blob Types - -Sometimes you want to store large text or binary data in the database. In MySQL the `text` type can represent large textual sequences, and the `blob` type represents large binary sequences. These can be as large as 4 gigabytes. Blob and text data is not searchable, but it is convenient to associate it with some other indexed fields. For example, a commonly used pattern called a `key-value` store, associates a single key field with a blob field. This basically uses the database as a big persistent map. - -Another example of storing large text data comes from the chess application. With chess, you need to store your game board and make it searchable using the game ID. One way to do this is to serialize your board to JSON and then place the JSON data in a `text` field. - -We can demonstrate how to do this using a simple pet record that has a name, a type, and a list of friends. - -```java -record Pet(String name, String type, String[] friends) {} -``` - -We can create a SQL table schema that matches this structure by including field for the friend array that has type `longtext`. The `longtext` type can represent text strings that are up to 4 gigabytes and so that will be plenty of room for all the pet's friends. - -```java -CREATE TABLE IF NOT EXISTS pet ( - name VARCHAR(255) DEFAULT NULL, - type VARCHAR(255) DEFAULT NULL, - friends longtext NOT NULL -); -``` - -We then create a method that inserts a pet into the database. This serializes the friend field using the Gson `toJson` method, and uses a SQL INSERT statement to put it in the database. - -```java -void insertPet(Connection conn, Pet pet) throws SQLException { - try (var preparedStatement = conn.prepareStatement("INSERT INTO pet (name, type, friends) VALUES(?, ?, ?)")) { - preparedStatement.setString(1, pet.name); - preparedStatement.setString(2, pet.type); - - // Serialize and store the friend JSON. - var json = new Gson().toJson(pet.friends); - preparedStatement.setString(3, json); - - preparedStatement.executeUpdate(); - } -} -``` - -And we can read it back out again by reversing the process. - -```java -Collection listPets(Connection conn) throws SQLException { - var pets = new ArrayList(); - try (var preparedStatement = conn.prepareStatement("SELECT name, type, friends FROM pet")) { - try (var rs = preparedStatement.executeQuery()) { - while (rs.next()) { - var name = rs.getString("name"); - var type = rs.getString("type"); - - // Read and deserialize the friend JSON. - var json = rs.getString("friends"); - var friends = new Gson().fromJson(json, String[].class); - - pets.add(new Pet(name, type, friends)); - } - } - } - return pets; -} -``` - -## Things to Understand - -- How to execute each of the SQL statements from Java using JDBC -- How to use JDBC connections -- How to generate Java objects from the result of a database query -- How to retrieve auto-increment primary keys that were generate by the database on an insert -- How to get a JDBC driver for MySQL and make it available to your Java project/code - -## Videos - -- 🎥 [JDBC Overview (3:20)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=cabe9971-3ff7-4579-be2e-ad660156090a&start=0) - [[transcript]](https://github.com/user-attachments/files/17737257/CS_240_Java_Database_Access_with_JDBC_Transcript.pdf) -- 🎥 [JDBC Drivers and Connections (7:44)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=1e05e1c6-727a-49b4-81cf-b1a00121b187&start=0) - [[transcript]](https://github.com/user-attachments/files/17737267/CS_240_JDBC_Drivers_and_Connections_Transcript.pdf) -- 🎥 [Executing Queries with JDBC (5:09)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=79ca902c-b6f2-457a-b1ba-b1a0012499a4&start=0) - [[transcript]](https://github.com/user-attachments/files/17737275/CS_240_Executing_Queries_with_JDBC_Transcript.pdf) -- 🎥 [Executing Insert, Update, and Delete Statements (8:37)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=9033fa48-8260-4701-84ee-b1a001262b8c&start=0) - [[transcript]](https://github.com/user-attachments/files/17737292/CS_240_Executing_Insert_Update_and_Delete_Statements_Transcript.pdf) -- 🎥 [Retrieving Auto-Increment Primary Keys and Ending Transactions (4:33)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=78e3086c-c6de-43d0-bba5-b1a0012a17fa&start=0) - [[transcript]](https://github.com/user-attachments/files/17737303/CS_240_Retrieving_Auto_Increment_Primary_Keys_and_Ending_Transactions_Transcript.pdf) -- 🎥 [Usernames, Passwords, and User Permissions (3:25)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=636f5721-1e35-413e-a1fe-b1a0012d43d7&start=0) - [[transcript]](https://github.com/user-attachments/files/17737306/CS_240_Usernames_Passwords_and_User_Permissions_Transcript.pdf) -- 🎥 [JDBC - Putting It All Together (9:48)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=a882dded-56a9-43ff-b4fe-b1a0012e6341&start=0) - [[transcript]](https://github.com/user-attachments/files/17737311/CS_240_JDBC_Putting_It_All_Together_Transcript.pdf) -- 🎥 [Unit Testing Database Code (5:12)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=6d8bf3b3-3ddd-4f3d-b90d-ad6b014f2bb7&start=0) - [[transcript]](https://github.com/user-attachments/files/17780620/CS_240_Unit_Testing_Database_Code.pdf) -- 🎥 [Correction - Unit Testing Database Code (3:52)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=9178d92a-e41b-48f4-8e68-adf8015d7a91&start=0) - [[transcript]](https://github.com/user-attachments/files/17780623/CS_240_Unit_Testing_Database_Code_Correction.pdf) diff --git a/instruction/db-jdbc/mysql-connector.png b/instruction/db-jdbc/mysql-connector.png deleted file mode 100644 index 0fcbd9aa..00000000 Binary files a/instruction/db-jdbc/mysql-connector.png and /dev/null differ diff --git a/instruction/db-jdbc/xkcd-sql-injection.png b/instruction/db-jdbc/xkcd-sql-injection.png deleted file mode 100644 index af6683e2..00000000 Binary files a/instruction/db-jdbc/xkcd-sql-injection.png and /dev/null differ diff --git a/instruction/db-model/db-model.md b/instruction/db-model/db-model.md deleted file mode 100644 index 068186a9..00000000 --- a/instruction/db-model/db-model.md +++ /dev/null @@ -1,138 +0,0 @@ -# Relational Databases - The Relational Model - -🖥️ [Slides](https://docs.google.com/presentation/d/19nC7v6SDqoEeK75Mb-f6L3QhnbuP6Xfo/edit?usp=sharing&ouid=114081115660452804792&rtpof=true&sd=true) - -🖥️ [Lecture Videos](#videos) - -![Edgar Cobb](edgar-codd.png) - -> _source: [Wikipedia](https://en.wikipedia.org/wiki/Edgar_F._Codd)_ - -> “At the time, Nixon was normalizing relations with China. I figured that if he could normalize relations, then so could I.” -> -> — Edgar Cobb - -Relational databases are commonly used to persistently store and retrieve data. You can read and write data to a relational database from your program using the structured query language (SQL). Your code executes SQL statements against a database using standard library classes known as Java Database Connectivity (JDBC) package. Before we dive into how you actually write an application that uses a database, we first want to discuss how relational databases work. - -At a basic level, relational data is stored in a `database`. A database contains `tables`, and a table has a number of `columns` that define the fields of the table. This can be things like `name`, `phone number`, or `id`. When you insert data into a database table it becomes a `row` in the table. The inserted data must have fields that matches each of the tables columns. - -| column1 | column2 | column3 | -| ------- | ------- | ------- | -| row1 | row1 | row1 | -| row2 | row2 | row2 | -| row3 | row3 | row3 | - -Usually each table in a relational database will have a column that represents a unique ID for the table. You use the ID to request data back out of the table. - -## Mapping Objects to Tables - -Sometimes it is helpful to think about relational databases in the context of objects in your code. If you have a Java record in your code that represents the data for a pet, and you create three object from the `Pet` record definition, it might look like this the following. - -```java -record Pet(int id, String name, String type){} - -var pets = Pet[]{ - new Pet(93, "Fido", "dog"), - new Pet(14, "Puddles", "cat"), - new Pet(77, "Chip", "bird") -} -``` - -Using this example you can map the Java record declaration directly to a relational database table definition. The fields in the record map to the columns of the table. The Java record and the database table share the strong typing in their different representations. Each of the Java Pet objects in the array, map to a row in the database table. The following table is a relational representation of the Java code above. - -**Pet table** - -| id | name | type | -| --- | ------- | ---- | -| 93 | Fido | dog | -| 14 | Puddles | cat | -| 77 | Chip | bird | - -## Table Relationships - -The term `relational` in relational databases refers to the relationships that exist between tables. Relational databases seek to strictly promote cohesion and only represent one type of data in every table. Once you have represented cohesive data into different tables, you then create relationships between tables by referencing keys between tables. - -The following gives a simple visualization of a database named `pet-store` that contains a table for `pet`, `owner`, and `purchase`. The `pet` and `owner` tables are related to each other because of the key relationship defined in the `purchase` table. The purchase table maps what owner purchased which pet. - -**pet** - -| id | name | type | -| --- | ------- | ---- | -| 93 | Fido | dog | -| 14 | Puddles | cat | -| 77 | Chip | bird | - -**owner** - -| id | name | phoneNumber | -| --- | ---- | ----------- | -| 81 | Juan | 6196663333 | -| 82 | Bud | 8018889999 | - -**purchase** - -| id | ownerId | petId | -| --- | ------- | ----- | -| 51 | 81 | 93 | -| 52 | 82 | 77 | - -With your data stored in relational tables you can use the different ID fields of the table to cross-reference, or join, the data together to create new views of the data. A table column that represents the unique ID of the table data is called the `primary key` of the table. When a table column contains the primary key of a different table, it is called a `foreign key`. - -![table relationships](table-relationship.png) - -A good primary key has the following characteristics. - -- **Unique** - The key must be unique. -- **Stable** - The key doesn't change over time. For example, a person's name would be considered unstable because it could change during the person's life. -- **Simple** - Sometimes multiple fields must be combined to create a unique key that is representative of the row. However, you should attempt to keep the key as simple as possible because you reference the key so often when working with relational databases. - -## Decomposition - -All of the same principles of good software design also apply when creating representations in a relational model. For example, you don't want to create a single relational table that contains all of the properties for your entire application. Doing so would create a table that lacks cohesion. - -| ownerId | ownerName | petId | petName | petStore | storeCity | vaccinated | purchaseDate | -| ------- | --------- | ----- | ------- | --------- | --------- | ---------- | ------------ | -| 81 | Juan | 93 | Fido | Pets4You | Provo | true | 2026 | -| 82 | Bud | 77 | Chip | DoggyTown | Orem | false | 2027 | -| 83 | Bud | 56 | Puddles | DoggyTown | Orem | false | 2027 | - -Additionally, large, non-cohesive tables, force you to represent the same data in multiple rows which violates the DRY principle. Notice in the above example that the store information is repeated in multiple rows. Instead you want to `normalize` a table like this into multiple tables that each represent a single cohesive object. You then use relationships between the tables to create aggregations, or views as they are called in the relational model, as desired. - -## Views - -You can create new views of the relational data by specifying queries that `join` data from different tables based upon matching keys. - -From the pet store tables we defined above, we could create a different view of the data with a query that joined the owner name with the pet's name based upon the ID fields found in the purchase table. This query might look something like: - -```text -Join the owner and pet data together based upon matching pet IDs. -``` - -This would result in a view that would look like the following. - -| ownerId | ownerName | petId | petName | -| ------- | --------- | ----- | ------- | -| 81 | Juan | 93 | Fido | -| 82 | Bud | 77 | Chip | - -Data views are usually only created temporarily so that an application can use the aggregated data to facilitate the functionality of the application. That means they are created in memory and then thrown away once the application is done with them. - -## Working with Relational Data - -In practical terms, relational data is stored in a Relational Database Management System (RDBMS). For this course, we will use MySQL as our RDBMS. The language most commonly used to read, write, and query relational data is called Structure Query Language (SQL). We will discuss this declarative language as a future topic. - -## Things to Understand - -- How data is represented in the relational model -- How primary and foreign keys work -- How to represent one-to-one, one-to-many, and many-to-many relationships using primary and foreign keys -- What makes a good primary key -- How to model inheritance relationships in the relational model -- How to represent a data model in an ERD - -## Videos - -- 🎥 [Relational Databases Overview (5:02)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=10667c35-dea3-4f1e-8c91-ad66013d553b&start=0) - [[transcript]](https://github.com/user-attachments/files/17737470/CS_240_Relational_Databases_Overview_Transcript.pdf) -- 🎥 [Understanding the Relational Model (13:55)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=3ec3f6de-a112-4e0a-a0af-ad66013f8bc7&start=0) - [[transcript]](https://github.com/user-attachments/files/17780681/CS_240_Understanding_the_Relational_Model.pdf) -- 🎥 [Modeling a Database Schema (8:42)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=ee130025-e1ab-4f6b-a72c-ad660143e8aa&start=0) - [[transcript]](https://github.com/user-attachments/files/17780684/CS_240_Modeling_a_Database_Schema.pdf) -- 🎥 [Modeling Inheritance Relationships (7:42)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=6bb9d1f1-803c-4d8f-a5ea-ad660146883e&start=0) - [[transcript]](https://github.com/user-attachments/files/17780687/CS_240_Modeling_Inheritance_Relationships.pdf) diff --git a/instruction/db-model/diagram.uml b/instruction/db-model/diagram.uml deleted file mode 100644 index 2a386c11..00000000 --- a/instruction/db-model/diagram.uml +++ /dev/null @@ -1,23 +0,0 @@ -classDiagram - class pet { - id : primary key - name - type - } - - class owner { - id : primary key - name - phoneNumber - } - - - class purchase { - id : primary key - price - ownerId : foreign key - petId : foreign key - } - - purchase --> pet: petId -> id - purchase --> owner: ownerId -> id diff --git a/instruction/db-model/edgar-codd.png b/instruction/db-model/edgar-codd.png deleted file mode 100644 index 15bedd19..00000000 Binary files a/instruction/db-model/edgar-codd.png and /dev/null differ diff --git a/instruction/db-model/table-relationship.png b/instruction/db-model/table-relationship.png deleted file mode 100644 index 2f154cfb..00000000 Binary files a/instruction/db-model/table-relationship.png and /dev/null differ diff --git a/instruction/db-sql/db-sql.md b/instruction/db-sql/db-sql.md deleted file mode 100644 index c3b8042d..00000000 --- a/instruction/db-sql/db-sql.md +++ /dev/null @@ -1,335 +0,0 @@ -# Relational Databases - SQL - -🖥️ [Slides](https://docs.google.com/presentation/d/1_kGyItbM3fp0PQSemvBocclT8EU87rBX) - -🖥️ [Lecture Videos](#videos) - -`Structured Query Language` (SQL) is a programming language that is specifically designed to interact with relational databases. It contains statements for inserting, updating, reading, and deleting data. It also provides statements for managing the database and the users that have access to the database. - -You can categorizes the most commonly used SQL statements into the following buckets. - -1. **DDL** (Data Definition Language) - Create, alter, drop. -1. **DML** (Data Manipulation Language) - Insert, update, delete. -1. **DQL** (Data Query Language) - Select. - -Here is an example of SQL statements for creating a database, creating at table, and inserting some sample data. - -```sql -> CREATE DATABASE pet_store; -> USE pet_store; -> CREATE TABLE pet (id int, name varchar(255), type varchar(255)); -> INSERT INTO pet VALUES (93, "Fido", "dog"); -> INSERT INTO pet VALUES (14, "Puddles", "cat"); -> INSERT INTO pet VALUES (77, "Chip", "bird"); -> DESCRIBE pet; - -+-------+--------------+------+-----+---------+-------+ -| Field | Type | Null | Key | Default | Extra | -+-------+--------------+------+-----+---------+-------+ -| id | int | YES | | NULL | | -| name | varchar(255) | YES | | NULL | | -| type | varchar(255) | YES | | NULL | | -+-------+--------------+------+-----+---------+-------+ -``` - -The following demonstrates a simple query to read all of the pets in a database. - -```sql -> SELECT id, name, type FROM pet; - -+--------+----------+---------------+ -| id | name | type | -+--------+----------+---------------+ -| 93 | Fido | dog | -| 14 | Puddles | cat | -| 77 | Chip | bird | -+--------+----------+---------------+ -``` - -SQL is a declarative programming language. This means that you declare what you want rather than providing a series of imperative commands that define how to do something. - -In order to completely understand the above example we need to take a step back and examine some of the common SQL statements. - -## Working with Databases - -A database server, or remote database management system (RDBMS), can host one or more databases. You create a database with the `CREATE DATABASE` statement. After you have created the database you execute a `USE` statement to select the database for use with future commands. - -```sql -CREATE DATABASE pet_store; -USE pet_store; -``` - -All databases have a default character set that is used for representing bytes as text. Normally if you would specify the character set when you execute the CREATE request, but if you didn't then you can alter the database with the `ALTER DATABASE` statement. For example, if you wanted to represent text with UTF-8, we would run the following ALTER statement. - -```sql -ALTER DATABASE pet_store CHARACTER SET utf8mb4; -``` - -If you want to delete a database, and all of the data it represents, you use the `DROP DATABASE` statement. While this should rarely be used in a production environment, it is common to drop a database in a development environment while you are experimenting with creating working table schemas. - -```sql -DROP DATABASE pet_store -``` - -## Working with Tables - -Now that you have a database you can create a table to hold the rows that represent your objects. Remember that a table is similar to declaring a Java class. When you create a table, you must specify each field and the type of the field. - -```sql -CREATE TABLE pet ( - id INT NOT NULL AUTO_INCREMENT, - name VARCHAR(255) NOT NULL, - type VARCHAR(255) NOT NULL, - PRIMARY KEY (id) -); -``` - -Notice that each field is followed by the `NOT NULL` clause. That means each of the fields must be provided for every row that is inserted. - -The `id` field is also annotated with the `AUTO_INCREMENT` keyword. This means that you don't actually provide the `id` field when you insert a row. The database will do that for you using an automatically increasing integer. - -### Altering tables - -If you need to alter your table you can use an `ALTER TABLE` statement. The following example shows you how to add a `nickname` field after the table is created. This alteration does not use the `NOT NULL` clause and so all of the existing nickname fields will be set to NULL. If a new row is added without specifying the nickname field, it will also be set to NULL. - -```sql -ALTER TABLE pet ADD COLUMN nickname VARCHAR(255); -``` - -If you decide that you want to delete a table then you execute a `DROP TABLE` statement. - -```sql -DROP TABLE pet; -``` - -Make sure you really want to drop the table before you execute the command, because there is no recovery from this one. - -It is important to note that changing and rerunning a `CREATE TABLE` statement does not change an existing table. A `CREATE TABLE` statement only creates a table. If the table already exists this command will throw an error. You can use `CREATE TABLE IF NOT EXISTS` qualifier in order to not throw an error if it already exists, but if you want to change an existing table definition you must either drop the table and recreate it, or use an `ALTER TABLE` statement. - -### Primary Keys and Indexes - -Along with specifying each field, the `CREATE TABLE` statement specifies which field is the primary key of the table. Primary keys are required to be unique. If you attempt to insert two rows with the same key, an error will occur. Primary keys are also indexed by default since it is assumed that you will use the key to query the table. - -With an index on a field, the performance of your queries will significantly increase, but you also consume storage and memory for each index you allocate. That means you should only create indexes when you can demonstrate that it is necessary for performance reasons. - -In addition to creating an index by specifying the primary key field, you can create indexes on other fields by specifying the `INDEX` keyword followed by the field you want to index. In the example below we added an index on the `name` field with the last clause in the statement. - -```sql -CREATE TABLE pet ( - id INT NOT NULL AUTO_INCREMENT, - name VARCHAR(255) NOT NULL, - type VARCHAR(255) NOT NULL, - PRIMARY KEY (id), - INDEX (name) -); -``` - -If you determine you need an index after you create a table, you can use the `CREATE INDEX` statement along with the table and field you want to index. - -```sql -CREATE INDEX index_name ON pet (name); -``` - -### Types - -Here is a list of the common SQL data types that you can use when you create a table. - -| Data type | Description | Example | -| --------- | ---------------------------------------- | --------------------------------------------------------- | -| INT | Integer numbers. | 1, 10, -100 | -| DECIMAL | Fixed-point decimal numbers. | 1.23, 100.00, -5.6789 | -| FLOAT | Single-precision floating-point numbers. | 1.23456789, 100.000000, -5.67890123 | -| DOUBLE | Double-precision floating-point numbers. | 1.234567890123456, 100.00000000000000, -5.678901234567890 | -| CHAR | Fixed-length character strings. | 'A', 'Hello, world!', '1234567890' | -| VARCHAR | Variable-length character strings. | 'A', 'Hello, world!', '1234567890' | -| TEXT | Variable-length text data. | 'This is a long text string that can be any length.' | -| BLOB | Variable-length binary data. | `Binary data of any length` | -| DATE | Date values. | '2023-10-14' | -| TIME | Time values. | '15:43:45' | -| DATETIME | Date and time values. | '2023-10-14 15:43:45' | - -## Inserting, Updating, and Deleting Data - -Now that you have a database and a table, it is time to insert some data. You can insert data into a table with an `INSERT` statement. This statement takes the name of the table, the fields you want to insert, and the values for those fields. If you created the fields with the `NOT NULL` annotation then you must supply all the non-null fields during the insertion. - -```sql -INSERT INTO pet (name, type) VALUES ('Puddles', 'cat'); -``` - -If you need to update an existing row then you use an `UPDATE` statement along with the names and values of the fields you want to update. When updating a row you want to be careful to specify which rows to update with a `WHERE` clause. If you don't specify which rows to update, then all the rows will be updated. In the example below, only the row with an `id` equal to 1 will be updated to set the pet name to `fido`. - -```sql -UPDATE pet SET name = 'fido' WHERE id = 1; -``` - -When you want to delete some rows, you use a `DELETE` statement and specify a `WHERE` clause to select the rows to delete. The following will delete all rows where the pet is a `cat`. - -```sql -DELETE FROM pet WHERE type = 'cat'; -``` - -If you want to delete **all** data from a table, then use the `TRUNCATE` statement. This will delete all of the table's data, but not the table itself. - -```sql -TRUNCATE TABLE pet; -``` - -## Selecting Data - -The `SELECT` statement provides the primary mechanism for querying data from a SQL compliant RDBMS. Here is an example of a simple SELECT that returns all the names and types for every pet. - -```sql -SELECT name, type FROM pet; -``` - -If you want to select specific pets, then you include a WHERE clause. WHERE clauses can be very complex. They can include boolean predicates, wildcards. You can also supply a `LIMIT` on the amount of data to return. Here is an example of a SELECT that returns a maximum of two rows that are either dogs with any name, or cats named Puddle. - -```sql -SELECT name, type FROM pet WHERE type='dog' OR (type='cat' AND name='Puddle') LIMIT 2; -``` - -You can select all rows in a table with the `*` query. You can also use the `COUNT` predicate to tell you how many rows there are in a table. - -```sql -SELECT * from pet; -SELECT COUNT(0) from pet; -``` - -## Joining Tables - -If you want to combine tables to compute a temporary different view of the data then you would use a `JOIN` clause along with the names of the two tables that you want to join. The following example would join together the purchase and pet tables into rows with matching pet IDs. - -```sql -SELECT purchase.id AS purchaseId, purchase.ownerId, pet.id AS petId, pet.name, pet.type - FROM purchase JOIN pet WHERE purchase.petId = pet.id; -``` - -Given the following source tables, - -**Source** - -```sql -+----+-------+---------+ -| id | petId | ownerId | -+----+-------+---------+ -| 1 | 890 | 3 | -| 2 | 891 | 3 | -| 3 | 895 | 4 | -+----+-------+---------+ - -+-----+---------+------+----------+ -| id | name | type | nickname | -+-----+---------+------+----------+ -| 890 | Puddles | cat | NULL | -| 891 | Fluffy | cat | NULL | -| 892 | Willie | cat | NULL | -| 893 | George | bird | NULL | -| 894 | Buddy | dog | NULL | -| 895 | Fido | dog | NULL | -+-----+---------+------+----------+ -``` - -this would be the result of our JOIN SELECT statement. - -**Result** - -```sql -+------------+---------+-------+---------+------+ -| purchaseId | ownerId | petId | name | type | -+------------+---------+-------+---------+------+ -| 1 | 3 | 890 | Puddles | cat | -| 2 | 3 | 891 | Fluffy | cat | -| 3 | 4 | 895 | Fido | dog | -+------------+---------+-------+---------+------+ -``` - -## Initializing Your Database - -When you are using a database to store your application data, it is often useful to make sure all of your databases and tables exist when you start up. You can do this by executing `CREATE DATABASE` and `CREATE TABLE` calls at the beginning of your application. You can conditionally create these objects with the `IF NOT EXISTS` clause. With that clause, the statement is simply ignored if the structure already exists. - -```sql -CREATE DATABASE IF NOT EXISTS petshop; -USE petshop; -CREATE TABLE IF NOT EXISTS pet ( - id INT NOT NULL AUTO_INCREMENT, - name VARCHAR(255) NOT NULL, - type VARCHAR(255) NOT NULL, - PRIMARY KEY (id) -); -``` - -By following this pattern, your application will always work even when it starts up using a database server that has not yet been initialized. This pattern is called `infrastructure as code` because it treats your configuration as code, removes the human error factor, and tracks the history of the infrastructure changes with the same version control process that your code uses. - -When we discuss the Java Database Connector (JDBC) we will demonstrate how to initialize your database from your Java code. - -You can also write a text file that contains SQL statements and execute them using the MySQL client shell (mysqlsh). For example, while you are trying to figure out what you want your final database schema to look like, you could use an initialization SQL script that deletes the database, recreates it, and creates all of the tables. - -```sql -DROP DATABASE pet_store; -CREATE DATABASE pet_store; - -USE pet_store; - -CREATE TABLE pet ( - id INT NOT NULL AUTO_INCREMENT, - name VARCHAR(255) NOT NULL, - type VARCHAR(255) NOT NULL, - PRIMARY KEY (id), - INDEX (name) -); -``` - -You could run the script with the following console command. - -```sh -➜ mysqlsh -u yourusername -pyourpassword --sql < initialize.sql -``` - -## Table of Common SQL Commands - -The follow table summaries all of the commands that were used in this instruction topic. - -| Command | Purpose | Example statement | -| --------------- | ----------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -| CREATE DATABASE | Creates a new database. | CREATE DATABASE pet_store; | -| ALTER DATABASE | Modifies the structure of a database. | ALTER DATABASE pet_store CHARACTER SET utf8mb4; | -| DROP DATABASE | Deletes a database. | DROP DATABASE pet_store; | -| USE DATABASE | Selects a database for use with future commands. | USE pet_store; | -| CREATE TABLE | Creates a new table in a database. | CREATE TABLE pet (id INT NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL, PRIMARY KEY (id)); | -| DESCRIBE TABLE | Describes the fields in a table. | DESCRIBE pet; | -| ALTER TABLE | Modifies the structure of a table. | ALTER TABLE pet ADD COLUMN nickname VARCHAR(255); | -| DROP TABLE | Deletes a table from a database. | DROP TABLE pet; | -| INSERT INTO | Inserts new data into a table. | INSERT INTO pet (name, type) VALUES ('Puddles', 'cat'); | -| SELECT | Select data from a table. | SELECT name, type FROM pet; | -| UPDATE | Updates existing data in a table. | UPDATE pet SET name = 'fido' WHERE id = 1; | -| DELETE | Deletes data from a table. | DELETE FROM pet WHERE id = 1; | -| CREATE INDEX | Creates an index on a column or columns in a table. | CREATE INDEX pet_name_index ON pet (name); | -| DROP INDEX | Deletes an index from a table. | DROP INDEX pet_name_index; | -| TRUNCATE TABLE | Deletes all rows from a table, but preserves the table structure. | TRUNCATE TABLE pet; | -| CREATE VIEW | Creates a virtual table that is based on one or more underlying tables. | CREATE VIEW cats AS SELECT \* FROM pet WHERE type = 'cat'; | -| DROP VIEW | Deletes a view. | DROP VIEW cats; | - -## Things to Understand - -- How to create and drop tables -- Why drop table if exists is useful -- How to insert, update, delete, and retrieve data from a database table -- How to retrieve data from multiple related tables using a join -- What database transactions are and why we need them - -## Videos - -- 🎥 [Structured Query Language (2:14)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=4f5a6bfe-5170-4c3c-97e8-ad660148d05a&start=0) - [[transcript]](https://github.com/user-attachments/files/17780823/CS_240_Structured_Query_Language_.SQL.pdf) -- 🎥 [SQL Data Types (3:48)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=91cb451f-fc88-426d-9656-ad660149a253&start=0) - [[transcript]](https://github.com/user-attachments/files/17737747/CS_240_SQL_Data_Types_Transcript.pdf) -- 🎥 [Creating and Dropping Tables (14:22)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=1f257807-3728-4239-a82b-b1a0011ad706&start=0) - [[transcript]](https://github.com/user-attachments/files/17737753/CS_240_Creating_and_Dropping_Tables_Transcript.pdf) -- 🎥 [Inserting, Updating, and Deleting Rows (6:40)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=203b8c65-d726-4282-8912-b1a0011f18e5&start=0) - [[transcript]](https://github.com/user-attachments/files/17737783/CS_240_Inserting_Updating_and_Deleting_Rows_Transcript.pdf) -- 🎥 [Retrieving Data with SQL Queries (11:15)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=e7083e5f-66a8-425f-be92-ad6601513cbd&start=0) - [[transcript]](https://github.com/user-attachments/files/17780824/CS_240_Retrieving_Data_with_SQL_Queries.pdf) -- 🎥 [Database Transactions (3:46)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=6e75d23e-4075-4a27-85d0-ad6601548134&start=0)- [[transcrip]](https://github.com/user-attachments/files/17780825/CS_240_Database_Transactions.pdf) - -## Demonstration code - -📁 [Book.java](example-code/Book.java) - -📁 [DatabaseAccessExample.java](example-code/DatabaseAccessExample.java) - -📁 [create-db.sql.txt](example-code/create-db.sql.txt) diff --git a/instruction/db-sql/example-code/Book.java b/instruction/db-sql/example-code/Book.java deleted file mode 100644 index e087390c..00000000 --- a/instruction/db-sql/example-code/Book.java +++ /dev/null @@ -1,89 +0,0 @@ -import java.util.Objects; - -public class Book { - private int id; - private String title; - private String author; - private String genre; - private int categoryId; - - public Book(String title, String author, String genre, int categoryId) { - this.title = title; - this.author = author; - this.genre = genre; - this.categoryId = categoryId; - } - - public Book(int id, String title, String author, String genre, int categoryId) { - this(title, author, genre, categoryId); - this.id = id; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getAuthor() { - return author; - } - - public void setAuthor(String author) { - this.author = author; - } - - public String getGenre() { - return genre; - } - - public void setGenre(String genre) { - this.genre = genre; - } - - public int getCategoryId() { - return categoryId; - } - - public void setCategoryId(int categoryId) { - this.categoryId = categoryId; - } - - @Override - public String toString() { - return "Book{" + - "id=" + id + - ", title='" + title + '\'' + - ", author='" + author + '\'' + - ", genre='" + genre + '\'' + - ", categoryId=" + categoryId + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Book book = (Book) o; - return getId() == book.getId() && - getCategoryId() == book.getCategoryId() && - Objects.equals(getTitle(), book.getTitle()) && - Objects.equals(getAuthor(), book.getAuthor()) && - Objects.equals(getGenre(), book.getGenre()); - } - - @Override - public int hashCode() { - return Objects.hash(getId(), getTitle(), getAuthor(), getGenre(), getCategoryId()); - } -} diff --git a/instruction/db-sql/example-code/DatabaseAccessExample.java b/instruction/db-sql/example-code/DatabaseAccessExample.java deleted file mode 100644 index 36ca14b9..00000000 --- a/instruction/db-sql/example-code/DatabaseAccessExample.java +++ /dev/null @@ -1,198 +0,0 @@ -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.List; - -public class DatabaseAccessExample { - /* - * Note: You will need to create a user and grant access in MySQL and then change the username and password - * below to your username and password. Use the following sql statements (replacing the username and password): - * - * CREATE USER 'jerodw'@'localhost' IDENTIFIED BY 'mypassword'; - * GRANT ALL on BookClub.* to 'jerodw'@'localhost'; - * - * Note: The grant statement assumes you named your database 'BookClub' when you created it. - * - * Note: In practice you shouldn't store your username and password in source code. A better way is to store it - * in a config file and add the config file to your .gitignore to prevent it from being checked into source - * control. Then write code to pull the username and password out of the config file to include in the - * connection String. - */ - public static final String username = "jerodw"; - public static final String password = "mypassword"; - - public static void main(String [] args) { - try { - DatabaseAccessExample example = new DatabaseAccessExample(); - List books = example.doTransaction(); - System.out.println("Final Book List:"); - example.printBooks("\t", books); - } catch (SQLException e) { - System.err.println("Unable to list books because of exception " + e.getMessage()); - } - } - - public List doTransaction() throws SQLException { - - List books; - - String connectionURL = "jdbc:mysql://localhost:3306/BookClub"; - - Connection connection = null; - try(Connection c = DriverManager.getConnection(connectionURL, username, password)) { - connection = c; - - // Start a transaction - connection.setAutoCommit(false); - - // Remove all books - removeBooks(connection); - System.out.println(); - - // Insert books - insertBooks(connection, getBooksToInsert()); - System.out.println(); - - // Retrieve books - books = getBooks(connection); - System.out.println("Retrieved the following books from the database:"); - printBooks("\t", books); - System.out.println(); - - // Change the author of the first book - Book book = books.get(0); - book.setAuthor("Jerod Wilkerson"); - updateBook(connection, books.get(0)); - System.out.println(); - - // Commit the transaction - connection.commit(); - } catch(SQLException ex) { - if(connection != null && !connection.isClosed()) { - connection.rollback(); - } - throw ex; - } - - return books; - } - - private List getBooksToInsert() { - List books = new ArrayList<>(); - - books.add(new Book("Decision Points", "George W. Bush", "NonFiction", 7)); - books.add(new Book("The Work and the Glory", "Gerald Lund", "HistoricalFiction", 3)); - books.add(new Book("Dracula", "Bram Stoker", "Fiction", 8)); - books.add(new Book("The Holy Bible", "The Lord", "NonFiction", 5)); - - return books; - } - - private void printBooks(String prefix, List books) { - for(Book book : books) { - System.out.println(prefix + book); - } - } - - private void removeBooks(Connection connection) throws SQLException { - deleteBooksRead(connection); - deleteBooks(connection); - } - - private static void deleteBooksRead(Connection connection) throws SQLException { - String sql = "delete from books_read"; - - try(PreparedStatement stmt = connection.prepareStatement(sql)) { - stmt.executeUpdate(); - } - } - - private static void deleteBooks(Connection connection) throws SQLException { - String sql = "delete from book"; - - try(PreparedStatement stmt = connection.prepareStatement(sql)) { - - int count = stmt.executeUpdate(); - - // Reset the auto-increment counter so new books start over with an id of 1 - sql = "ALTER TABLE book AUTO_INCREMENT = 1"; - try(PreparedStatement resetAutoIncrementStatement = connection.prepareStatement(sql)) { - resetAutoIncrementStatement.executeUpdate(); - } - - System.out.printf("Deleted %d books\n", count); - } - } - - private void insertBooks(Connection connection, List books) throws SQLException { - String sql = "insert into book (title, author, genre, category_id) values (?, ?, ?, ?)"; - - try(PreparedStatement stmt = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { - for(Book book : books) { - stmt.setString(1, book.getTitle()); - stmt.setString(2, book.getAuthor()); - stmt.setString(3, book.getGenre()); - stmt.setInt(4, book.getCategoryId()); - - if(stmt.executeUpdate() == 1) { - try(ResultSet generatedKeys = stmt.getGeneratedKeys()) { - generatedKeys.next(); - int id = generatedKeys.getInt(1); // ID of the inserted book - book.setId(id); - } - - System.out.println("Inserted book " + book); - } else { - System.out.println("Failed to insert book"); - } - } - } - } - - private List getBooks(Connection connection) throws SQLException { - - List books = new ArrayList<>(); - - String sql = "select id, title, author, genre, category_id from book"; - - try(PreparedStatement stmt = connection.prepareStatement(sql); - ResultSet rs = stmt.executeQuery()) { - - while(rs.next()) { - int id = rs.getInt(1); - String title = rs.getString(2); - String author = rs.getString(3); - String genre = rs.getString(4); - int categoryId = rs.getInt(5); - - books.add(new Book(id, title, author, genre, categoryId)); - } - } - - return books; - } - - private void updateBook(Connection connection, Book book) throws SQLException { - String sql = "update book " + - "set title = ?, author = ?, genre = ?, category_id = ? " + - "where id = ?"; - - try(PreparedStatement stmt = connection.prepareStatement(sql)) { - stmt.setString(1, book.getTitle()); - stmt.setString(2, book.getAuthor()); - stmt.setString(3, book.getGenre()); - stmt.setInt(4, book.getCategoryId()); - stmt.setInt(5, book.getId()); - - if(stmt.executeUpdate() == 1) { - System.out.println("Updated book " + book.getId()); - } else { - System.out.println("Failed to update book " + book.getId()); - } - } - } -} diff --git a/instruction/db-sql/example-code/create-db.sql.txt b/instruction/db-sql/example-code/create-db.sql.txt deleted file mode 100644 index 41825b27..00000000 --- a/instruction/db-sql/example-code/create-db.sql.txt +++ /dev/null @@ -1,77 +0,0 @@ -drop table if exists books_read; -drop table if exists member; -drop table if exists book; -drop table if exists genre; -drop table if exists category; - -create table member -( - id integer not null primary key auto_increment, - name varchar(255) not null, - email_address varchar(255) not null -); - - -create table genre -( - genre varchar(20) not null primary key, - description varchar(255) -); - -create table category -( - id integer not null primary key, - name varchar(255) not null, - parent_id integer, - foreign key(parent_id) references category(id) -); - -create table book -( - id integer not null primary key auto_increment, - title varchar(255) not null, - author varchar(255) not null, - genre varchar(32) not null, - category_id integer not null, - foreign key(genre) references genre(genre), - foreign key(category_id) references category(id) -); - -create table books_read -( - member_id integer not null, - book_id integer not null, - foreign key(member_id) references member(id), - foreign key(book_id) references book(id) -); - - -insert into member (name, email_address) values ('Ann', 'ann@cs.byu.edu'); -insert into member (name, email_address) values ('Bob', 'bob@cs.byu.edu'); -insert into member (name, email_address) values ('Chris', 'chris@cs.byu.edu'); - -insert into genre (genre, description) values ('NonFiction', 'Books that are not fiction.'); -insert into genre (genre, description) values ('Fiction', 'Books that are not true.'); -insert into genre (genre, description) values ('HistoricalFiction', 'Fictitious books about actual events.'); - -insert into category (id, name) values (1, 'Top'); -insert into category (id, name, parent_id) values (2, 'Must Read', 1); -insert into category (id, name, parent_id) values (3, 'Must Read (New)', 2); -insert into category (id, name, parent_id) values (4, 'Must Read (Old)', 2); -insert into category (id, name, parent_id) values (5, 'Must Read (Really Old)', 2); -insert into category (id, name, parent_id) values (6, 'Optional', 1); -insert into category (id, name, parent_id) values (7, 'Optional (New)', 3); -insert into category (id, name, parent_id) values (8, 'Optional (Old)', 3); -insert into category (id, name, parent_id) values (9, 'Optional (Really Old)', 3); - -insert into book (title, author, genre, category_id) values ('Decision Points', 'George W. Bush', 'NonFiction', 7); -insert into book (title, author, genre, category_id) values ('The Work and the Glory', 'Gerald Lund', 'HistoricalFiction', 3); -insert into book (title, author, genre, category_id) values ('Dracula', 'Bram Stoker', 'Fiction', 8); -insert into book (title, author, genre, category_id) values ('The Holy Bible', 'The Lord', 'NonFiction', 5); - -insert into books_read (member_id, book_id) values (1, 1); -insert into books_read (member_id, book_id) values (1, 2); -insert into books_read (member_id, book_id) values (2, 2); -insert into books_read (member_id, book_id) values (2, 3); -insert into books_read (member_id, book_id) values (3, 3); -insert into books_read (member_id, book_id) values (3, 4); diff --git a/instruction/db-sql/example-code/initialize.sql b/instruction/db-sql/example-code/initialize.sql deleted file mode 100644 index eb560971..00000000 --- a/instruction/db-sql/example-code/initialize.sql +++ /dev/null @@ -1,45 +0,0 @@ -DROP DATABASE pets; -CREATE DATABASE pets; - -USE pets; - -CREATE TABLE pet ( - id INT NOT NULL AUTO_INCREMENT, - name VARCHAR(255) NOT NULL, - type VARCHAR(255) NOT NULL, - PRIMARY KEY (id), - INDEX (name) -); - - -CREATE TABLE owner ( - id INT NOT NULL AUTO_INCREMENT, - name VARCHAR(255) NOT NULL, - phoneNumber VARCHAR(255), - PRIMARY KEY (id), - INDEX (name) -); - - -CREATE TABLE purchase ( - id INT NOT NULL AUTO_INCREMENT, - ownerId INT NOT NULL, - petId INT NOT NULL, - price INT NOT NULL, - PRIMARY KEY (id), - INDEX (ownerId), - INDEX (petId) -); - -INSERT INTO pet (name, type) VALUES ("Fido", "dog"); -INSERT INTO pet (name, type) VALUES ("Puddles", "cat"); -INSERT INTO pet (name, type) VALUES ("Chip", "bird"); -INSERT INTO owner (name, phoneNumber) VALUES ("Juan", "801-866-3333"); -INSERT INTO owner (name, phoneNumber) VALUES ("Pat", "619-583-9923"); -INSERT INTO owner (name, phoneNumber) VALUES ("Tessa", "217-360-3168"); -INSERT INTO purchase (ownerId, petId, price) VALUES(1, 1, 600); -INSERT INTO purchase (ownerId, petId, price) VALUES(2, 2, 20); -INSERT INTO purchase (ownerId, petId, price) VALUES(2, 3, 5); - -SELECT purchase.id, purchase.ownerId, pet.id, pet.name, pet.type FROM purchase JOIN pet WHERE purchase.petId = pet.id; - diff --git a/instruction/debugging/conditional-breakpoint-hit.png b/instruction/debugging/conditional-breakpoint-hit.png deleted file mode 100644 index 51b9594a..00000000 Binary files a/instruction/debugging/conditional-breakpoint-hit.png and /dev/null differ diff --git a/instruction/debugging/conditional-breakpoint.png b/instruction/debugging/conditional-breakpoint.png deleted file mode 100644 index 7c03955f..00000000 Binary files a/instruction/debugging/conditional-breakpoint.png and /dev/null differ diff --git a/instruction/debugging/debug-multiple-processes.gif b/instruction/debugging/debug-multiple-processes.gif deleted file mode 100644 index bc200b94..00000000 Binary files a/instruction/debugging/debug-multiple-processes.gif and /dev/null differ diff --git a/instruction/debugging/debug-stepping.gif b/instruction/debugging/debug-stepping.gif deleted file mode 100644 index 95d2dafe..00000000 Binary files a/instruction/debugging/debug-stepping.gif and /dev/null differ diff --git a/instruction/debugging/debugging.md b/instruction/debugging/debugging.md deleted file mode 100644 index c85ac65a..00000000 --- a/instruction/debugging/debugging.md +++ /dev/null @@ -1,305 +0,0 @@ -# Debugging - -🖥️ [Slides](https://docs.google.com/presentation/d/14CiV7TwmAG-vEWWsQQtaP_-Hx-pqJlGR/edit?usp=sharing&ouid=114081115660452804792&rtpof=true&sd=true) - -🖥️ [Lecture Videos](#videos) - -Debugging is one of the most important development skills that you can master. If you can learn how to rapidly reproduce a problem, narrow down its cause, and quickly implement a solution, you will dramatically increase your value as a software engineer. - -Knowing what debugging tools are available and how to effectively employ them is key to your success. Common categories of debugging tools include: - -1. Visual debuggers -1. Stack traces -1. Logs -1. Metrics -1. Customer reports -1. Development and staging environments -1. Unit, system, and end to end tests -1. Code reviews -1. Performance profilers - -The more you think about debugging as applying the scientific method, the more you will become adept at the debugging process. - -1. Concisely state the problem -1. Reproduce the problem with a unit test -1. Isolate the problem to its simplest representation -1. Step through the tested code -1. Implement a solution -1. Verify that the unit test passes -1. Verify that all tests pass - -In this instruction we focus on `visual debuggers`. You are encouraged to become experts with the debugger that is available for your development environment. In our case this is IntelliJ. Learn how to quickly execute the debugger, use it with only keystrokes, maximize the use of breakpoints, inspect variables and execution stacks, and isolate a reproduction of the problem, possibly with new unit tests. - -## Example Debugging - -To demonstrate some debugging techniques let's consider a simple example of a function that has the following specification. - -> Given a list of words, return a collection that only contains words of any length that start with a lowercase `c`, and words that are longer than five characters that start with a lowercase `a`. - -With that description, we go ahead and write our code and deploy it to production. - -```java -Collection filterToCWordsAnyLengthAndAWordsGreaterThanFive(List words) { - var result = new ArrayList(); - try { - for (var i = words.size(); i >= 0; i--) { - var word = words.get(i); - if (word.matches("^(c|a).{3,100}$")) { - result.add(word); - } - } - } catch (Exception ignore) { - } - return result; -} -``` - -Sometime later we get a report from a user that says the function doesn't return the expected result. When they pass in: - -`"cattle", "dog", "appalachian", "apple", "pig", "cat"` - -They are expecting to get back: - -`"cattle", "appalachian", "cat"` - -but instead they get back nothing. - -## Reproducing the Bug with a Test - -When you, or a customer, finds a bug, the first step is to verify the bug by creating a test that reproduces the problem. IntelliJ helps with this by providing the `Generate Test` functionality. So we right click on the function name and choose the `Generate` option followed by `Test...`. - -![Generate Test](generate-test.png) - -This will write a stub test function. - -```java -@Test -void filterToCWordsAnyLengthAndAWordsGreaterThanFive() { -} -``` - -We then fill in the test with the user's reported reproduction steps. - -```java -@Test -void filterToCWordsAnyLengthAndAWordsGreaterThanFive() { - var words = List.of("cattle", "dog", "appalachian", "apple", "pig", "cat"); - - var actual = BugExample.filterToCWordsAnyLengthAndAWordsGreaterThanFive(words); - actual = actual.stream().sorted().toList(); - - var expected = List.of("cattle", "appalachian", "cat"); - expected = expected.stream().sorted().toList(); - - assertIterableEquals(expected, actual); -} -``` - -Now we can run the test and verify that we get the same result as what the customer reported. - -``` -org.opentest4j.AssertionFailedError: iterable lengths differ, -Expected :2 -Actual :0 -``` - -## Stepping Through Code - -Sometimes it is obvious what the problem is by simply looking at the test. Other times we need to step through the code using the debugger to see what is going on. To do this we put a breakpoint in our test on the line that makes the calling to our filtering function. You can set a breakpoint by clicking on the left margin. - -![Set Breakpoint](set-breakpoint.png) - -With a breakpoint set, you can then click on the `debug` icon in the left margin associated with the function and select `Debug`. This will start up the test and execute until the breakpoint is reached. - -![Run debug](run-debug.png) - -At this point you can view the variables and confirm any assumptions that you have. This is an important step. Oftentimes a bug is created when we make assumptions about the possible variable values. If everything looks good, then we can start stepping through the code. - -### Pro Tip: Hotkeys - -An important skill to learn is the hotkeys for stepping through the code. Learning these keys will greatly increase your debugging speed. If you find yourself reaching for the mouse, take the time instead to learn the keystroke for the desired action. Each development environment is different, but here are the big ones for IntelliJ. - -| Windows | Mac | Purpose | -| -------- | ----- | ----------------- | -| Shift F9 | ⌃ D | Debug | -| F7 | F7 | Step into | -| F8 | F8 | Step over | -| F9 | ⌘ ⌥ R | Resume program | -| Alt F9 | ⌥ F9 | Run to cursor | -| Ctrl F8 | ⌘ F8 | Toggle breakpoint | - -### Example Debugging: Stepping Through Code - -As we step through the execution of our test function we will see that we are referencing a position beyond the length of our list. This is going to throw an out of bounds exception. However, we incorrectly catch and ignore the exception and so the error is hidden and it appears to the caller that we filtered out all the words and returned an empty list. - -![Debug stepping](debug-stepping.gif) - -Our first correction will be to remove the bad exception handling that is hiding our error. With this change our code now looks like this: - -```java -Collection filterToCWordsAnyLengthAndAWordsGreaterThanFive(List words) { - var result = new ArrayList(); - for (var i = words.size(); i >= 0; i--) { - var word = words.get(i); - if (word.matches("^(c|a).{3,100}$")) { - result.add(word); - } - } - return result; -} -``` - -## Error Messages - -The error messages generated while debugging often contain valuable information. Take that time to read them and digest what they are telling you. Also note that you can follow the links displayed in the stack traces to see exactly where the errors are occurring. You can then set a breakpoint on that line and rerun the test to debug what is going on. - -### Example Debugging: Error Messages - -When we run our test again, after removing the empty catch block, we see the following exception error written to the console window. - -```text -java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5 - - at java.base/java.util.ImmutableCollections$ListN.get(ImmutableCollections.java:680) - at debugging.BugExample.filterToCWordsAnyLengthAndAWordsGreaterThanFive(BugExample.java:16) - at debugging.BugExampleTest.filterToCWordsAnyLengthAndAWordsGreaterThanFive(BugExampleTest.java:15) - at java.base/java.lang.reflect.Method.invoke(Method.java:578) - at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) - at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) -``` - -This clearly describes what our problem is and points us to the line in our code that threw the exception. When we examine the line of code we see that the `for` loop incorrectly initializes with the size of the list instead of the last position in the list. - -```java -for (var i = words.size(); i >= 0; i--) { -``` - -We fix this by subtracting one from the size. - -```java -for (var i = words.size() - 1; i >= 0; i--) { -``` - -And run our test again. Now the test returns that it got an `apple` when it expected a `cat`. Since `apple` starts with `a` and is not greater than a length of five we have now reproduced another problem. - -``` -AssertionFailedError: iterable contents differ at index [1], -Expected :cat -Actual :apple -``` - -### Conditional Breakpoints - -When you create a breakpoint in IntelliJ you can specify conditions such as the required value of a variable before the breakpoint will trigger. To set a conditional breakpoint, first set a breakpoint and then right click on it to bring up the conditions dialog. - -### Example Debugging: Conditional Breakpoints - -We can use a conditional breakpoint to see what the code is doing when attempting to filter out the `apple`. The breakpoint is set by clicking on the margin next to the `word.matches` expression, and then right clicking on the breakpoint and specifying the condition: - -```java -word.equals("apple") -``` - -![Conditional Breakpoint](conditional-breakpoint.png) - -With the conditional breakpoint in place we can debug the test and it will only stop when `word` equals `apple`. - -![Conditional Breakpoint Hit](conditional-breakpoint-hit.png) - -If we step over the match call we see that `apple` does match, and it gets added to the list. That means we have a problem with our regular expression. We can take that regular expression and use a tool like [Regex101.com](https://regex101.com/) to figure out why it is matching. This leads us to realize that we need to change our regular expression to allow anything on `c` and change the starting limit from `3` to `5` for words beginning with `a`. - -```java -^(c.*|a.{5,100})$ -``` - -Now the test passes and we have improved our confidence that the code is doing what it is working correctly. - -## Examining up the Stack - -As you are debugging you might find that you need to know what happened in the functions that called the current function that you are debugging. The chain of parent function calls is referred to as the `call stack`. You can tell the debugger to move the current context up the call stack so that you can see what the variable values were. To do this open, or move to, the debugger stake pane and click on the function you wish to inspect. When you are done looking up the stack, you can click on the current function and continue debugging. - -## Debugging Example: Examining up the Stack - -When we discovered that the regular expression matching wasn't working right, we could have stepped into the JDK code for the `match` function to see how it was computing the match. If, while examining the JDK code, we wanted to look back up the stack we can open the debugger stake pane and click on any of the previous functions. In the case shown below, we can look back at the filter function and see exactly what the variables looked like before we called `match`. - -![Stack](stack.png) - -## Executing Multiple Processes - -Sometimes you need to debug/run multiple processes at the same time. For example, you might want to debug both your server and your client so that you can see how requests from the client execute on your server. With IntelliJ, you can debug multiple programs by just starting each one up individually. In the following image you can see that the server is started and a breakpoint set on the `listNames` HTTP endpoint. Then we set a breakpoint in the client and start it up. As the request flow goes from client to server, the server breakpoint is hit. Once we resume execution, the client picks up the when call to the server returns. This allows us to see exactly what is happening in each application. - -![debug multiple processes](debug-multiple-processes.gif) - -## Executing the Same Process Multiple Times - -Sometimes you need to have multiple copies of the same application running. For example, when you deploy your client chess application you will need a client application running for each of the players and observers. By default, IntelliJ only allows a single instance of an application to execute. In order to enable multiple instances to run concurrently take the following steps. - -1. Right click on the `Run` icon next to the main function of your application. -1. Choose the `Modify run configuration` option. -1. Select the `Modify options` dropdown. -1. Click on `Allow multiple instances`. -1. Save the changes. - - ![Multiple instances](multipleInstances.gif) - -Now every time you launch the application it will run an additional instance. This also means that you will need to shut each of them down when you are finished debugging them. - -## Enhancing Tests - -As you fix bugs you will often discover other problems that haven't been reported yet. You can also discover that the tests have a bug in them and the code is actually running fine. It is also possible that the test is succeeding, but not actually testing anything of value. - -When you discover any of these situations it is important that you enhance your tests to increase your confidence that the code is correct. - -Once we are confident that everything is working we need to run all of the tests to make sure we didn't break some other functionality. If that passes then we commit our changes and push them to GitHub. - -### Example Debugging: Enhancing Tests - -As we wrote our tests and debugged our code you may have noticed that the regular expression limits the `c` words to a maximum of 100 characters. While this may seem reasonable, it is contrary to requirements and so we should alter our test to ensure everything is up to specification. - -```java -@Test -void filterToCWordsAnyLengthAndAWordsGreaterThanFive() { - var big = "a"; - for (var i = 0; i < 1005; i++) { - big += 'a'; - } - - var words = List.of("cattle", "dog", "appalachian", "apple", "pig", big); - var actual = BugExample.filterToCWordsAnyLengthAndAWordsGreaterThanFive(words); - actual = actual.stream().sorted().toList(); - - var expected = List.of("cattle", "appalachian", big); - expected = expected.stream().sorted().toList(); - - assertIterableEquals(expected, actual); -} -``` - -When we run this the test fails on a new big word. - -``` -AssertionFailedError: iterable contents differ at index [0], -Expected :aaaaaaaaaaaaaaaaaaaa... -Actual :appalachian -``` - -A quick change to our regular expression corrects the problem. - -```java -"^(c.*|a.{5,})$" -``` - -## Things to Understand - -- How to set a breakpoint -- How to step through code and into method calls -- How to set conditional breakpoints -- How to view the values and local and instance values while stepping through code -- How to view the current call stack -- How to set watches - -## Videos - -- 🎥 [Introduction (6:07)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=f2279dc0-fd71-46af-ab7a-ad6d01516f20&start=0) - [[transcript]](https://github.com/user-attachments/files/17780854/CS_240_Java_Debugging_Introduction.pdf) -- 🎥 [Debugging in IntelliJ (10:17)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=6ff3df28-71f9-435e-915e-ad6d01535f13&start=0) - [[transcript]](https://github.com/user-attachments/files/17780859/CS_240_Debugging_in_InteliJ.pdf) -- 🎥 [Advanced Breakpoint Settings (11:32)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=a0c39358-184c-4290-ace7-b1aa010a61f2&start=0) - [[transcript]](https://github.com/user-attachments/files/17737928/CS_240_Advanced_Breakpoint_Settings_Transcript.pdf) diff --git a/instruction/debugging/example-code/Ball.java b/instruction/debugging/example-code/Ball.java deleted file mode 100644 index 198a652e..00000000 --- a/instruction/debugging/example-code/Ball.java +++ /dev/null @@ -1,38 +0,0 @@ -class Ball { - private final int id; - - Ball(int id) { - this.id = id; - } - - int getId() { - return id; - } - - @Override - public String toString() { - return "Ball{" + - "id=" + id + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (o == null || getClass() != o.getClass()) { - return false; - } - - Ball ball = (Ball) o; - - return id == ball.id; - } - - @Override - public int hashCode() { - return id; - } -} diff --git a/instruction/debugging/example-code/Clock.java b/instruction/debugging/example-code/Clock.java deleted file mode 100644 index fbd30fbe..00000000 --- a/instruction/debugging/example-code/Clock.java +++ /dev/null @@ -1,169 +0,0 @@ -import java.util.ArrayList; -import java.util.Deque; -import java.util.LinkedList; -import java.util.List; - -public class Clock { - private static final int MIN_BALLS = 27; - private static final int MAX_BALLS = 127; - - private static final int MINUTE_QUEUE_MAX = 4; - private static final int FIVE_MINUTE_QUEUE_MAX = 11; - private static final int HOUR_QUEUE_MAX = 11; - - private final Deque minutes = new LinkedList<>(); - private final Deque fiveMinutes = new LinkedList<>(); - private final Deque hours = new LinkedList<>(); - private List queue; - - private int twelveHourCounter = 0; - - public static void main(String [] args) { - try { - long startMillis = System.currentTimeMillis(); - Clock clock = new Clock(); - - String outputString; - switch(args.length) { - case 1: - outputString = clock.run(Integer.parseInt(args[0]), 0); - break; - case 2: - outputString = clock.run(Integer.parseInt(args[0]), Integer.parseInt(args[1])); - break; - default: - throw new IllegalArgumentException("Invalid number of arguments: " + args.length); - } - - System.out.println(outputString); - long endMillis = System.currentTimeMillis(); - System.out.println("Completed in " + (endMillis - startMillis) + " milliseconds (" + ((endMillis - startMillis) / 1000.0) + " seconds)"); - } catch (IllegalArgumentException ex) { - printUsage(ex.getMessage()); - } - } - - private static void printUsage(String message) { - System.out.println(message); - System.out.println(); - System.out.println("Usage: java Clock numbBalls "); - } - - String run(int numbBalls, int numbMinutes) { - validateParams(numbBalls, numbMinutes); - initializeQueue(numbBalls); - - if(numbMinutes > 0) { - for(int i = 0; i < numbMinutes; i++) { - tick(); - } - - return getClockState(); - } else { - do { - tick(); - } while(!clockInInitialState(numbBalls)); - - return getOutputString(numbBalls, twelveHourCounter); - } - } - - private void validateParams(int numbBalls, int numbMinutes) { - if(numbBalls < MIN_BALLS || numbBalls > MAX_BALLS) { - throw new IllegalArgumentException("Invalid number of balls (" + numbBalls + "). Must be between " + - MIN_BALLS + " and " + MAX_BALLS + "."); - } - - if(numbMinutes < 0) { - throw new IllegalArgumentException("Number of minutes may not be negative (" + numbMinutes + ")"); - } - } - - private void initializeQueue(int numbBalls) { - queue = new ArrayList<>(numbBalls); - for(int i = 0; i < numbBalls; i++) { - queue.add(new Ball(i + 1)); - } - } - - private void tick() { - Ball currentBall = queue.remove(0); - if(minutes.size() < MINUTE_QUEUE_MAX) { - minutes.add(currentBall); - } else { - dumpMinuteQueue(currentBall); - } - } - - private void dumpMinuteQueue(Ball currentBall) { - dumpQueue(minutes); - - if(fiveMinutes.size() < FIVE_MINUTE_QUEUE_MAX) { - fiveMinutes.add(currentBall); - } else { - dumpFiveMinuteQueue(currentBall); - } - } - - private void dumpQueue(Deque source) { - while(source.size() > 0) { - queue.add(source.removeLast()); - } - } - - private void dumpFiveMinuteQueue(Ball currentBall) { - dumpQueue(fiveMinutes); - - if(hours.size() < HOUR_QUEUE_MAX) { - hours.add(currentBall); - } else { - dumpHourQueue(currentBall); - } - } - - private void dumpHourQueue(Ball currentBall) { - dumpQueue(hours); - queue.add(currentBall); - twelveHourCounter++; - } - - private boolean clockInInitialState(int numbBalls) { - boolean returnValue = true; - - if(queue.size() != numbBalls) { - returnValue = false; - } else { - for(int i = 0; i < numbBalls; i++) { - if(!(queue.get(i).getId() == i + 1)) { - returnValue = false; - break; - } - } - } - - return returnValue; - } - - private String getOutputString(int numbBalls, int twelveHourCounter) { - return numbBalls + " balls cycle after " + (twelveHourCounter / 2) + " days."; - } - - private String getClockState() { - return "{\"Min\":[" + getQueueState(minutes) + "],\"FiveMin\":[" + getQueueState(fiveMinutes) + "],\"Hour\":[" + - getQueueState(hours) + "],\"Main\"[" + getQueueState(queue) + "]}"; - } - - private String getQueueState(Iterable iterable) { - StringBuilder builder = new StringBuilder(); - - for(Ball ball : iterable) { - if(builder.length() > 0) { - builder.append(','); - } - - builder.append(ball.getId()); - } - - return builder.toString(); - } -} diff --git a/instruction/debugging/example-code/ClockTest.java b/instruction/debugging/example-code/ClockTest.java deleted file mode 100644 index 9981f350..00000000 --- a/instruction/debugging/example-code/ClockTest.java +++ /dev/null @@ -1,62 +0,0 @@ -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class ClockTest { - private Clock clock; - - @Before - public void setup() { - clock = new Clock(); - } - - @Test(expected = IllegalArgumentException.class) - public void testTooFewBalls() { - clock.run(26,0); - } - - @Test(expected = IllegalArgumentException.class) - public void testTooManyBalls() { - clock.run(128,0); - } - - @Test - public void test30BallsNoMinutes() { - Assert.assertEquals(clock.run(30, 0),"30 balls cycle after 15 days."); - } - - @Test - public void test45BallsNoMinutes() { - Assert.assertEquals(clock.run(45, 0), "45 balls cycle after 378 days."); - } - - @Test - public void test123BallsNoMinutes() { - Assert.assertEquals(clock.run(123, 0), "123 balls cycle after 108855 days."); - } - - @Test - public void test27BallsOneMinute() { - Assert.assertEquals(clock.run(27, 1), "{\"Min\":[1],\"FiveMin\":[],\"Hour\":[],\"Main\"[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]}"); - } - - @Test - public void test27Balls4Minutes() { - Assert.assertEquals(clock.run(27, 4), "{\"Min\":[1,2,3,4],\"FiveMin\":[],\"Hour\":[],\"Main\"[5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27]}"); - } - - @Test - public void test27Balls5Minutes() { - Assert.assertEquals(clock.run(27, 5), "{\"Min\":[],\"FiveMin\":[5],\"Hour\":[],\"Main\"[6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,4,3,2,1]}"); - } - - @Test - public void test27Balls6Minutes() { - Assert.assertEquals(clock.run(27, 6), "{\"Min\":[6],\"FiveMin\":[5],\"Hour\":[],\"Main\"[7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,4,3,2,1]}"); - } - - @Test - public void test30Balls325Minutes() { - Assert.assertEquals(clock.run(30, 325), "{\"Min\":[],\"FiveMin\":[22,13,25,3,7],\"Hour\":[6,12,17,4,15],\"Main\"[11,5,26,18,2,30,19,8,24,10,29,20,16,21,28,1,23,14,27,9]}"); - } -} diff --git a/instruction/debugging/example-code/Readme.docx b/instruction/debugging/example-code/Readme.docx deleted file mode 100644 index 69089513..00000000 Binary files a/instruction/debugging/example-code/Readme.docx and /dev/null differ diff --git a/instruction/debugging/example-code/java/ClockTest.java b/instruction/debugging/example-code/java/ClockTest.java deleted file mode 100644 index 9981f350..00000000 --- a/instruction/debugging/example-code/java/ClockTest.java +++ /dev/null @@ -1,62 +0,0 @@ -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class ClockTest { - private Clock clock; - - @Before - public void setup() { - clock = new Clock(); - } - - @Test(expected = IllegalArgumentException.class) - public void testTooFewBalls() { - clock.run(26,0); - } - - @Test(expected = IllegalArgumentException.class) - public void testTooManyBalls() { - clock.run(128,0); - } - - @Test - public void test30BallsNoMinutes() { - Assert.assertEquals(clock.run(30, 0),"30 balls cycle after 15 days."); - } - - @Test - public void test45BallsNoMinutes() { - Assert.assertEquals(clock.run(45, 0), "45 balls cycle after 378 days."); - } - - @Test - public void test123BallsNoMinutes() { - Assert.assertEquals(clock.run(123, 0), "123 balls cycle after 108855 days."); - } - - @Test - public void test27BallsOneMinute() { - Assert.assertEquals(clock.run(27, 1), "{\"Min\":[1],\"FiveMin\":[],\"Hour\":[],\"Main\"[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]}"); - } - - @Test - public void test27Balls4Minutes() { - Assert.assertEquals(clock.run(27, 4), "{\"Min\":[1,2,3,4],\"FiveMin\":[],\"Hour\":[],\"Main\"[5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27]}"); - } - - @Test - public void test27Balls5Minutes() { - Assert.assertEquals(clock.run(27, 5), "{\"Min\":[],\"FiveMin\":[5],\"Hour\":[],\"Main\"[6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,4,3,2,1]}"); - } - - @Test - public void test27Balls6Minutes() { - Assert.assertEquals(clock.run(27, 6), "{\"Min\":[6],\"FiveMin\":[5],\"Hour\":[],\"Main\"[7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,4,3,2,1]}"); - } - - @Test - public void test30Balls325Minutes() { - Assert.assertEquals(clock.run(30, 325), "{\"Min\":[],\"FiveMin\":[22,13,25,3,7],\"Hour\":[6,12,17,4,15],\"Main\"[11,5,26,18,2,30,19,8,24,10,29,20,16,21,28,1,23,14,27,9]}"); - } -} diff --git a/instruction/debugging/example-code/main/java/Ball.java b/instruction/debugging/example-code/main/java/Ball.java deleted file mode 100644 index 198a652e..00000000 --- a/instruction/debugging/example-code/main/java/Ball.java +++ /dev/null @@ -1,38 +0,0 @@ -class Ball { - private final int id; - - Ball(int id) { - this.id = id; - } - - int getId() { - return id; - } - - @Override - public String toString() { - return "Ball{" + - "id=" + id + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (o == null || getClass() != o.getClass()) { - return false; - } - - Ball ball = (Ball) o; - - return id == ball.id; - } - - @Override - public int hashCode() { - return id; - } -} diff --git a/instruction/debugging/example-code/main/java/Clock.java b/instruction/debugging/example-code/main/java/Clock.java deleted file mode 100644 index fbd30fbe..00000000 --- a/instruction/debugging/example-code/main/java/Clock.java +++ /dev/null @@ -1,169 +0,0 @@ -import java.util.ArrayList; -import java.util.Deque; -import java.util.LinkedList; -import java.util.List; - -public class Clock { - private static final int MIN_BALLS = 27; - private static final int MAX_BALLS = 127; - - private static final int MINUTE_QUEUE_MAX = 4; - private static final int FIVE_MINUTE_QUEUE_MAX = 11; - private static final int HOUR_QUEUE_MAX = 11; - - private final Deque minutes = new LinkedList<>(); - private final Deque fiveMinutes = new LinkedList<>(); - private final Deque hours = new LinkedList<>(); - private List queue; - - private int twelveHourCounter = 0; - - public static void main(String [] args) { - try { - long startMillis = System.currentTimeMillis(); - Clock clock = new Clock(); - - String outputString; - switch(args.length) { - case 1: - outputString = clock.run(Integer.parseInt(args[0]), 0); - break; - case 2: - outputString = clock.run(Integer.parseInt(args[0]), Integer.parseInt(args[1])); - break; - default: - throw new IllegalArgumentException("Invalid number of arguments: " + args.length); - } - - System.out.println(outputString); - long endMillis = System.currentTimeMillis(); - System.out.println("Completed in " + (endMillis - startMillis) + " milliseconds (" + ((endMillis - startMillis) / 1000.0) + " seconds)"); - } catch (IllegalArgumentException ex) { - printUsage(ex.getMessage()); - } - } - - private static void printUsage(String message) { - System.out.println(message); - System.out.println(); - System.out.println("Usage: java Clock numbBalls "); - } - - String run(int numbBalls, int numbMinutes) { - validateParams(numbBalls, numbMinutes); - initializeQueue(numbBalls); - - if(numbMinutes > 0) { - for(int i = 0; i < numbMinutes; i++) { - tick(); - } - - return getClockState(); - } else { - do { - tick(); - } while(!clockInInitialState(numbBalls)); - - return getOutputString(numbBalls, twelveHourCounter); - } - } - - private void validateParams(int numbBalls, int numbMinutes) { - if(numbBalls < MIN_BALLS || numbBalls > MAX_BALLS) { - throw new IllegalArgumentException("Invalid number of balls (" + numbBalls + "). Must be between " + - MIN_BALLS + " and " + MAX_BALLS + "."); - } - - if(numbMinutes < 0) { - throw new IllegalArgumentException("Number of minutes may not be negative (" + numbMinutes + ")"); - } - } - - private void initializeQueue(int numbBalls) { - queue = new ArrayList<>(numbBalls); - for(int i = 0; i < numbBalls; i++) { - queue.add(new Ball(i + 1)); - } - } - - private void tick() { - Ball currentBall = queue.remove(0); - if(minutes.size() < MINUTE_QUEUE_MAX) { - minutes.add(currentBall); - } else { - dumpMinuteQueue(currentBall); - } - } - - private void dumpMinuteQueue(Ball currentBall) { - dumpQueue(minutes); - - if(fiveMinutes.size() < FIVE_MINUTE_QUEUE_MAX) { - fiveMinutes.add(currentBall); - } else { - dumpFiveMinuteQueue(currentBall); - } - } - - private void dumpQueue(Deque source) { - while(source.size() > 0) { - queue.add(source.removeLast()); - } - } - - private void dumpFiveMinuteQueue(Ball currentBall) { - dumpQueue(fiveMinutes); - - if(hours.size() < HOUR_QUEUE_MAX) { - hours.add(currentBall); - } else { - dumpHourQueue(currentBall); - } - } - - private void dumpHourQueue(Ball currentBall) { - dumpQueue(hours); - queue.add(currentBall); - twelveHourCounter++; - } - - private boolean clockInInitialState(int numbBalls) { - boolean returnValue = true; - - if(queue.size() != numbBalls) { - returnValue = false; - } else { - for(int i = 0; i < numbBalls; i++) { - if(!(queue.get(i).getId() == i + 1)) { - returnValue = false; - break; - } - } - } - - return returnValue; - } - - private String getOutputString(int numbBalls, int twelveHourCounter) { - return numbBalls + " balls cycle after " + (twelveHourCounter / 2) + " days."; - } - - private String getClockState() { - return "{\"Min\":[" + getQueueState(minutes) + "],\"FiveMin\":[" + getQueueState(fiveMinutes) + "],\"Hour\":[" + - getQueueState(hours) + "],\"Main\"[" + getQueueState(queue) + "]}"; - } - - private String getQueueState(Iterable iterable) { - StringBuilder builder = new StringBuilder(); - - for(Ball ball : iterable) { - if(builder.length() > 0) { - builder.append(','); - } - - builder.append(ball.getId()); - } - - return builder.toString(); - } -} diff --git a/instruction/debugging/example-code/test/java/ClockTest.java b/instruction/debugging/example-code/test/java/ClockTest.java deleted file mode 100644 index 9981f350..00000000 --- a/instruction/debugging/example-code/test/java/ClockTest.java +++ /dev/null @@ -1,62 +0,0 @@ -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -public class ClockTest { - private Clock clock; - - @Before - public void setup() { - clock = new Clock(); - } - - @Test(expected = IllegalArgumentException.class) - public void testTooFewBalls() { - clock.run(26,0); - } - - @Test(expected = IllegalArgumentException.class) - public void testTooManyBalls() { - clock.run(128,0); - } - - @Test - public void test30BallsNoMinutes() { - Assert.assertEquals(clock.run(30, 0),"30 balls cycle after 15 days."); - } - - @Test - public void test45BallsNoMinutes() { - Assert.assertEquals(clock.run(45, 0), "45 balls cycle after 378 days."); - } - - @Test - public void test123BallsNoMinutes() { - Assert.assertEquals(clock.run(123, 0), "123 balls cycle after 108855 days."); - } - - @Test - public void test27BallsOneMinute() { - Assert.assertEquals(clock.run(27, 1), "{\"Min\":[1],\"FiveMin\":[],\"Hour\":[],\"Main\"[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]}"); - } - - @Test - public void test27Balls4Minutes() { - Assert.assertEquals(clock.run(27, 4), "{\"Min\":[1,2,3,4],\"FiveMin\":[],\"Hour\":[],\"Main\"[5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27]}"); - } - - @Test - public void test27Balls5Minutes() { - Assert.assertEquals(clock.run(27, 5), "{\"Min\":[],\"FiveMin\":[5],\"Hour\":[],\"Main\"[6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,4,3,2,1]}"); - } - - @Test - public void test27Balls6Minutes() { - Assert.assertEquals(clock.run(27, 6), "{\"Min\":[6],\"FiveMin\":[5],\"Hour\":[],\"Main\"[7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,4,3,2,1]}"); - } - - @Test - public void test30Balls325Minutes() { - Assert.assertEquals(clock.run(30, 325), "{\"Min\":[],\"FiveMin\":[22,13,25,3,7],\"Hour\":[6,12,17,4,15],\"Main\"[11,5,26,18,2,30,19,8,24,10,29,20,16,21,28,1,23,14,27,9]}"); - } -} diff --git a/instruction/debugging/generate-test.png b/instruction/debugging/generate-test.png deleted file mode 100644 index 93892ae1..00000000 Binary files a/instruction/debugging/generate-test.png and /dev/null differ diff --git a/instruction/debugging/multipleInstances.gif b/instruction/debugging/multipleInstances.gif deleted file mode 100644 index 557a2a0c..00000000 Binary files a/instruction/debugging/multipleInstances.gif and /dev/null differ diff --git a/instruction/debugging/run-debug.png b/instruction/debugging/run-debug.png deleted file mode 100644 index bf9ddbc6..00000000 Binary files a/instruction/debugging/run-debug.png and /dev/null differ diff --git a/instruction/debugging/set-breakpoint.png b/instruction/debugging/set-breakpoint.png deleted file mode 100644 index 622f4b41..00000000 Binary files a/instruction/debugging/set-breakpoint.png and /dev/null differ diff --git a/instruction/debugging/stack.png b/instruction/debugging/stack.png deleted file mode 100644 index 12ca7661..00000000 Binary files a/instruction/debugging/stack.png and /dev/null differ diff --git a/instruction/defensive-programming/defensive-programming.md b/instruction/defensive-programming/defensive-programming.md deleted file mode 100644 index f92fb348..00000000 --- a/instruction/defensive-programming/defensive-programming.md +++ /dev/null @@ -1,104 +0,0 @@ -# Defensive Programming - -🖥️ [Slides](https://docs.google.com/presentation/d/1VOvCn5605TAaCC4DBZBH-B4YSDZij0UF/edit?usp=sharing&ouid=114081115660452804792&rtpof=true&sd=true) - -📖 **Required Reading**: Core Java for the Impatient - -- Chapter 5: Exceptions, Assertions, and Logging. _Only Section 2 Assertions - 2.2: Enabling and Disabling Assertions_ - -🖥️ [Lecture Videos](#videos) - -Java introduced the `assertion` keyword with version 1.4. - -## Protecting Public Access - -It is critical that you defend yourself from any input provided to your application by a user or external application. Failure to do this can allow a user to breach your application security, or cause your application to act erratically or completely fail. - -There are two types of action you generally take to ensure that user inputs are safe. - -- **Validation** - Asserting that the input meets the parameters of the request. This can include out of bounds parameters such as a negative value where only positive values are allowed, or text that is beyond the expected length of the input. -- **Sanitization** - Modifying user input in order to make it fit the parameters of the request. Sanitation assumes that request is benignly malformed and seeks to provide a satisfactory response. Type casting, defaulting to a defined value, and removing input that otherwise would be harmful are all considered sanitization. - -You must be careful to not make your application so flexible with validation and sanitization that you enlarge the attack surface of your application to the point where a malevolent user can exploit your validation with a denial of service attack, or penetrate your sanitization with an injection attack. - -Commonly, protecting public access, involves quickly executing tests that reject a user's request by throwing an exception or returning a failure error. For example, if you had a public HTTP endpoint, that required the input to be of alphabetic characters of a certain length then you would test that requirement and return a 400 error if violated. - -```java -public class DefensiveExample { - public static void main(String[] args) { - var javalin = Javalin.create() - .get("/name/{name}", DefensiveExample::getName) - .start(8080); - } - - private static void getName(Context ctx) { - ctx.contentType("application/json"); - var name = ctx.pathParam("name"); - if (!name.matches("(\\w|\\d){3,64}")) { - ctx.status(400); - ctx.result(new Gson().toJson(Map.of("error", "invalid parameter"))); - } - - ctx.result(new Gson().toJson(Map.of("result", name))); - } -} -``` - -## Protecting Internal Assumptions - -You may also protect internal objects and methods from inadvertent parameters by using the Java `assert` keyword. For example, in the following code, if the provided name is numerical, the Java runtime will throw an exception. - -```java -private String normalize(String name) { - assert !name.matches("\\d+") : "Numeric name provided"; - - return name.toUpperCase(); -} -``` - -By Java assertions described by the `assert` keyword are ignored by the runtime. You must explicitly enable them by providing the `-ea` switch when executing the `java` interpreter. - -This makes it so you use the `-ea` switch during testing and development, and then disable it when you deploy it for production so that you don't have to incur the performance overhead associated with the assertions. - -## Full Example - -Here is a full example that demonstrates the use of both exceptions and assertions. - -```java -public class DefensiveExample { - public static void main(String[] args) { - var javalin = Javalin.create() - .get("/name/{name}", DefensiveExample::getName) - .start(8080); - } - - private static void getName(Context ctx) { - ctx.contentType("application/json"); - var name = ctx.pathParam("name"); - if (!name.matches("(\\w|\\d){3,64}")) { - ctx.status(400); - ctx.result(new Gson().toJson(Map.of("error", "invalid parameter"))); - } - - name = normalize(name); - - ctx.result(new Gson().toJson(Map.of("result", name))); - } - - private static String normalize(String name) { - assert !name.matches("\\d+") : "Numeric name provided"; - - return name.toUpperCase(); - } -} -``` - -## Things to Understand - -- How and when to write assertions. -- How and when to use parameter checking instead of assertions. - -## Videos - -- 🎥 [Assertions (11:48)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=934d5be6-15b3-4213-a25b-ad6d01430c86&start=0) - [[transcript]](https://github.com/user-attachments/files/17780884/CS_240_Defensive_Programming_Assertions.pdf) -- 🎥 [Parameter Checking (2:27)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=4d06fa38-cf64-4dc2-ace5-ad6d0146799a&start=0) - [[transcript]](https://github.com/user-attachments/files/17780887/CS_240_Defensive_Programming_Parameter_Checking.pdf) diff --git a/instruction/design-principles/barbara-liskov.jpeg b/instruction/design-principles/barbara-liskov.jpeg deleted file mode 100644 index c9865d4c..00000000 Binary files a/instruction/design-principles/barbara-liskov.jpeg and /dev/null differ diff --git a/instruction/design-principles/design-principles.md b/instruction/design-principles/design-principles.md deleted file mode 100644 index 0b975ebc..00000000 --- a/instruction/design-principles/design-principles.md +++ /dev/null @@ -1,594 +0,0 @@ -# Design Principles - -🖥️ [Slides](https://docs.google.com/presentation/d/1f1X706vwJKqBRPhlB-yBF7-059--6DoF/edit#slide=id.p1) - -🖥️ [Lecture Videos](#videos) - -📖 **Required Reading**: None - -Software design is the process of defining, architecting, and creating an application. The primary goal of any application is to satisfy a customer's requirements. With a firm focus on the customer, you then apply the principles of good software design to identify the important actors, objects, and interactions necessary to represent the application's domain. This naturally leads to a code architecture that is easy to understand, debug, enhance, and maintain as requirements change. - -As you seek to design software you should focus on the following high level goals: - -1. It does what the customer wants it to do -1. It is easy to understand, debug, and maintain -1. It is extensible to requirement changes - -Using these goals we can discuss the methods that commonly lead to successful software designs. - -## Domain Driven Design - -In order to build an application that a customer wants you need to understand the domain that the customer lives in. This helps you to properly define the application in terms that the customer understands. This approach is often referred to as [Domain Driven Design](https://en.wikipedia.org/wiki/Domain-driven_design). - -As software engineers, it is tempting to focus on computer science algorithms and data structures instead of the objects and actors that a user is familiar with. With Domain Driven Design you reverse the thought process and instead think of the following: - -1. Who are the **actors** in the system? -1. What **tasks** do the actors want to accomplish? -1. What are the **objects** that the actors use? -1. What are the **interactions** between actors and objects that are necessary to complete the tasks? - -Once you have the actors, tasks, objects, and interactions defined you can then think about the data structures, devices, and protocols that will best support the domain. Basically you think about retail stores, employees, SKUs, and credit cards before you worry about hashmaps, protocols, tables, and networks. - -Be careful to consider all of your users, not just your target customers. Oftentimes internal corporate, or governmental, customers are just as important. That means you need to consider security, regulatory restrictions, data privacy, administration, reporting, and metrics as primary pieces of the domain design. - -## Persona Role Play - -Sometimes it is helpful to assign personas to your primary actors and have a role play conversation with them. Creating a persona that gives a name and backstory to an actor allows you to walk through a story with them to validate the assumptions of your design. It changes the conversation from a shallow statement like: - -> "A user buys a car" - -to something closer to the reality of the user's domain: - -> "Perry is a student from rural Utah who is short on cash. He needs to buy a car so that he can get to his part time job. He is willing to spend a lot of time finding and negotiating the best deal possible. However, he finds interacting with sales people intimidating and would prefer an automated process. He is going to need to finance his car with a cosigner on the loan." - -Being thoughtful about the background of your customer will make it easier to avoid incorrect assumptions in your design. The more real the persona becomes, the better the result will be. In the end, intentional introspection of this type will save you time because your earlier design iterations will be closer to what the customer wants. - -## Top Level Design - -Before you dig into the details of your design you want to create a couple of diagrams that capture the vision of what you are building. This is not meant to be an exhausting diagram, but it should make it so your team has a common vision of the most important pieces of the application architecture. It should represent both the high level UI pieces and the major components of the underlying application. - -The following is an example of a top level design diagram for the Chess application. - -![chess design](top-level-design.png) - -## Iterative Design - -It is important to realize that the complexity of software increases exponentially with the size of the application and the team working on it. One method for dealing with increasing complexity is to execute a series of simplified iterations. Each iteration becomes a deliverable by itself in a journey towards a larger goal. With the understanding that you are going to take an iterative approach to your design you then break each iteration into three distinct steps. First consider the design for some foundational piece of the application. For example, start with a nonfunctional client that displays hardcoded placeholders. Next, you build a minimal implementation that satisfies the design. Finally, you verify that your iteration satisfies the design by examining the test coverage, and soliciting user feedback that the implementation of the design is correct. You then repeat the process. - -![Iterative Design](iterativeDesign.png) - -Using an iterative design is important because it will break the application down into manageable pieces, incrementally introduce complexity, and allow you to correct bad design decisions early in the process. - -The size of your iteration will depend on the size of your team and the complexity of the project, but work that can be completed in one to two weeks is a common measure. Iterating for more than four weeks will often lead to wasted or inefficient efforts. - -## Abstraction - -In order to understand the world we use abstraction. When we see a person, we don't see organs and DNA. When we think of a university, we don't think about databases of scholastic records, cleaning crews, pipes, and department budgets. Likewise, when we think of a software application, we don't consider all of the layers of complexity that make the application work. We abstract away many layers of detail and instead focus on the pieces necessary to complete our current task. Without abstracting away things like the hardware, operating system, application interface, threads, user interface, rendering engine, network communication, persistent storage, and memory we would never be able to keep even the simplest of programs in our heads. - -When we create abstractions in our applications we begin by defining abstractions that represent real world objects. We call these the objects of our application domain. For example, a bank, customer, account, and loan. We then add an additional level of abstraction to represent the data structures and algorithms necessary to support the domain objects. For example, database schemas, network protocols, hash tables, and events. - -### Interfaces and Objects - -In object oriented programming `Interfaces` and `Objects` are used to provide the bulk of abstraction. - -**Objects** abstract details by differentiating between private and public methods. Public methods can be accessed by other objects. Private methods can only be accessed by the object that defines them. - -```mermaid -classDiagram - class car { - - private engine - - private driveTrain - - private suspension - + public gasPedal() - + public steeringWheel() - } -``` - -An **interface** is a public description of functionality that provides no implementation. Think of it as a description without the ability to actually do anything. The interface description hides how the actual work is done. To use an interface, an object must first implement the interfaces definition. However, you can refer to the implementing object by any interface that the object implements. This hides not only how the functionality is implement, but who is implementing it. - -```mermaid -classDiagram - class vehicle { - <> - + public gasPedal() - + public steeringWheel() - } - - class electricCar { - - electricEngine - } - - class dieselTruck { - - dieselEngine - } - - electricCar --|> vehicle - dieselTruck --|> vehicle -``` - -### Things to abstract - -Whenever you program you should try and abstract things into the following parts. - -1. What are the input interfaces -1. What are the output interfaces -1. What interface does the my abstraction need to provide -1. What class will implement the interface - -Note that sometimes it is not necessary to create an interface when a single class representation can simply expose public methods and abstract away the details. Interfaces are useful when there are multiple different algorithms that can be used to satisfy the interface, or when there are classes that implement multiple interfaces. - -The important thing to remember about abstraction is that you **hide** all implementation details of domain and system objects until those details are required. Think of everything on a purely "need to know" basis. This makes the current system easier to understand and allows for enhancement in the future. - -### Benefits of abstraction - -Some of the benefits of abstraction include: - -1. **Comprehension** - Less details makes it easier to understand how the objects interact and form a complete mental model. -1. **Extensibility** - When we are not aggressive with exposing details, we can expose those details later, or we can expose new operations that might have conflicted with previously exposed operations that were unnecessary at the time. -1. **Evolution** - Hiding how the object gets things done means that you can change the implementation without changing anything that depends on the object. -1. **Security** - Anything that is hidden by an object is less likely to be subject to attack through the object's interface. - -One common mistake with abstraction is to think that it only applies to the public methods that you include in a class. You can also provide data hiding by implementing interfaces that restrict the view of what an object can do to a small set of methods. For example, you might have a class that represents a person. In order to provide abstraction of the class, the person might represent an `Object`, `LivingEntity` and `Animal` interface. By exposing different aspects of the person, the consumer of the object only needs to know about the aspect that is of interest to them. This provides all of the benefits of comprehension, extensibility, evolution, and security. - -## Encapsulation - -Encapsulation is a form of abstraction that takes an object that provides some functionality and encapsulates, or hides it, in another object. For example, a car encapsulates an engine, drive train, and suspension. The driver of the car does not need to know any of those details because the driver never interfaces with those components. - -```mermaid -classDiagram - class car { - - private Engine - - private DriveTrain - - private Suspension - + public gasPedal() - + public steeringWheel() - } -``` - -However, the driver does need to be able to accelerate the car by pressing on the gas pedal which interfaces with the engine and drive train, but the car only exposes the gas pedal, not the engine or other encapsulated objects. - -## Inheritance - -Inheritance is another form of abstraction where one object can inherit the functionality of another object without knowing the details of how the parent object provides the functionality. - -For example, a `Car` could inherit a `WheeledVehicle` object that provides the wheels and suspension. The `wheeledVehicle` could inherit a `Vehicle` object that provides a place for passengers to sit. - -```mermaid -classDiagram - car --|> wheeledVehicle - wheeledVehicle --|> Vehicle -``` - -## Prefer Encapsulation Over Inheritance - -When you are creating your classes you need to carefully consider the different meanings and implications of using inheritance instead of encapsulation. However, by favoring encapsulation you can create composable objects that have the benefits of multiple inheritance without all of the complexity that multiple inheritance incurs. Encapsulated objects can demonstrate polymorphic behavior by exposing interfaces that are implemented by the contained objects. As long as interfaces are used to access the encapsulation, the containing class can replace the encapsulated objects without impacting any users of the objects. In short, when combined with interfaces, encapsulation can provide: - -1. `has-a` and `is-a` relationships -1. Benefits of multiple inheritance without the complexity -1. Decreased coupling -1. Better hiding of details -1. Increased interface segregation - -This suggests that in many cases Encapsulation should be preferred over inheritance. - -## Decomposition - -The basic idea of decomposition is to create abstractions that represent layers of generalization and specialization. Each layer has a specific task to do and it accomplishes it by using the layers beneath. The idea is that you start at the top with a very general representation. For example, a chess game. You then decompose, or factor out, each layer of the higher level into increasingly specialized pieces. For example, a game is made up of participants, pieces, and a board. This process continues until the smallest necessary level of decomposition is completed. Continuing our example, this could include decomposing participants into players and observers, pieces into piece types, and a board into squares. - -The advantage of decomposition is that you only need to think about the details of the layer when you are actually working on it. This includes defining its interfaces, implementing the details, and writing tests for that layer. For example, when defining the `Participant` layer, you only need to think about how a participant interacts with the `Game` and is represented by a `Player` or `Observer`. At the player level, you don't need to worry about what a `Board` is comprised of, or what the rules for moving a `King` are. - -```mermaid -classDiagram - Game *-- Board - Game *-- Piece - Game *-- Participant - - Board *-- Square - Participant <|-- Player - Participant <|-- Observer - - Piece <|-- King - Piece <|-- Rook - Piece <|-- Pawn -``` - -Programming languages themselves utilize decomposition to represent different parts of a program. When using Java we use the following decompositions: - -| Decomposition | Purpose | -| ------------- | ---------------------------------------------------------------- | -| Application | The top level that we hand to the operating system for execution | -| Jar | A zip file containing packages of classes | -| Package | A directory of classes | -| Class | A domain or system object | -| Method | An action of an object | -| Expression | Logic of a method | - -Using decomposition at the program level helps you so that you don't have to keep the whole code base on your screen at the same time. You just need to open the files that represent the current task. - -## High Cohesion and Low Coupling - -High cohesion means that an object only represents highly related data and functionality. You don't include tangentially related methods or fields in an object. Instead you create a cohesive object that executes in concert with other related objects. - -Low coupling means that objects do not strongly rely on each other. High coupling occurs when an object that cannot be used without understanding the specific implementation details of another object, or when two objects require each other to operate. Generally, low coupling means that you are using interfaces appropriately and that objects do not have bidirectional bindings. - -## Simplicity - -Simplicity is a core design principle. When given a choice between the simple and the complex always choose the simple. Dropping functionality is often preferable to introducing complexity that will make the system less usable and maintainable. - -Simplicity is such an important principle that it is easy to find quotes from every thought leader on the subject. - -> Controlling complexity is the essence of computer programming. -> -> — Brian Kernighan - -> Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away. -> -> — Antoine de Saint-Exupéry - -> Any fool can write code that a computer can understand. Good programmers write code that humans can understand. -> -> — Martin Fowler - -When complexity cannot be avoided then make it more manageable by using decomposition to break the complexity into simpler parts, or by using abstraction to hide the complexity until it can be replaced by a simpler solution. - -## Immutability - -Objects that do not change after they are constructed are referred to as immutable. In order to understand that value of immutability, consider the `String` class. If `String` was not immutable then you would never be sure you still had the same string value after a sub method was called. The following example demonstrates an unintentional side effect of calling an imaginary operation named `String.setText`. - -```java - -void printList(){ - String prefix = "- " - var items = list.of("a", "b", "c"); - for (var item : items) { - printWithPrefix(prefix, item); - } -} - -void printWithPrefix(String prefix, String text) { - prefix.setText(prefix + text); - System.out.println(prefix); -} - -// Output: -// - a -// - a- b -// - a- b- c -``` - -In reality, because `String` is immutable, you never have to worry about its value being changed and you can safely pass it to any function. - -Immutability also guarantees thread safe code because it eliminates the possibility that one thread can be modifying an object at the same time a different thread is reading it. - -## Avoiding Code Duplication - -If your code contains multiple copies of the same code then it is violating the `Do not repeat yourself`, or DRY, principle. Code duplication creates maintenance problems when you want to alter the code, increase the impact of errors, and makes it more difficult to correct the problems. It also makes the code unnecessarily complex because the reader has to read the same blocks over and over again to make sure they don't contain subtle variations. - -You can reduce duplicated code by: - -1. Using inheritance and encapsulation to represent a single version of the functionality. -1. Using utility methods for common operations. -1. Using generics to represent objects that only differ by type. - -## SOLID - -The SOLID principles of clean code were promoted by a popular software design consultant named Robert Martin (AKA Uncle Bob). - -![Uncle Bob](robert-martin.png) - -> _source: [SmarterMSP.com](https://smartermsp.com/pioneers-in-tech-barbara-liskov-and-the-clu-programming-language/)_ - -> “Truth can only be found in one place: the code.” -> -> — Robert Martin - -SOLID represent five key principles. - -1. Single Responsibility - An actor has only one reason to use you -1. Open Closed - Open for extension, closed for modification -1. Liskov Substitution - Actually implement the interface -1. Interface Segregation - Keep interfaces cohesive -1. Dependency Inversion - Make dependencies parameters - -Let's look at each of these in detail. - -### Single Responsibility Principle - -The [Single Responsibility Principle](https://en.wikipedia.org/wiki/Single-responsibility_principle) represents the desirability of high cohesion. The idea here is that an actor only has one reason to use an object. You don't have a `Person` class that represents everything associated with a person. You have a `Person` class that represents the distinct attributes of a person such as `name` and `birthDate`, and then you have other classes that represent things associated with a Person. - -```mermaid -classDiagram - Person <-- FoodConsumption : uses-a - Person <-- OutdoorActivity : uses-a - Death --* Person : has-a - Birth --* Person : has-a - class Person{ - name - birth - death - } - - class FoodConsumption { - eat(Person, Meal) - } - - class OutdoorActivity { - play(Person, Game) - } - - Date <|-- Death - Date <|-- Birth - OutdoorActivity --> Game : uses-a - - class Death { - } - - class Birth { - } -``` - -Following the single responsibility principle makes it so there is only one reason to manipulate the class. You manipulate the `Person` class to represent the person and the `Death` class to represent a death. If you find yourself making a `FrankenObject` that represents multiple objects, or responsibilities, then you should consider refactoring your code into multiple classes. - -The Java `String` class is a frequently cited example of violating the single responsibility principle as it not only represents an immutable string but provides operations for manipulating and converting the string. This makes the `String` class both a data container and a data mutator. - -Classes are not the only places where you need to consider the single responsibility principle. Methods and variables can also fall prey to confusing and conflicting responsibilities. For example, the following method has been overloaded with multiple responsibilities and interpret the parameters and return value in contradictory ways. - -If you find yourself changing a class for different reasons, functionality vs representation vs mutation vs display vs persistence, then you are probably in violation of the single responsibility principle. - -#### Violation Example - -```java -public interface FrankenPerson { - public void drive(); - public void sleep(); - public void eat(); - public void work(); - public void die(); - public void play(); - - public void setAlarm(); - public void planRoute(); - public void shopForFood(); - public void buyGymPass(); -} -``` - -```java -public interface SRPViolation { - /** - * i < 0 delete the key and the empty string if successful - * i == 0 return the old value if different - * i > 0 replace the value and return the old value - */ - public String dbAction(String key, String value, int i); -} -``` - -### Open Closed Principle - -Classes should be open to extension and closed for modification. The core concept is that you should generalize the functionality of a class so that you don't have to internally modify it in order to provide a desired extension of its functionality. - -A common example for the open closed principle involves passing in interfaces that control how the class works. This is in contrast to modifying the classes methods to provide new functionality. - -#### Violation Example - -As an example, the following code forces you to create a new method for every different type of format that you want the class to support. Additionally, the class has a constructor that represents a specific type of data. If you want to provide a different type of data, you must modify the class to include an additional constructor and internal data type. - -```java -public static class OpenForModificationList { - final private String[] items; - - public OpenForModificationList(String[] items) { - this.items = items; - } - - public String formatCommaSeparated() { - return String.join(",", items); - } - - public String formatQuotedCommaSeparated() { - var formattedItems = new ArrayList(); - for (var item : items) { - formattedItems.add(String.format("'%s'", item)); - } - - return String.join(",", formattedItems); - } -} -``` - -#### Correct Example - -We can improve the previous code by using interface parameters and Java generics to open the class to extension without ever modifying the code. - -```java -public interface Formatter { - String format(T s); -} - -public static class OpenForExtensionList { - final private List items; - - public OpenForExtensionList(List items) { - this.items = items; - } - - public String format(Formatter formatter, String separator) { - var formattedItems = new ArrayList(); - for (var item : items) { - formattedItems.add(formatter.format(item)); - } - - return String.join(separator, formattedItems); - } -} -``` - -In this example the `Formatter` interface extends how the class formats and the generic type extends the supported types. - -Dependency inversion and inheritance are both examples of the open closed principle. - -### Liskov Substitution Principle - -![Barbara Liskov](barbara-liskov.jpeg) - -> _source: [SmarterMSP.com](https://smartermsp.com/pioneers-in-tech-barbara-liskov-and-the-clu-programming-language/)_ - -> “[be] aware not just of what you understand, but also what you don’t understand” -> -> — Barbara Liskov - -If an operation is dependent on an interface, or base class, you must be able to substitute any derived class without altering the operation. This can happen if a base class throws an `UnsupportedException` for an interface or overridden method, or if the operation does a type cast on the interface. - -#### Violation Example - -```java -public class LSPExample extends Object { - public int hashCode() { - throw new UnsupportedOperationException(); - } -} -``` - -```java -void lspViolation2(List list) { - var arrayList = (ArrayList)list; -} -``` - -Violations of this principle cause unexpected behaviors within the application and require the developer to understand all of the code before they can safely make substitutions. - -### Interface Segregation Principle - -When you define an interface you only include methods that work together as a cohesive whole. You don't add methods that are related, but not necessary for the consumption of the primary usage of the interface. Put another way, the interface segregation principle states that that no consumer of an interface should be forced to depend on methods it does not use. - -Exposing methods to all consumers of the interface, without regard for the use of the methods by all the consumers, creates a significant maintenance problem. If you want to alter the interface then you must examine all uses of the interface. Instead, the preferred approach is to create multiple interfaces that an object uses and only use the interface that is appropriate to the consumer. - -#### Violation Example - -```java -public interface ReaderWriter { - byte readByte(); - String readString(); - int readInt(); - - // Outside cohesive whole. - void writeByte(byte b); - void writeString(String s); - void writeInt(int i); -} -``` - -#### Correct Example - -```java -public interface Reader { - byte readByte(); - String readString(); - int readInt(); -} - -public interface Writer { - void writeByte(byte b); - void writeString(String s); - void writeInt(int i); -} -``` - -### Dependency Inversion Principle - -The dependency inversion principle suggests that low level objects should not explicitly depend on high level objects. Instead of a low level object creating and using a high level object, you should provide the high level object to the low level object. Interfaces enable the core abstraction necessary to enable dependency inversion.At the very least you are exposing a specific implementation, constructor, and potentially extraneous methods that are unnecessary to the use of higher level object. - -Put another way, the principle says that dependencies are made on aspects of functionality, not on implementations of the functionality. In the following example, the low level `Route` object is highly coupled with the instantiation and use of the high level `Honda` object. - -#### Violation Example - -```java -class Violation { - public static void main(String[] args) { - new Route().drive(); - } - - static class Route { - void drive() { - Honda honda = new Honda(); - - honda.go(); - } - - } - - static class Honda { - void go() { - System.out.println("bruum"); - } - } -} -``` - -#### Correct Example - -In order to properly apply the dependency inversion principle you invert the use of high level object through an interface parameter. In the following example we use a factory method that uses reflection to load the desired high level object. Now the `Route` doesn't know anything about the vehicle that is being used. It just calls `go`. This breaks the coupling between the objects and moves the decision about what vehicle is actually used to be completely out of the code. - -```java -class Correct { - interface Vehicle { - void go(); - } - - public static void main(String[] args) throws Exception { - var vehicleMakerClass = args.length == 1 ? args[0] : "Honda"; - Vehicle vehicle = createVehicle(vehicleMakerClass); - new Route().drive(vehicle); - } - - static class Route { - void drive(Vehicle vehicle) { - vehicle.go(); - } - } - - static Vehicle createVehicle(String vehicleMakerClass) throws Exception { - var vehicleClass = Class.forName("Correct$" + vehicleMakerClass); - var vehicleConstructor = (Constructor) vehicleClass.getDeclaredConstructor(); - return vehicleConstructor.newInstance(); - } - - static class Honda implements Vehicle { - public void go() { - System.out.println("bruuum"); - } - } - - static class BMW implements Vehicle { - public void go() { - System.out.println("vroom"); - } - } -} -``` - -By inverting the dependencies, you can decouple the code and move the commitment to an algorithm at a higher level. Now you can execute the code with different parameters and completely modify how it works. - -## Things to Understand - -- The goals of software design -- Design is an iterative process -- Abstraction -- Single Responsibility Principle -- Decomposition -- Good algorithm and data structure selection -- Encapsulation - Information hiding -- DRY - Avoiding code duplication - -## Videos - -- 🎥 [Design Principles - Introduction (2:27)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=3e09338f-77ca-4465-bebc-b17e014a8118) - [[transcript]](https://github.com/user-attachments/files/17738057/CS_240_Design_Principles_Introduction_Transcript.pdf) -- 🎥 [Design Principles - Design Is Inherently Iterative (3:12)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=86a379ac-0a85-4843-9e3e-b17e014ba495) - [[transcript]](https://github.com/user-attachments/files/17738081/CS_240_Design_Principles_Design_is_Inherently_Iterative_Transcript.pdf) -- 🎥 [Design Principles - Abstraction (8:29)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=0fa47857-e09e-47c7-8af1-b17e014cb378) - [[transcript]](https://github.com/user-attachments/files/17738090/CS_240_Design_Principles_Abstraction_Transcript.pdf) -- 🎥 [Design Principles - Good Naming (4:24)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=93653a93-9f2a-4550-89d5-b17e01513ccc) - [[transcript]](https://github.com/user-attachments/files/17738108/CS_240_Design_Principles_Good_Naming_Transcript.pdf) -- 🎥 [Design Principles - Single Responsibility Principle (2:44)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=551b4011-c9c5-44b6-a190-b17e0152b18a) - [[transcript]](https://github.com/user-attachments/files/17738113/CS_240_Design_Principles_Single_Responsibility_Principle_Transcript.pdf) -- 🎥 [Design Principles - Decomposition (5:25)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=8ebca729-bde2-43a3-a031-b17e015394f6) - [[transcript]](https://github.com/user-attachments/files/17738129/CS_240_Design_Principles_Decomposition_Transcript.pdf) -- 🎥 [Design Principles - Good Algorithm and Data Structure Selection (2:25)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=2356c7a4-3702-49c4-8c1d-b17e0155485a) - [[transcript]](https://github.com/user-attachments/files/17738176/CS_240_Design_Principles_Good_Algorithm_and_Data_Structure_Selection_Transcript.pdf) -- 🎥 [Design Principles - Low Coupling (9:37)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=b1c2ca29-d89f-44a5-9e82-b17e01562e89) - [[transcript]](https://github.com/user-attachments/files/17738182/CS_240_Design_Principles_Low_Coupling_Transcript.pdf) -- 🎥 [Design Principles - Avoid Code Duplication (3:34)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=81229b4c-251d-4aaa-a2c6-b17e0158fe0b) - [[transcript]](https://github.com/user-attachments/files/17738191/CS_240_Design_Principles_Avoid_Code_Duplication_Transcript.pdf) diff --git a/instruction/design-principles/diagrams.uml b/instruction/design-principles/diagrams.uml deleted file mode 100644 index a3f93c91..00000000 --- a/instruction/design-principles/diagrams.uml +++ /dev/null @@ -1,71 +0,0 @@ -classDiagram - MyAbstraction <-- Input - MyAbstraction --> Output - class Input{ - getA() - getB() - } - class MyAbstraction{ - -private encapsulatedData - -private encapsulatedMethods() - process(Input):Output - } - class Output{ - setC(c) - } - - Game *-- Board - Game *-- Piece - Game *-- Participant - - Board *-- Square - Participant <|-- Player - Participant <|-- Observer - - Piece <|-- King - Piece <|-- Rook - Piece <|-- Pawn - - - Person <-- FoodConsumption : uses-a - Person <-- OutdoorActivity : uses-a - Death --* Person : has-a - Birth --* Person : has-a - class Person{ - name - birth - death - } - - class FoodConsumption { - eat(Person, Meal) - } - - class OutdoorActivity { - play(Person, Game) - } - - Date <|-- Death - Date <|-- Birth - OutdoorActivity --> Game : uses-a - - class Death { - } - - class Birth { - } - - - class FrankenPerson { - void drive() - void sleep() - void eat() - void work() - void die() - void play() - void setAlarm() - void planRoute() - void shopForFood() - void buyGymPass() - } - diff --git a/instruction/design-principles/iterativeDesign.png b/instruction/design-principles/iterativeDesign.png deleted file mode 100644 index 268e5a80..00000000 Binary files a/instruction/design-principles/iterativeDesign.png and /dev/null differ diff --git a/instruction/design-principles/robert-martin.png b/instruction/design-principles/robert-martin.png deleted file mode 100644 index 66bded62..00000000 Binary files a/instruction/design-principles/robert-martin.png and /dev/null differ diff --git a/instruction/design-principles/top-level-design.png b/instruction/design-principles/top-level-design.png deleted file mode 100644 index eb2fb76c..00000000 Binary files a/instruction/design-principles/top-level-design.png and /dev/null differ diff --git a/instruction/exceptions/example-code/ExceptionRethrowingExample.java b/instruction/exceptions/example-code/ExceptionRethrowingExample.java deleted file mode 100644 index d5006b89..00000000 --- a/instruction/exceptions/example-code/ExceptionRethrowingExample.java +++ /dev/null @@ -1,12 +0,0 @@ -public class ExceptionRethrowingExample { - - public void myMethod() { - try { - // Code that may throw different types of exceptions - } catch (RuntimeException ex) { - throw ex; - } catch (Exception ex) { - // Do something with all checked exceptions - } - } -} diff --git a/instruction/exceptions/example-code/ExceptionThrowingExample.java b/instruction/exceptions/example-code/ExceptionThrowingExample.java deleted file mode 100644 index 87af4c2c..00000000 --- a/instruction/exceptions/example-code/ExceptionThrowingExample.java +++ /dev/null @@ -1,8 +0,0 @@ -public class ExceptionThrowingExample { - - public void myMethod(int methodParam) { - if(methodParam < 0) { - throw new IllegalArgumentException("The parameter may not be negative"); - } - } -} diff --git a/instruction/exceptions/example-code/FileReadingWithExceptions.java b/instruction/exceptions/example-code/FileReadingWithExceptions.java deleted file mode 100644 index 2f3dee2c..00000000 --- a/instruction/exceptions/example-code/FileReadingWithExceptions.java +++ /dev/null @@ -1,11 +0,0 @@ -import java.io.File; -import java.io.IOException; - -public class FileReadingWithExceptions { - - public String readFile(String fileName) throws IOException { - File file = new File(fileName); - String fileContents = ""; - return fileContents; - } -} diff --git a/instruction/exceptions/example-code/FileReadingWithoutExceptions.java b/instruction/exceptions/example-code/FileReadingWithoutExceptions.java deleted file mode 100644 index 8b469794..00000000 --- a/instruction/exceptions/example-code/FileReadingWithoutExceptions.java +++ /dev/null @@ -1,24 +0,0 @@ -import java.io.File; - -public class FileReadingWithoutExceptions { - - public boolean readFile(String fileName, String fileContents) { - boolean success = true; - - File file = new File(fileName); - - if(!file.exists()) { - success = false; - } - - if(success) { - fileContents = ""; - - if(fileContents == "") { - success = false; - } - } - - return success; - } -} diff --git a/instruction/exceptions/example-code/FinallyExample.java b/instruction/exceptions/example-code/FinallyExample.java deleted file mode 100644 index 9a15a981..00000000 --- a/instruction/exceptions/example-code/FinallyExample.java +++ /dev/null @@ -1,49 +0,0 @@ -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; - -public class FinallyExample { - - public static void main(String [] args) { - FinallyExample example = new FinallyExample(); - System.out.println(example.readFile(args[0])); - } - - public String readFile(String fileName) { - File file = new File(fileName); - String fileContents = ""; - - FileReader fr = null; - BufferedReader br = null; - - try { - fr = new FileReader(file); - br = new BufferedReader(fr); - - String line; - while((line = br.readLine()) != null) { - fileContents += line; - fileContents += "\n"; - } - - return fileContents; - - } catch(IOException ex) { - ex.printStackTrace(); - return fileContents; - } finally { - if(br != null) { - try { - br.close(); - } catch (IOException e) {} - } - - if(fr != null) { - try { - fr.close(); - } catch (IOException e) {} - } - } - } -} diff --git a/instruction/exceptions/example-code/ImageEditorException.java b/instruction/exceptions/example-code/ImageEditorException.java deleted file mode 100644 index 39d04d6c..00000000 --- a/instruction/exceptions/example-code/ImageEditorException.java +++ /dev/null @@ -1,20 +0,0 @@ -public class ImageEditorException extends Exception { - public ImageEditorException() { - } - - public ImageEditorException(String message) { - super(message); - } - - public ImageEditorException(String message, Throwable cause) { - super(message, cause); - } - - public ImageEditorException(Throwable cause) { - super(cause); - } - - public ImageEditorException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } -} diff --git a/instruction/exceptions/example-code/TryCatchExample.java b/instruction/exceptions/example-code/TryCatchExample.java deleted file mode 100644 index 644f295a..00000000 --- a/instruction/exceptions/example-code/TryCatchExample.java +++ /dev/null @@ -1,34 +0,0 @@ -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; - -public class TryCatchExample { - - public static void main(String [] args) { - TryCatchExample example = new TryCatchExample(); - System.out.println(example.readFile(args[0])); - } - - public String readFile(String fileName) { - File file = new File(fileName); - String fileContents = ""; - - try { - FileReader fr = new FileReader(file); - BufferedReader br = new BufferedReader(fr); - - String line; - while((line = br.readLine()) != null) { - fileContents += line; - fileContents += "\n"; - } - - return fileContents; - - } catch(IOException ex) { - ex.printStackTrace(); - return fileContents; - } - } -} diff --git a/instruction/exceptions/example-code/TryWithResourcesExample.java b/instruction/exceptions/example-code/TryWithResourcesExample.java deleted file mode 100644 index f14da184..00000000 --- a/instruction/exceptions/example-code/TryWithResourcesExample.java +++ /dev/null @@ -1,29 +0,0 @@ -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; - -public class TryWithResourcesExample { - - public static void main(String [] args) throws IOException { - TryWithResourcesExample example = new TryWithResourcesExample(); - System.out.println(example.readFile(args[0])); - } - - public String readFile(String fileName) throws IOException { - File file = new File(fileName); - String fileContents = ""; - - try(FileReader fr = new FileReader(file); - BufferedReader br = new BufferedReader(fr)) { - - String line; - while((line = br.readLine()) != null) { - fileContents += line; - fileContents += "\n"; - } - - return fileContents; - } - } -} diff --git a/instruction/exceptions/exceptions.md b/instruction/exceptions/exceptions.md deleted file mode 100644 index 0c7b1674..00000000 --- a/instruction/exceptions/exceptions.md +++ /dev/null @@ -1,227 +0,0 @@ -# Java Exceptions - -🖥️ [Slides](https://docs.google.com/presentation/d/1CIyKxxGhJXUCQvwsJT64Oaao0p9LcBIZ/edit?usp=sharing&ouid=114081115660452804792&rtpof=true&sd=true) - -🖥️ [Lecture Videos](#videos) - -📖 **Required Reading**: Core Java for the Impatient - -- Chapter 5: Exceptions, Assertions, And Logging. (_Only read sections 5.1-5.1.9: Exception Handling_) - -Java exceptions allow you to escape out of the normal execution flow of a program when something exceptional happens. You can then centrally handle the exception at a location higher in the code execution stack. - -Java uses the standard `try`, `throw`, and `catch` syntax that are found in most programming languages. You define a block where exceptions can occur with the `try` statement. The `try` block is then followed by one or more `catch` blocks. For each `catch` block you can specify what exception type(s) the block handles. That type and any types derived from it will be caught by that block unless they also match a more specific block. The runtime will pick the block that most specifically matches your exception. If you want to handle all exceptions, then you can specify the `Exception` base class in your catch block. Keep in mind that it is often best to catch only the most specific exception type that will be thrown. - -```java -try { - // Code that might throw an exception -} catch (FileNotFoundException ex) { - // Specific file error handling -} catch (IOException ex) { - // Other IO error handling except file not found - /* FileNotFoundException is a subclass of - IOExeption, but won't trigger this block. */ -} catch (Exception ex) { - // General error handling -} - -``` - -## Throw and Throws - -You use the `throw` keyword followed by the allocation of a new exception in order to raise an exception. - -```java -throw new IllegalArgumentException("Missing required parameter"); -``` - -When you throw an exception, the normal flow of your code is interrupted and the execution pointer skips to the closest catch block in the execution stack. - -You can throw any exception from a function, but Java requires that your function signature declares all of the exceptions that the function throws. Note that the declaration requirement propagates to any function that calls a function that can throw an exception. - -```java -void top() { - try { - A(); - } catch (Exception ex) { - System.out.println("this WILL execute"); - } -} - -void A() throws Exception { - B(); - System.out.println("this will NOT execute"); -} - -void B() throws Exception { - C(); - System.out.println("this will NOT execute"); -} - -void C() throws Exception { - throw new Exception("declarations all the way up"); - System.out.println("this will NOT execute"); -} -``` - -### Unchecked Exceptions - -The exclusion to the `throws` declaration rule is when you throw what is known as an unchecked exception. Unchecked exceptions are defined as any class that is derived from the `RuntimeException` class. The reason for unchecked exceptions is that they can be thrown at anytime and so it is unreasonable to explicitly handle them on every function in your code. These should be caught or thrown only very rarely, as they usually indicate a bug in your code (such as a `NullPointerException`, which is unchecked) rather than a problem that can occur during execution of your program (such as a `FileNotFoundException`, which is checked). - -## Finally - -You can also use the `try` syntax to create a block of code that always gets executed whenever the try block exits. This is called a finally block. The finally block is executed whether or not an exception is throw. If an exception is thrown, but there is no catch block, the finally method will get called, but then the exception continues up the call stack until a catch block is discovered. - -```java -try { - // Code that may throw an exception -} finally { - // Code that always gets called -} -``` - -## Example - -Consider the example of a program that requires a configuration file in order to work correctly. If the file does not exist, then you want report the error from your `main` function and not deep down in the initialization code where the file fails to load. - -Note the use of multiple `catch` blocks, the use of `finally`, and also the necessity of declaring the exceptions that may be thrown. - -```java -import java.io.File; -import java.io.FileNotFoundException; - -public class ExceptionExample { - public static void main(String[] args) { - // Exceptions are handled centrally for anything that happens in this scope. - try { - var example = new ExceptionExample(); - example.loadConfig(); - } catch (FileNotFoundException ex) { - System.out.printf("Required file not found: %s", ex); - } catch (Exception ex) { - System.out.printf("General error: %s", ex); - } finally { - System.out.println("Program completed"); - } - } - - private void loadConfig() throws Exception { - loadConfigFile("user"); - loadConfigFile("system"); - } - - // Note that the function indicates that it can throw an exception. - private void loadConfigFile(String location) throws FileNotFoundException { - var file = new File(location); - if (!file.exists()) { - // Let the code above know there was an exception. - throw new FileNotFoundException(); - } - - // Otherwise load the configuration - } -} -``` - -## Custom Exception Types - -Java has many useful Exception types you can `throw`, but often you won't find one that matches what you need. You can create your own exception types by creating subclasses of the `Exception` class (or of any other exception type). Feel free to add fields to your exception classes to contain any information that might be useful about what went wrong. If you find yourself catching an exception and then checking the message string to see what kind of error it is, you may want to replace it with a custom exception type instead. - -Here is an example of a custom exception type: -```java -public class AlreadyTakenException extends Exception { - public AlreadyTakenException(String message) { - super(message) - } -} -``` - -## Try-With-Resources - -Not closing resources, such as file handles or database connections, can lead to leaks that will cause your application to fail. The following example shows the allocation of an input stream that closes the stream after it is used. However, if an exception is thrown during the read operation the stream is not closed and the file handle is leaked. That means the resources associated with the file are never released and eventually that application will not be able to open files. - -```java -public void NoTry() throws IOException { - FileInputStream input = new FileInputStream("test.txt"); - System.out.println(input.read()); - - // If an exception is thrown this will not close the stream - input.close(); -} -``` - -To work around this, it is common to use the `try/finally` syntax to clean up resources that need to be closed. In the example below the stream will be closed whether or not an exception is thrown. - -```java -public void TryWithFinally() throws IOException { - FileInputStream input = null; - try { - input = new FileInputStream("test.txt"); - System.out.println(input.read()); - } finally { - if (input != null) { - // If an exception is thrown this will not close the stream - input.close(); - } - } -} -``` - -As you can see by the previous example, resource cleanup introduces a lot of boilerplate code. To make this common and necessary activity easier to implement, Java introduced the `try-with-resources` syntax. You can use this syntax with any class that implements the [closable](https://docs.oracle.com/javase/8/docs/api/java/io/Closeable.html) interface. This includes things like input and output streams, readers and writers, network connections, files, and channels. - -To use this syntax you place the allocation of the object as a parameter to the `try` keyword. The Java complier will automatically generate the finally block and call close for you. - -```java -public void tryWithResources() throws IOException { - // Close is automatically called at the end of the try block - try (FileInputStream input = new FileInputStream("test.txt")) { - System.out.println(input.read()); - } -} -``` - -## Where to Use `catch` and `throws` - -A significant part of exception handling is deciding where to handle exceptions. When an exception is thrown, at each level of the execution stack, you can either `catch` the error or use `throws` to pass it to the next level up. Consider what needs to happen when the exception is thrown. For example, do I want my program to halt? Does a message need to be sent back to the user? Which part of my program can do that? - -A good rule of thumb is to ask: after I'm done handling this exception, where can I resume normal execution? For example, a login screen might have a UI layer, which calls a login service layer, which calls a database layer. If someone tries to login with an incorrect username, the database throws an error: user not found. The login service layer can't continue its normal execution, so it `throws` the error to the UI layer. However, the UI layer knows how to display an "invalid username" message, so it can `catch` the exception and resume. - -Sometimes a layer cannot handle an exception, but does have additional information about what went wrong. Then you can catch the exception and simply throw another exception, possibly of a different type, that contains that information. For example, the database layer from the previous example might throw a ValueNotFoundException, but the login service layer knows it's really an InvalidCredentialsException, so it catches and re-throws a more useful exception type. - -## Exceptions Should be Exceptional - -Remember that exceptions should be exceptional. Do not throw exceptions for things that happen in the normal flow of your code. For example, if it is expected that sometimes a file may not be found, then that is not exceptional. Also do not throw exceptions to return values from a function. For example, a token parser should not throw exceptions in order to return tokens that it parses to anyone with a catch block. - -Using exceptions for non-exceptional cases makes debugging much more difficult and creates unexpected side effects in your code that make it less maintainable. - -## Things to Understand - -- The difference between checked and unchecked exceptions in Java -- How and when to handle an exception in Java -- How and when to throw an exception in Java -- How to create custom exception classes -- How to use try/catch blocks -- What finally blocks are and how to use them - -## Videos - -- 🎥 [Exceptions (35:32)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=83d5acf8-12b7-473d-919d-ad6b0124631b&start=0) - [[transcript]](https://github.com/user-attachments/files/17780908/CS_240_Exceptions_Exceptions_in_Java.pdf) -- 🎥 [Checked vs. Unchecked Exceptions (4:35)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=3e7b6f62-13e5-41e6-9a81-ad6b012e8b25&start=0) - [[transcript]](https://github.com/user-attachments/files/17780909/CS_240_Exceptions_Checked_vs_Unchecked_Exceptions.pdf) - -## Demonstration code - -📁 [ExceptionRethrowingExample](example-code/ExceptionRethrowingExample.java) - -📁 [ExceptionThrowingExample](example-code/ExceptionThrowingExample.java) - -📁 [FileReadingWithExceptions](example-code/FileReadingWithExceptions.java) - -📁 [FileReadingWithoutExceptions](example-code/FileReadingWithoutExceptions.java) - -📁 [FinallyExample](example-code/FinallyExample.java) - -📁 [ImageEditorException](example-code/ImageEditorException.java) - -📁 [TryCatchExample](example-code/TryCatchExample.java) - -📁 [TryWithResourcesExample](example-code/TryWithResourcesExample.java) diff --git a/instruction/final-exam-review/final-exam-review.md b/instruction/final-exam-review/final-exam-review.md deleted file mode 100644 index 69b6af2d..00000000 --- a/instruction/final-exam-review/final-exam-review.md +++ /dev/null @@ -1,17 +0,0 @@ -# Final Exam Review - -🖥️ [Lecture Videos](#videos) - -This exam covers the topics not included in your Chess project work. This includes the following concepts: - -- [Command-Line Builds](../command-line-builds/command-line-builds.md) -- [Computer Security](../computer-security/computer-security.md) -- [Concurrency](../concurrency/concurrency.md) - -The format is multiple choice, multiple answer, and true/false. No external documents, references, persons, or sources of any kind may be referenced during the exam. The exam is proctored using [Honorlock](https://honorlock.com/). - -For in-person students, it is strongly recommended that you attend the in-class final exam review. For online students, you should watch the final exam review video and take and study the Kahoot that your instructor will make avilable to you. - -## Videos - -- 🎥 [Final Exam Review (3:40)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=d35c30fd-b1c6-47dc-ad31-b1aa0126a444&start=0) - [[transcript]](https://github.com/user-attachments/files/17738250/CS_240_Final_Exam_Review_Transcript.pdf) diff --git a/instruction/generics/example-code/KeyValuePair.java b/instruction/generics/example-code/KeyValuePair.java deleted file mode 100644 index c8f17e2a..00000000 --- a/instruction/generics/example-code/KeyValuePair.java +++ /dev/null @@ -1,5 +0,0 @@ -public class KeyValuePair extends Pair { - public KeyValuePair(String value1, V value2) { - super(value1, value2); - } -} diff --git a/instruction/generics/example-code/Pair.java b/instruction/generics/example-code/Pair.java deleted file mode 100644 index 068833e5..00000000 --- a/instruction/generics/example-code/Pair.java +++ /dev/null @@ -1,25 +0,0 @@ -public class Pair { - private T value1; - private U value2; - - public Pair(T value1, U value2) { - this.value1 = value1; - this.value2 = value2; - } - - public T getValue1() { - return value1; - } - - public void setValue1(T value1) { - this.value1 = value1; - } - - public U getValue2() { - return value2; - } - - public void setValue2(U value2) { - this.value2 = value2; - } -} diff --git a/instruction/generics/example-code/PairUser.java b/instruction/generics/example-code/PairUser.java deleted file mode 100644 index 22828e45..00000000 --- a/instruction/generics/example-code/PairUser.java +++ /dev/null @@ -1,11 +0,0 @@ -import java.util.Date; - -public class PairUser { - public static void main(String[] args) { - Pair pair1 = new Pair("Hello", 123); - Pair pair2 = new Pair<>("Hello", 123); - var pair3 = new Pair("Hello", 123); - StringPair pair4 = new StringPair("Hello", "BYU"); - KeyValuePair pair5 = new KeyValuePair<>("Hello", new Date()); - } -} \ No newline at end of file diff --git a/instruction/generics/example-code/StringPair.java b/instruction/generics/example-code/StringPair.java deleted file mode 100644 index 008d22ae..00000000 --- a/instruction/generics/example-code/StringPair.java +++ /dev/null @@ -1,5 +0,0 @@ -public class StringPair extends Pair { - public StringPair(String value1, String value2) { - super(value1, value2); - } -} diff --git a/instruction/generics/example-code/interfaceExample/Capitalizer.java b/instruction/generics/example-code/interfaceExample/Capitalizer.java deleted file mode 100644 index f74c2d52..00000000 --- a/instruction/generics/example-code/interfaceExample/Capitalizer.java +++ /dev/null @@ -1,8 +0,0 @@ -package interfaceExample; - -public class Capitalizer implements Function { - @Override - public String apply(String param) { - return param == null ? null : param.toUpperCase(); - } -} diff --git a/instruction/generics/example-code/interfaceExample/Function.java b/instruction/generics/example-code/interfaceExample/Function.java deleted file mode 100644 index 0f5f4d38..00000000 --- a/instruction/generics/example-code/interfaceExample/Function.java +++ /dev/null @@ -1,5 +0,0 @@ -package interfaceExample; - -public interface Function { - R apply(T param); -} diff --git a/instruction/generics/example-code/interfaceExample/SpaceRemover.java b/instruction/generics/example-code/interfaceExample/SpaceRemover.java deleted file mode 100644 index 2aff9bb2..00000000 --- a/instruction/generics/example-code/interfaceExample/SpaceRemover.java +++ /dev/null @@ -1,8 +0,0 @@ -package interfaceExample; - -public class SpaceRemover implements Function { - @Override - public String apply(String param) { - return param == null ? null : param.replaceAll(" ", ""); - } -} diff --git a/instruction/generics/example-code/interfaceExample/StringManipulator.java b/instruction/generics/example-code/interfaceExample/StringManipulator.java deleted file mode 100644 index bc766548..00000000 --- a/instruction/generics/example-code/interfaceExample/StringManipulator.java +++ /dev/null @@ -1,13 +0,0 @@ -package interfaceExample; - -public class StringManipulator { - public static void main(String[] args) { - StringManipulator manipulator = new StringManipulator(); - System.out.println(manipulator.manipulateString("my string", new Capitalizer())); - System.out.println(manipulator.manipulateString("my string with spaces that will be removed", new SpaceRemover())); - } - - public String manipulateString(String str, Function manipulationFunction) { - return manipulationFunction.apply(str); - } -} diff --git a/instruction/generics/generics.md b/instruction/generics/generics.md deleted file mode 100644 index 0883f61e..00000000 --- a/instruction/generics/generics.md +++ /dev/null @@ -1,81 +0,0 @@ -# Java Generics - -🖥️ [Slides](https://docs.google.com/presentation/d/1a3aELn5tIIfY-g4-wOQ1vackTD4RacDn/edit?usp=sharing&ouid=114081115660452804792&rtpof=true&sd=true) - -📖 **Required Reading**: Core Java for the Impatient - -- Chapter 6: Generic Programming. _Only_ Sections 6.1-6.4 - -🖥️ [Lecture Videos](#videos) - -`Generic Programming` is a common programming language technique that is useful for strongly typed languages such as C++, C#, or Java. You can use generic programming to reuse class or function code that only differs by the type of variables they operate on. - -For example, consider the standard JDK object `ArrayList`. The `` part of the class name refers to the `type parameter` for the class. When you create an object based on this class you specify what type you want the generic to use. This means you can create an `ArrayList` that only contains `String` objects or one that only contains `Integer` objects. - -```java -var intList = new ArrayList(); -var stringList = new ArrayList(); - -intList.add(3); -stringList.add("cow"); - -Integer integerItem = intList.get(0); -String stringItem = stringList.get(0); - -``` - -If you attempt to put an integer into the stringList you will get a compile time error, and vice-versa. Also, because the compiler knows what its type parameter is bound to for the generic class, you don't need to do the type conversion. - -Before generics were introduced to Java you had to either create a different class implementation for each type you wanted to support, or you had to use an `Object` to represent the type of the class and then typecast the `Object` before you could use it. Consider the following use of the non-generic `ArrayList` class. - -```java -var list = new ArrayList(); -list.add(3); -list.add("cow"); - -Integer integerItem = (Integer) list.get(0); -String stringItem = (String) list.get(0); // Exception thrown at runtime -``` - -Not only does this code force the overhead of type casting, it is also dangerous because your list can contain any type of object, and unless you use reflection, you have to guess how to type cast the object. If you guess wrong you will throw a runtime exception. - -## Writing Your Own Generic Classes - -You can also write your own generic classes by using the syntax that creates placeholders for the generic type. The following example creates a generic storage object that can be initialized to contain any specific type. - -The example simply wraps an `ArrayList`, but it could be altered to read and write data to a database that supports different types. - -```java -class Storage { - List items = new ArrayList<>(); - - void add(T item) { - items.add(item); - } - - T get(int i) { - return items.get(i); - } -} - -var intStorage = new Storage(); -var stringStorage = new Storage(); -``` - -## Videos - -- 🎥 [Generic Types Overview (4:00)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=15993248-1fa0-47fa-ba6f-b0530109e081) - [transcript](https://github.com/user-attachments/files/18543997/CS_240_Generic_Types_Overview_Transcript.pdf) -- 🎥 [Using Generic Classes (6:49)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=ced1be5e-61a3-4dfd-b03f-b053010b6950) - [transcript](https://github.com/user-attachments/files/18544002/CS_240_Using_Generic_Classes_Transcript.pdf) -- 🎥 [Generic Type Wildcards (1:59)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=32ad9f28-5028-44d0-8bb2-b053010d7bc9) - [transcript](https://github.com/user-attachments/files/18544003/CS_240_Generic_Types_Wildcards_Transcript.pdf) - -## Demonstration code - -📁 [KeyValuePair.java](example-code/KeyValuePair.java) - -📁 [Pair.java](example-code/Pair.java) - -📁 [PairUser.java](example-code/PairUser.java) - -📁 [StringPair.java](example-code/StringPair.java) - -📁 [interfaceExample](example-code/interfaceExample) diff --git a/instruction/git/Branching.gif b/instruction/git/Branching.gif deleted file mode 100644 index eb04d6b0..00000000 Binary files a/instruction/git/Branching.gif and /dev/null differ diff --git a/instruction/git/GitCommitWorkflow.png b/instruction/git/GitCommitWorkflow.png deleted file mode 100644 index 8bf3b536..00000000 Binary files a/instruction/git/GitCommitWorkflow.png and /dev/null differ diff --git a/instruction/git/GitHubClone.jpg b/instruction/git/GitHubClone.jpg deleted file mode 100644 index 794bc10e..00000000 Binary files a/instruction/git/GitHubClone.jpg and /dev/null differ diff --git a/instruction/git/GitHubCreateRepo.jpg b/instruction/git/GitHubCreateRepo.jpg deleted file mode 100644 index e30d5276..00000000 Binary files a/instruction/git/GitHubCreateRepo.jpg and /dev/null differ diff --git a/instruction/git/GitIcon.png b/instruction/git/GitIcon.png deleted file mode 100644 index a935dc2a..00000000 Binary files a/instruction/git/GitIcon.png and /dev/null differ diff --git a/instruction/git/GitIntelliJ.gif b/instruction/git/GitIntelliJ.gif deleted file mode 100644 index c9e12807..00000000 Binary files a/instruction/git/GitIntelliJ.gif and /dev/null differ diff --git a/instruction/git/GitStage.jpg b/instruction/git/GitStage.jpg deleted file mode 100644 index bc8369c7..00000000 Binary files a/instruction/git/GitStage.jpg and /dev/null differ diff --git a/instruction/git/GitUrlButton.jpg b/instruction/git/GitUrlButton.jpg deleted file mode 100644 index ed8ef43b..00000000 Binary files a/instruction/git/GitUrlButton.jpg and /dev/null differ diff --git a/instruction/git/git.md b/instruction/git/git.md deleted file mode 100644 index b777376e..00000000 --- a/instruction/git/git.md +++ /dev/null @@ -1,319 +0,0 @@ -# Git - -![Git Icon](GitIcon.png) - -🖥️ [Slides](https://docs.google.com/presentation/d/1y4u5y9uNiekYcubilyhYLjUGVoYBqs4q/edit?usp=sharing&ouid=114081115660452804792&rtpof=true&sd=true) - -🖥️ [Lecture Videos](#videos) - -📖 **Required reading**: - -- [GitHub create a repo](https://docs.github.com/en/get-started/quickstart/create-a-repo) -- [GitHub cloning a repo](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) -- [GitHub personal access tokens](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) - -[Linus Torvalds](https://en.wikipedia.org/wiki/Linus_Torvalds), the creator of Linux, was fed up with the proprietary version control software that he was using to track the code for the Linux kernel and so over a weekend he built Git, the world's most popular version control system. - -![Linus Torvalds](linusTorvalds.jpg) - -> _Source: Wikipedia_ - -> “Talk is cheap. Show me the code.” -> -> — Linus Torvalds - -## Overview - -Git is the industry standard **Version Control System** that powerfully manages the changes made to hundreds of files over the entire lifetime of a project. Git makes it easy to view, undo, redo, branch, and merge with collaborators in a trustable, secure way. - -Git provides two valuable functions. First, it allows you to track versions of files in a directory. Second, it allows you to clone all of those versions to a different location, usually to a different computer. We are going to focus on tracking versions in this instruction and cover cloning repositories when we talk later about GitHub. - -The general Git development workflow is illustrated in the following diagram. - -![Commit workflow](GitCommitWorkflow.png) - -To give a reference on the typically frequency of each of the stages, developers typically: - -- **Change** files all day long -- **Stage** and **commit** changes multiple times per hour -- **Review** commits and **push** about hourly - -## Installing Git - -Before we can talk about Git you need to make sure it is installed in your development environment. Open a console and type `git --version`. - -```sh -➜ git --version -git version 2.32.0 (Apple Git-132) -``` - -If you do not see something like that, then you need to follow these [instructions](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) to install Git. - -## Getting Started with Git - -You can track file versions of any files in a directory by initializing Git for that directory. You can do this right now by creating a new directory in a console window and initializing it as a Git repository. - -```sh -➜ mkdir playingWithGit -➜ cd playingWithGit -➜ git init -``` - -If you list all files in the directory you will see that you now have a hidden directory named `.git`. - -```sh -➜ ls -la -total 0 -drwxr-xr-x 3 lee staff 96 Dec 1 22:59 . -drwxr-xr-x+ 54 lee staff 1728 Dec 1 23:00 .. -drwxr-xr-x 9 lee staff 288 Dec 1 22:59 .git -``` - -The `.git` directory is where all of the versions get stored. Now use the `echo` command to create a file so that we can see how versioning works. After creating the new file, use `git status` to tell you what git is doing. - -```sh -➜ echo hello world > hello.txt -➜ git status - -On branch master -No commits yet -Untracked files: - (use "git add ..." to include in what will be committed) - hello.txt - -nothing added to commit but untracked files present (use "git add" to track) -``` - -Git status tells you that it detects a new file named `hello.txt`, but it isn't currently tracking versions for that file. To begin tracking versions you need to add it. Usually you track all files in a repository directory and so you can tell Git to track everything that it doesn't know about with `git add .`. Follow this with another call to `git status`. - -```sh -➜ git add . -➜ git status - -On branch master -No commits yet -Changes to be committed: - (use "git rm --cached ..." to unstage) - new file: hello.txt -``` - -Now Git tells us that it has `staged` the file `hello.txt` and it is ready to be committed as a version in the repository. We commit a version with the `commit` command. We always want to have a meaningful comment about the version we are committing and so we use the `-m` parameter to provide a message that will live with the version. Follow this with another call to `git status`. - -```sh -➜ git commit -m "initial draft" -[master (root-commit) d43b07b] initial draft - 1 file changed, 1 insertion(+) - create mode 100644 hello.txt - -➜ git status -On branch master -nothing to commit, working tree clean -``` - -Congratulations! You have just committed your first file to a Git repository. It is important to note that we were only working with a single file in this example. However, a commit can represent multiple files. You just need to add them all before you execute the commit. Also, note that the point of the stage (add) step, is so that you can commit some files while still leaving other modified file out of the commit. - -Let's make an edit to our file and commit it again. This time we will tell Git that we want to add all the tracked modified files to our commit by including the `-a` parameter along with our message parameter. - -```sh -➜ echo goodbye world > hello.txt - -➜ git commit -am "changed greeting to reflect the present mood" - -[master e65f983] changed greeting to reflect the present mood - 1 file changed, 1 insertion(+), 1 deletion(-) -``` - -Now that we have a couple versions in our repository we can view the versions with the `git log` command. - -```sh -➜ git log - -commit e65f9833ca8ee366d0d9c1676a91b1a977dab441 (HEAD -> master) -Author: Lee -Date: Thu Dec 1 23:32:22 2022 -0700 - - changed greeting to reflect the present mood - -commit d43b07b8890f52defb31507211ba78785bf6dccf -Author: Lee -Date: Thu Dec 1 23:29:11 2022 -0700 - - initial draft -``` - -This shows both commits with the associated comments. - -## Commit SHA - -Every commit has a unique identifier that is generated by hashing the file along with the timestamp using the SHA hashing algorithm. You can always refer to a specific commit in your version history by using its SHA. For example, if we want to temporarily switch back to a previous version to see what it contains we can use the `checkout` command. You only need to provide the first few characters of the SHA. - -```sh -➜ git checkout d43b07b8890f - -Note: switching to 'd43b07b8890f'. -HEAD is now at d43b07b initial draft - -➜ cat hello.txt -hello world -``` - -The above output omits a big message saying that you are no longer looking at the latest version, but the important thing is that you can see that we are now looking at our old version. To get back to the top of the version chain, use the `checkout` command and reference the branch name, which is by default `master`. - -```sh -➜ git checkout master -Previous HEAD position was d43b07b initial draft -Switched to branch 'master' - -➜ cat hello.txt -goodbye world -``` - -Now we are back to our latest version. - -The following diagram shows how your commits move from your working directory, to staging them for a commit, and then committing them to a repository. - -![Git stage](GitStage.jpg) - -A commit is a full snapshot of what was staged from your directory at the time of the commit. That means all of the files contained in the commit were reverted when you executed the checkout command. Since we only had one file in our commit, it looks like we are only flipping that file around, but basically you can think of it as a time machine for the entire directory. - -## Diff - -Most of the time you don't want to reverse back to an earlier commit. Instead you just want to compare the differences between commits. We can do that with the `diff` command. You can specify two SHAs that you would like to compare, or you can use the HEAD variable which points to the top of the commit change. To refer to earlier commits you just add `~` and the numerical distance from head that you want to reference. In this case we will compare HEAD and HEAD~1. - -```sh -➜ git diff HEAD HEAD~1 -``` - -```diff -diff --git a/hello.txt b/hello.txt -index 3b18e51..eeee2af 100644 ---- a/hello.txt -+++ b/hello.txt -@@ -1 +1 @@ --hello world -+goodbye world -``` - -You can see that we made a change to `hello.txt` by removing `hello world` and adding `goodbye world`. - -## Branches - -Git supports the ability to branch your code. This allows you to work on variations of the code while still allowing progress on the main branch. For example, if you wanted to work on a new feature named `A` without interrupting work on the master branch, you would use the `git branch A` command and start working on the `A` branch with the `git checkout A` command. Now commits can be done to both the master and the `A` branch. When you want to combine the work done on both branches you us checkout the master branch and execute `git merge A`. If you decide you want to abandon the new feature then you just don't ever merge it back into the master branch. - -Here is a demonstration of this working on the visualization tool provided by [git-school.github.io](https://git-school.github.io/visualizing-git/). - -![Branches](Branching.gif) - -## Commit often - -You will be required to commit frequently and consistently as you work on each phase of the chess project in order to get credit for the assignment. Commonly, this will be an initial commit that contains the set up for the phase, followed by commits at each working piece (test case, endpoint, sql query), and then a final commit for the working phase. Committing your code often is an important practice for you to develop. This protects you from losing your work, allows access from anywhere, makes it so you can quickly share changes, reduces conflicts with your peers, and enables you to efficiently explore different possibilities. This also enables others to review the progression of your development efforts in order to prove the originality of your work. - -Remember to make meaningful commit messages that describe the **what** and **why** of the changes made. Here is a [good post](https://www.freecodecamp.org/news/how-to-write-better-git-commit-messages/) on how make meaningful commit messages. - -## Binary files - -You can store any type of file in Git, but be aware that if you store large binary files, such as images or videos, you are storing a copy of that file each time you make a change to it. For example, suppose you use Git to track the changes you make to a video production project. Every time you save a change to your 10 GB video file you store a complete copy of the file. That means 10 commits of the video file will store 100 GB of data in your repository. - -## GitHub - -When we introduced `Git`, we said that Git provides two things, 1) Version tracking in a repository, and 2) the ability to clone a copy of the repository to a different location. You can clone repositories between computers used by your development team, but the management of cloning repositories is much easier when you use a cloud based service such as `GitHub`. - -GitHub was launched in 2008 by a small group of developers that wanted to make code collaboration easy. GitHub was acquired by Microsoft in 2018 for $7.5 billion. Since its beginning as a simple web application for cloning and storing Git repositories, GitHub has added functionality for hosting websites, supporting community pull requests, tracking issues, hosting codespaces, running continuous deployment processes, managing projects, and even AI driven code generation. - -### Creating and cloning a repository - -While you can create a repository in your development environment using `git init` and then connect it to an upstream repository on GitHub, it is **always** easier to create your repository first on GitHub and then clone it to your development environment. That way your repositories are automatically linked to each other. - -To create a repository in GitHub, log into your account, select the `Repositories` tab, and press `New repository`. You then specify a unique repository name, give a description, indicate that you want it to be public, add a default README.md file, and choose a license. - -![GitHub create repository](GitHubCreateRepo.jpg) - -Every repository in GitHub has a unique URL assigned to it. Assuming the repository is public, anyone with the URL can clone it to their development environment. A repository clone is an exact copy of the repository including all of the commits, comments, and SHAs. It also configures the clone to know what the remote source is so that you can use Git commands to keep them in sync as changes are made. - -![GitHub clone](GitHubClone.jpg) - -You clone a repository by providing the GitHub repository's URL as a parameter to the `git clone` command from in a console window. You can get a copy of the URL from the repository's GitHub page and clicking on the green `Code` button, and then clicking on the copy button next to the HTTPS url. - -![GitHub clone URL](GitUrlButton.jpg) - -When you clone a repository it is placed in a subdirectory named with the name of the repository. So make sure you are in the directory where you keep all of your source repositories before you run the command. - -```sh -➜ git clone https://github.com/YOURACCOUNT/chess.git - -Cloning into 'chess'... -remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 0 -Receiving objects: 100% (4/4), done. - -➜ cd chess -``` - -## IntelliJ and Git - -Knowing how to use Git from the console is a very valuable skill. Git offers a wide variety of functionality such as creating branches of the repository, temporarily stashing changes, and cloning repositories to other machines. However, by using a tool like IntelliJ you can hide all of the complexity of the command line and use a visual interface instead. - -Here are the steps you need to take to successfully use Git, GitHub, and IntelliJ. - -### One Time Steps - -1. Make sure Git is installed. -1. Make sure you have a GitHub account. -1. Make sure you have a personal access token or have configured IntelliJ to have access to your GitHub account using OAuth. - -### Per Project Steps - -1. Create a GitHub repo for the project. Creating your repo in GitHub and then cloning it locally is much easier than trying to associate a local Git repo to a newly created GitHub repo. -1. Copy the URL for your GitHub repo. - - ![GitHub Repo URL](github-url.png) - -1. Clone the GitHub repo to your development environment using the GitHub repo URL. - -```sh -➜ git clone https://github.com/YOURACCOUNT/YOURREPO.git -``` - -1. Create your project in IntelliJ. Set the target location for the project to be the same location where your cloned the repo. - -1. In the IntelliJ project, make a change, commit, and push to make sure it is working. - -The following video demonstrates committing and pushing code from IntelliJ to a GitHub repo. Once we have made our changes, we can use the `Commit` tab on the left to interact with Git and GitHub. On the `Commit` tab we can see all the changes we have made to the code. By clicking on the files we see the difference between the old and new version. If everything looks good we can press the `Commit and Push` button. If this is the first push you are making to your GitHub account then, you need to provide our Personal Access Token. Once you have done this once, you don't need to do it again. - -![IntelliJ Git](GitIntelliJ.gif) - -You can also use the `Git` tab, at the bottom of the screen, to see the commit history for your project. This allows you to walk back in history and see where changes were introduced or even revert back to previous versions. - -Underneath the covers, IntelliJ is running Git commands just like we did on the command line, but using a visual tool makes working with versions much easier. - -Take some time and play with adding files, modifying them, committing, and diffing. You want to get to the point where this is second nature so that you can easily experiment and make mistakes, knowing that with Git, you can always easily recover. - -### Connecting an Existing IntelliJ Project to GitHub - -If you already have a Git repo in your local development environment and you want to connect it to a GitHub repo then you need to take two steps. - -1. Set the upstream origin for your local repo to point to the GitHub repo. - - ```sh - ➜ git remote add origin https://github.com/YOURACCOUNT/YOURREPO.git - ``` - -1. Set the branch and remote for the origin. You do this the first time you push. Note that your branch may be `master` instead of `main` depending on how you have configured your GitHub repo. - - ```sh - ➜ git push -u origin main - ``` - -## Videos - -- 🎥 [Git Overview (4:50)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=57cf5ee3-521c-470e-987b-b169014cdec4) - [[transcript]](https://github.com/user-attachments/files/17738322/CS_240_Git_Overview_Transcript.pdf) -- 🎥 [Install and Configure Git (5:11)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=87ddb22d-729b-44ec-a476-b169014e892b) - [[transcript]](https://github.com/user-attachments/files/17738329/CS_240_Install_and_Configure_Git_Transcript.pdf) -- 🎥 [Creating a Local Git Repository (6:56)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=dfad1615-37dd-4416-b22c-b16901505d17) - [[transcript]](https://github.com/user-attachments/files/17738340/CS_240_Creating_a_Local_Git_Repository_Transcript.pdf) -- 🎥 [Commits (5:44)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=99d9a734-fcc7-4b21-b312-b1690152b5a0) - [[transcript]](https://github.com/user-attachments/files/17738354/CS_240_Commits_Transcript.pdf) -- 🎥 [Basic Git Commands (9:34)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=fce3f593-caa1-4c76-9327-b1690154d107) - [[transcript]](https://github.com/user-attachments/files/17738363/CS_240_Basic_Git_Commands_Transcript.pdf) -- 🎥 [.gitignore (5:14)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=0963f0ab-08ef-48e8-88c6-b1690157c264) - [[transcript]](https://github.com/user-attachments/files/17738368/CS_240_.gitignore_Transcript.pdf) -- 🎥 [Renaming, Moving, and Deleting Files (4:44)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=164be31f-0638-4517-afd7-b16901599a70) - [[transcript]](https://github.com/user-attachments/files/17738375/CS_240_Renaming_Moving_and_Deleting_Files_Transcript.pdf) -- 🎥 [IntelliJ Git Integration (5:05)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=99d7bc8f-4605-4948-87ee-b169015b41d1) - [[transcript]](https://github.com/user-attachments/files/17738392/CS_240_IntelliJ_Git_Integration_Transcript.pdf) -- 🎥 [Git Tips (3:41)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=cd651660-5fcd-4249-950d-b169015ddf09) - [[transcript]](https://github.com/user-attachments/files/17738394/CS_240_Git_Tips_Transcript.pdf) -- 🎥 [GitHub Overview (11:22)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=1750077c-a834-437e-86ef-b169015f60d8) - [[transcript]](https://github.com/user-attachments/files/17738402/CS_240_GitHub_Overview_Transcript.pdf) -- 🎥 [GitHub Set Up (9:59)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=27cf1095-6538-4ff2-a12f-b16901630775) - [[transcript]](https://github.com/user-attachments/files/17738408/CS_240_GitHub_Set_Up_Transcript.pdf) -- 🎥 [GitHub Demo (4:29)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=1bd5974c-a15b-45ef-b3df-b16901665e90) - [[transcript]](https://github.com/user-attachments/files/17738411/CS_240_GitHub_Demo_Transcript.pdf) diff --git a/instruction/git/github-url.png b/instruction/git/github-url.png deleted file mode 100644 index 7e1c36d0..00000000 Binary files a/instruction/git/github-url.png and /dev/null differ diff --git a/instruction/git/linusTorvalds.jpg b/instruction/git/linusTorvalds.jpg deleted file mode 100644 index 7f3e17c2..00000000 Binary files a/instruction/git/linusTorvalds.jpg and /dev/null differ diff --git a/instruction/http/http.md b/instruction/http/http.md deleted file mode 100644 index 51c91c27..00000000 --- a/instruction/http/http.md +++ /dev/null @@ -1,190 +0,0 @@ -# Hypertext Transfer Protocol - -🖥️ [Slides](https://docs.google.com/presentation/d/1VECGwiLgXd541yq9BWVSYiphHAXHG0ca/edit?usp=sharing&ouid=114081115660452804792&rtpof=true&sd=true) - -🖥️ [Lecture Videos](#videos) - -📖 **Optional Reading**: [MDN An overview of HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview) - -![Tim Berners Lee](timBernersLee.jpg) - -> “You affect the world by what you browse” -> -> — Tim Berners-Lee, (**Source**: _Answers for Young People_) - -## URL - -The Uniform Resource Locator (URL) represents the location of a web resource. A web resource can be anything, such as a web page, font, image, video stream, database record, or JSON object. It can also be completely ephemeral, such as a visitation counter, or gaming session. - -Looking at the different parts of a URL is a good way to understand what it represents. Here is an example URL that represents a query to BYU for cities that contain `pro` using secure HTTP. - -![url](url.png) - -The URL syntax uses the following convention. Notice the delimiting punctuation between the parts of the URL. Most parts of the URL are optional. The only ones that are required are the scheme, and the domain name. - -```yaml -://:/?# -``` - -| Part | Example | Meaning | -| ----------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Scheme | https | The protocol required to ask for the resource. For web applications, this is usually HTTPS. But it could be any internet protocol such as FTP or MAILTO. | -| Domain name | byu.edu | The domain name that owns the resource represented by the URL. | -| Port | 3000 | The port specifies the numbered network port used to connect to the domain server. Lower number ports are reserved for common internet protocols, higher number ports can be used for any purpose. The default port is 80 if the scheme is HTTP, or 443 if the scheme is HTTPS. | -| Path | /school/byu/user/8014 | The path to the resource on the domain. The resource does not have to physically be located on the file system with this path. It can be a logical path representing endpoint parameters, a database table, or an object schema. | -| Parameters | filter=names&highlight=intro,summary | The parameters represent a list of key value pairs. Usually it provides additional qualifiers on the resource represented by the path. This might be a filter on the returned resource or how to highlight the resource. The parameters are also sometimes called the query string. | -| Anchor | summary | The anchor usually represents a sub-location in the resource. For HTML pages this represents a request for the browser to automatically scroll to the element with an ID that matches the anchor. The anchor is also sometimes called the hash, or fragment ID. | - -Technically you can also provide a user name and password before the domain name. This was used historically to authenticate access, but for security reasons this is deprecated. However, you will still see this convention for URLs that represent database connection strings. - -## HTTP - -Hypertext Transfer Protocol (`HTTP`) is how the web talks. When a web browser makes a request to a web server it does it using the HTTP protocol. The purpose of this instruction is help you master the high level internals of HTTP. Just like becoming fluent in a foreign language makes a visit to another country more enjoyable, understanding how to speak HTTP helps you communicate effectively when talking on the web. - -When a web client (e.g. a web browser) and a web server talk they exchange HTTP requests and responses. The browser will make an HTTP request and the server will generate an HTTP response. You can see the HTTP exchange by using the browser's debugger or by using a console tool like `curl`. For example, in your console you can use `curl` to make the following request. - -```sh -curl -v -s http://info.cern.ch/hypertext/WWW/Helping.html -``` - -### Request - -The HTTP request for the above command would look like the following. - -```http -GET /hypertext/WWW/Helping.html HTTP/1.1 -Host: info.cern.ch -Accept: text/html -``` - -An HTTP request has this general syntax. - -```yaml - -[
]* -[ - - -] -``` - -The first line of the HTTP request contains the `verb` of the request, followed by the path, parameters, and anchor of the URL, and finally the version of HTTP being used. The following lines are optional headers that are defined by key value pairs. After the headers you have an optional body. The body start is delimited from the headers with two new lines. - -In the above example, we are asking to `GET` a resource found at the path `/hypertext/WWW/Helping.html`. The version used by the request is `HTTP/1.1`. This is followed by two headers. The first specifies the requested host (i.e. domain name). The second specifies what type of resources the client will accept. The resource type is always a [MIME type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types) as defined by internet governing body IANA. In this case we are asking for HTML. - -### Response - -The response to the above request looks like this. - -```yaml -HTTP/1.1 200 OK -Date: Tue, 06 Dec 2022 21:54:42 GMT -Server: Apache -Last-Modified: Thu, 29 Oct 1992 11:15:20 GMT -ETag: "5f0-28f29422b8200" -Accept-Ranges: bytes -Content-Length: 1520 -Connection: close -Content-Type: text/html - -Helping -- /WWW - -

How can I help?

There are lots of ways you can help if you are interested in seeing -the web grow and be even more useful... -``` - -An HTTP response has the following syntax. - -```yaml - -[
]* -[ - - -] -``` - -You can see that the response syntax is similar to the request syntax. The major difference is that the first line represents the version and the status of the response. - -Understanding the meaning of the common HTTP verbs, status codes, and headers is important for you to understand, as you will use them in developing a web application. Take some time to internalize the following common values. - -## Verbs - -There are several verbs that describe what the HTTP request is asking for. The list below only describes the most common ones. - -| Verb | Meaning | -| ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| GET | Get the requested resource. This can represent a request to get a single resource or a resource representing a list of resources. | -| POST | Create a new resource. The body of the request contains the resource. The response should include a unique ID of the newly created resource. | -| PUT | Update a resource. Either the URL path, HTTP header, or body must contain the unique ID of the resource being updated. The body of the request should contain the updated resource. The body of the response may contain the resulting updated resource. | -| DELETE | Delete a resource. Either the URL path or HTTP header must contain the unique ID of the resource to delete. | -| OPTIONS | Get metadata about a resource. Usually only HTTP headers are returned. The resource itself is not returned. | - -## Status codes - -It is important that you use the standard HTTP status codes in your HTTP responses so that the client of a request can know how to interpret the response. The codes are partitioned into five blocks. - -- 1xx - Informational. -- 2xx - Success. -- 3xx - Redirect to some other location, or that the previously cached resource is still valid. -- 4xx - Client errors. The request is invalid. -- 5xx - Server errors. The request cannot be satisfied due to an error on the server. - -Within those ranges here are some of the more common codes. See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) for a full description of status codes. - -| Code | Text | Meaning | -| ---- | ------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- | -| 100 | Continue | The service is working on the request | -| 200 | Success | The requested resource was found and returned as appropriate. | -| 201 | Created | The request was successful and a new resource was created. | -| 204 | No Content | The request was successful but no resource is returned. | -| 304 | Not Modified | The cached version of the resource is still valid. | -| 307 | Permanent redirect | The resource is no longer at the requested location. The new location is specified in the response location header. | -| 308 | Temporary redirect | The resource is temporarily located at a different location. The temporary location is specified in the response location header. | -| 400 | Bad request | The request was malformed or invalid. | -| 401 | Unauthorized | The request did not provide a valid authentication token. | -| 403 | Forbidden | The provided authentication token is not authorized for the resource. | -| 404 | Not found | An unknown resource was requested. | -| 408 | Request timeout | The request takes too long. | -| 409 | Conflict | The provided resource represents an out of date version of the resource. | -| 418 | [I'm a teapot](https://en.wikipedia.org/wiki/Hyper_Text_Coffee_Pot_Control_Protocol) | The service refuses to brew coffee in a teapot. | -| 429 | Too many requests | The client is making too many requests in too short of a time period. | -| 500 | Internal server error | The server failed to properly process the request. | -| 503 | Service unavailable | The server is temporarily down. The client should try again with an exponential back off. | - -## Headers - -📖 **Optional Reading**: [MDN HTTP headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers) - -HTTP headers specify metadata about a request or response. This includes things like how to handle security, caching, data formats, and cookies. Some common headers that you will use include the following. - -| Header | Example | Meaning | -| --------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| Authorization | Bearer bGciOiJIUzI1NiIsI | A token that authorized the user making the request. | -| Accept | image/\* | What content format the client accepts. This may include wildcards. | -| Content-Type | text/html; charset=utf-8 | The format of the response content. These are described using standard [MIME](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types) types. | -| Cookie | SessionID=39s8cgj34; csrftoken=9dck2 | Key value pairs that are generated by the server and stored on the client. | -| Host | info.cern.ch | The domain name of the server. This is required in all requests. | -| Origin | cs260.click | Identifies the origin that caused the request. A host may only allow requests from specific origins. | -| Access-Control-Allow-Origin | https://cs260.click | Server response of what origins can make a request. This may include a wildcard. | -| Content-Length | 368 | The number of bytes contained in the response. | -| Cache-Control | public, max-age=604800 | Tells the client how it can cache the response. | -| User-Agent | Mozilla/5.0 (Macintosh) | The client application making the request. | - -## Body - -The format of the body of an HTTP request or response is defined by the `Content-Type` header. For example, it may be HTML text (text/html), a binary image format (image/png), JSON (application/json), or JavaScript (text/javascript). A client may specify what formats it accepts using the `accept` header. - -## Things to Understand - -- Internet basics: IP addresses, domain names, port numbers -- Web basics: URLs, the HTTP protocol (Headers, methods, and body) -- URL schema - -## Videos - -- 🎥 [Chess Server Review (3:39)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=a3d5b141-7756-4b0f-8912-b185014dbd5e) - [[transcript]](https://github.com/user-attachments/files/17738495/CS_240_Chess_Server_Review_Transcript.pdf) -- 🎥 [HTTP Overview (10:42)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=ef2d29d2-72af-4d8f-9cdc-b185014f4fe5) - [[transcript]](https://github.com/user-attachments/files/17738497/CS_240_HTTP_Overview_Transcript.pdf) -- 🎥 [HTTP GET Requests (23:29)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=ea7a075b-a516-40f2-b17b-b185015286d8) - [[transcript]](https://github.com/user-attachments/files/17738504/CS_240_HTTP_GET_Requests_Transcript.pdf) -- 🎥 [HTTP POST Requests (8:43)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=90dad290-87d6-44c5-9aa5-b185015930a1) - [[transcript]](https://github.com/user-attachments/files/17738509/CS_240_HTTP_POST_Requests_Transcript.pdf) -- 🎥 [HTTP Methods (2:49)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=50ec71e4-a0d9-4f55-853e-b185015bd652) - [[transcript]](https://github.com/user-attachments/files/17738511/CS_240_HTTP_Methods_Transcript.pdf) diff --git a/instruction/http/timBernersLee.jpg b/instruction/http/timBernersLee.jpg deleted file mode 100644 index 270e6744..00000000 Binary files a/instruction/http/timBernersLee.jpg and /dev/null differ diff --git a/instruction/http/url.png b/instruction/http/url.png deleted file mode 100644 index 0582eaab..00000000 Binary files a/instruction/http/url.png and /dev/null differ diff --git a/instruction/inner-classes/example-code/Iterator.java b/instruction/inner-classes/example-code/Iterator.java deleted file mode 100644 index c5813c3f..00000000 --- a/instruction/inner-classes/example-code/Iterator.java +++ /dev/null @@ -1,8 +0,0 @@ -package nestedClassExample; - -public interface Iterator { - - boolean hasNext(); - - int getNext(); -} diff --git a/instruction/inner-classes/example-code/anonymousInnerClass/DataStructure.java b/instruction/inner-classes/example-code/anonymousInnerClass/DataStructure.java deleted file mode 100644 index ba7dbc51..00000000 --- a/instruction/inner-classes/example-code/anonymousInnerClass/DataStructure.java +++ /dev/null @@ -1,55 +0,0 @@ -package nestedClassExample.anonymousInnerClass; - -import nestedClassExample.Iterator; - -public class DataStructure { - - private int[] arrayOfInts; - - public static void main(String s[]) { - - // Create an instance and fill it with with integer values - DataStructure ds = new DataStructure(10); - - // Iterate through the data structure and print it's values - Iterator iterator = ds.iterator(2); - while (iterator.hasNext()) { - System.out.println(iterator.getNext() + " "); - } - } - - public DataStructure(int size) { - - arrayOfInts = new int[size]; - - // Fill the array with ascending integer values - for (int i = 0; i < size; i++) { - arrayOfInts[i] = i; - } - } - - public Iterator iterator(int increment) { - // An anonymous inner class that implements the Iterator pattern. - return new Iterator() { - // Start stepping through the array from the beginning - private int next = 0; - - @Override - public boolean hasNext() { - // Check if a current element is the last in the array - return (next <= arrayOfInts.length - 1); - } - - @Override - public int getNext() { - // Get the value to be returned - int retValue = arrayOfInts[next]; - - // Increment the counter in preparation for the next call - next += increment; - - return retValue; - } - }; - } -} \ No newline at end of file diff --git a/instruction/inner-classes/example-code/innerClass/DataStructure.java b/instruction/inner-classes/example-code/innerClass/DataStructure.java deleted file mode 100644 index bdb27f37..00000000 --- a/instruction/inner-classes/example-code/innerClass/DataStructure.java +++ /dev/null @@ -1,68 +0,0 @@ -package nestedClassExample.innerClass; - -import nestedClassExample.Iterator; - -public class DataStructure { - - private int[] arrayOfInts; - - public static void main(String s[]) { - - // Create an instance and fill it with with integer values - DataStructure ds = new DataStructure(10); - - // Iterate through the data structure and print it's values - Iterator iterator = ds.iterator(2); - while (iterator.hasNext()) { - System.out.println(iterator.getNext() + " "); - } - } - - public DataStructure(int size) { - - arrayOfInts = new int[size]; - - // Fill the array with ascending integer values - for (int i = 0; i < size; i++) { - arrayOfInts[i] = i; - } - } - - public Iterator iterator(int increment) { - return new DataStructureIterator(increment); - } - - /** - * An inner class that implements the Iterator pattern. Notice that the inner - * class has direct access to the outer object's fields, so we do not need to pass - * them to a constructor. - */ - private class DataStructureIterator implements Iterator { - - int increment; - - // Start stepping through the array from the beginning - private int next = 0; - - DataStructureIterator(int increment) { - this.increment = increment; - } - - @Override - public boolean hasNext() { - // Check if a current element is the last in the array - return (next <= arrayOfInts.length - 1); - } - - @Override - public int getNext() { - // Get the value to be returned - int retValue = arrayOfInts[next]; - - // Increment the counter in preparation for the next call - next += increment; - - return retValue; - } - } -} \ No newline at end of file diff --git a/instruction/inner-classes/example-code/localInnerClass/DataStructure.java b/instruction/inner-classes/example-code/localInnerClass/DataStructure.java deleted file mode 100644 index 78f1889e..00000000 --- a/instruction/inner-classes/example-code/localInnerClass/DataStructure.java +++ /dev/null @@ -1,67 +0,0 @@ -package nestedClassExample.localInnerClass; - -import nestedClassExample.Iterator; - -public class DataStructure { - - private int[] arrayOfInts; - - public static void main(String s[]) { - - // Create an instance and fill it with with integer values - DataStructure ds = new DataStructure(10); - - // Iterate through the data structure and print it's values - Iterator iterator = ds.iterator(2); - while (iterator.hasNext()) { - System.out.println(iterator.getNext() + " "); - } - } - - public DataStructure(int size) { - - arrayOfInts = new int[size]; - - // Fill the array with ascending integer values - for (int i = 0; i < size; i++) { - arrayOfInts[i] = i; - } - } - - public Iterator iterator(int increment) { - - /** - * A local inner class that implements the Iterator pattern. Notice that the inner - * class not only has direct access to the outer object's fields, but also to the - * increment local variable, so we no longer need to pass it in the constructor. - * - * Local inner classes can only access variables that are final or "effectively final" - * meaning they can't access local variables that they or any other code in the method - * changes. - */ - class DataStructureIterator implements Iterator { - - // Start stepping through the array from the beginning - private int next = 0; - - @Override - public boolean hasNext() { - // Check if a current element is the last in the array - return (next <= arrayOfInts.length - 1); - } - - @Override - public int getNext() { - // Get the value to be returned - int retValue = arrayOfInts[next]; - - // Increment the counter in preparation for the next call - next += increment; - - return retValue; - } - } - - return new DataStructureIterator(); - } -} \ No newline at end of file diff --git a/instruction/inner-classes/example-code/staticInnerClass/DataStructure.java b/instruction/inner-classes/example-code/staticInnerClass/DataStructure.java deleted file mode 100644 index af43bd4f..00000000 --- a/instruction/inner-classes/example-code/staticInnerClass/DataStructure.java +++ /dev/null @@ -1,70 +0,0 @@ -package nestedClassExample.staticInnerClass; - -import nestedClassExample.Iterator; - -public class DataStructure { - - private int[] arrayOfInts; - - public static void main(String s[]) { - - // Create an instance and fill it with with integer values - DataStructure ds = new DataStructure(10); - - // Iterate through the data structure and print it's values - Iterator iterator = ds.iterator(2); - while (iterator.hasNext()) { - System.out.println(iterator.getNext() + " "); - } - } - - public DataStructure(int size) { - - arrayOfInts = new int[size]; - - // Fill the array with ascending integer values - for (int i = 0; i < size; i++) { - arrayOfInts[i] = i; - } - } - - public Iterator iterator(int increment) { - return new DataStructureIterator(arrayOfInts, increment); - } - - /** - * A static inner class that implements the Iterator pattern. Notice that the static - * inner class has no access to the outer object's fields, so we must pass all the - * data it needs into its constructor. - */ - private static class DataStructureIterator implements Iterator { - - private int[] array; - int increment; - - // Start stepping through the array from the beginning - private int next = 0; - - DataStructureIterator(int[] array, int increment) { - this.array = array; - this.increment = increment; - } - - @Override - public boolean hasNext() { - // Check if a current element is the last in the array - return (next <= array.length - 1); - } - - @Override - public int getNext() { - // Get the value to be returned - int retValue = array[next]; - - // Increment the counter in preparation for the next call - next += increment; - - return retValue; - } - } -} \ No newline at end of file diff --git a/instruction/inner-classes/inner-classes.md b/instruction/inner-classes/inner-classes.md deleted file mode 100644 index cd167940..00000000 --- a/instruction/inner-classes/inner-classes.md +++ /dev/null @@ -1,217 +0,0 @@ -# Java Inner Classes - -📖 **Required Reading**: Core Java for the Impatient - -- Chapter 2 section 2.7 Nested Classes -- Chapter 3 section 3.9 Local and Anonymous Classes - -🖥️ [Lecture Videos](#videos) - -Normally in Java, a class must be defined at the top level of a file that has the same name as the class. However, there are times when a class is only used within the context of another class, method, or scope. This is where inner, or nested, classes come into play. - -There are four types of Inner (Nested) Classes in Java. - -- **Static Inner Classes** - Defined within the scope of another class. -- **Inner Classes** - Defined within the scope of another class and shares the `this` pointer. -- **Local Inner Classes** - Defined within the scope of a block and shares scope variables. -- **Anonymous Inner Classes** - Defined without a class name and shares scope variables. - -## Static Inner Classes - -A static inner class is defined inside another class. Commonly this is done as a utility class within the parent, as an aggregation piece of the parent's fields, or as a public class that in necessary for the operation of the outer class. - -You can think of a static inner class as being a convenient way to declare a class, without creating a new file, that is tightly coupled to the outer class. - -Because the inner class is declared as being static, it is completely independent of the outer class, and does not have access to outer class's `this` pointer. - -```java -public class StaticOuterExample { - public static void main(String[] args) { - System.out.println(new StaticOuterExample()); - } - - private StaticInnerExample inner = new StaticInnerExample(); - - private static class StaticInnerExample { - public String toString() { - var inner = this.getClass().getName(); - return String.format("Inner: %s", inner); - } - } - - public String toString() { - return inner.toString(); - } -} -``` - -**Output** - -```sh -Inner: StaticOuterExample$StaticInnerExample -``` - -## Inner Classes - -An inner class, that is not marked as static, is similar to a static inner class, but has access to the `this` pointer of the outer class. To access the outer classes `this` pointer, the inner class prefixes the `this` pointer with the outer class's name. - -```java -public class OuterExample { - public static void main(String[] args) { - System.out.println(new OuterExample()); - } - - private InnerExample inner = new InnerExample(); - - private class InnerExample { - public String toString() { - var inner = this.getClass().getName(); - // Note the use of the outer class's this pointer. - var outer = OuterExample.this.getClass().getName(); - return String.format("Inner: %s has access to Outer: %s", inner, outer); - } - } - - public String toString() { - return inner.toString(); - } -} -``` - -**Output** - -```sh -Inner: OuterExample$InnerExample has access to Outer: OuterExample -``` - -## Local Inner Class - -A local inner class is like a normal inner class, but are declared within the scope of the block. A declaration scope may be a method, or something like a `for loop`. An important property of local inner classes is that, whatever variables exist within the declaration scope are also available to the local inner class. - -```java -public class LocalOuterExample { - public static void main(String[] args) { - System.out.println(new LocalOuterExample()); - } - - public String toString() { - var outerLocalVar = "outerLocalVar"; - - class InnerExample { - public String toString() { - var inner = this.getClass().getName(); - // Note the use of the outer class's this pointer and scope variables. - var outer = LocalOuterExample.this.getClass().getName(); - return String.format("Inner: %s has access to Outer: %s, and variables: %s", inner, outer, outerLocalVar); - } - } - - InnerExample inner = new InnerExample(); - - return inner.toString(); - } -} -``` - -**Output** - -```sh -Inner: OuterExample$1InnerExample has access to Outer: OuterExample, and variables: outerLocalVar -``` - -## Closure - -The ability for a local inner class to access the variables of its declaring scope is a programming concept called `closure`. This is useful when you want to create object factories that can be parameterized by the environment that they are declared in. Here is an example of using `closure` to create objects that can speak different languages. - -Notice that the object returned from factory method can access the `helloPhrase` parameter that was passed to the factory method even after the factory method has gone out of scope. - -```java -public class Closure { - public interface Speaker { - String sayHello(); - } - - public static void main(String[] args) { - - var spanish = SpeakerFactory("Hola"); - var german = SpeakerFactory("Hallo"); - - System.out.printf("Spanish: %s\nGerman: %s", spanish.sayHello(), german.sayHello()); - } - - private static Speaker SpeakerFactory(String helloPhrase) { - class InnerExample implements Speaker { - public String sayHello() { - return helloPhrase; - } - } - - return new InnerExample(); - } -} -``` - -**Output** - -```sh -Spanish: Hola -German: Hallo -``` - -## Anonymous Inner Class - -An anonymous inner class, is defined inline by referencing an interface, followed by the implementation. This is useful in cases where you have commonly used interfaces that only have a single method. This saves you from creating lots of little classes that are only used once. In the following example we can create two different implementations of the `Speaker` interface by defining the `sayHello` method inline. - -Note that anonymous inner classes also have closure on the scope that they were declared in. - -```java -public class AnonymousExample { - public interface Speaker { - String sayHello(); - } - - public static void main(String[] args) { - var spanish = new Speaker() { - public String sayHello() { - return "Hola"; - } - }; - var german = new Speaker() { - public String sayHello() { - return "Hallo"; - } - }; - - System.out.printf("Spanish: %s\nGerman: %s", spanish.sayHello(), german.sayHello()); - } -} -``` - -## Things to Understand - -- What are static inner classes and what benefits do they provide? -- What can regular inner classes do that static inner classes cannot? -- What can local inner classes do that regular inner classes cannot? -- What does it mean for a variable to be final or effectively final? -- Why do local inner classes have a restriction on which local variables they can access? -- How do you define an anonymous inner class and what benefit does it provide over a local inner class? - -## Videos - -- 🎥 [Introduction (6:23)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=1a6ec347-24b8-41db-9dd8-ad72014f1ec1&start=0) - [[transcript]](https://github.com/user-attachments/files/17780969/CS_240_Inner_Class_Introduction.pdf) -- 🎥 [Static Inner Classes (5:55)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=c02cdeb8-5929-4b80-b83a-ad72015107bc&start=0) - [[transcript]](https://github.com/user-attachments/files/17780972/CS_240_Static_Inner_Classes.pdf) -- 🎥 [Inner Classes (2:06)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=201871e8-f294-40d4-944c-ad720152d070&start=0) - [[transcript]](https://github.com/user-attachments/files/17804795/CS_240_Inner_Classes.pdf) -- 🎥 [Local Inner Classes (7:09)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=817e3e88-8d19-4ffa-85b4-ad7201539033&start=0) - [[transcript]](https://github.com/user-attachments/files/17804799/CS_240_Local_Inner_Classes.pdf) -- 🎥 [Anonymous Inner Classes (5:16)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=7faf22b0-00df-4429-818f-ad720155ad20&start=0) - [[transcript]](https://github.com/user-attachments/files/17804804/CS_240_Anonymous_Inner_Classes.pdf) - -## Demonstration code - -📁 [Iterator.java](example-code/Iterator.java) - -📁 [anonymousInnerClass](example-code/anonymousInnerClass) - -📁 [innerClass](example-code/innerClass) - -📁 [localInnerClass](example-code/localInnerClass) - -📁 [staticInnerClass](example-code/staticInnerClass) diff --git a/instruction/interfaces-abstract-classes/interfaces-and-abstract-classes.md b/instruction/interfaces-abstract-classes/interfaces-and-abstract-classes.md deleted file mode 100644 index c70b3d94..00000000 --- a/instruction/interfaces-abstract-classes/interfaces-and-abstract-classes.md +++ /dev/null @@ -1,386 +0,0 @@ -# Interfaces and Abstract Classes - -🖥️ [Slides](https://docs.google.com/presentation/d/1eaSGnq2FCGd7jNWve1W-LSNrERGUj7nT) - -📖 **Required Reading**: Core Java for the Impatient - -- Chapter 3: - - Section 1 - Interfaces - - Section 2 - Static, Default, and Private Methods - - Section 3 - Examples of Interfaces -- Chapter 4: - - Section 1 - Extending a Class - - Section 2 - Object: The Cosmic Superclass - - Section 3 - Enumerations - -🖥️ [Lecture Videos](#videos) - -## Polymorphism - -Polymorphism is the blanket term used in computer science to represent the idea of morphing an object to fit into many (i.e. poly) different contexts. In Java, the use of inheritance and abstract classes are the primary ways to provide polymorphism. You use the `extends` keyword to inherit another class's functionality, and you use the `implements` keyword to inherit an interface definition. Polymorphism allows you to decouple, or abstract, a class's internals, from how it is used. That makes it so you can significantly alter the class without having to change how the class is used. - -## Interfaces - -Interfaces allow you to define what something does, without specifying how it does it. It also allows you to create and supply alternative implementations for the interface. For example, you can have an interface that defines what a `List` can do, and then create classes that provide different implementations of the `List`. Perhaps one implementation uses less memory, and a different one is faster. You can then write code that uses the `List` interface and not have to think about if it is using the fast version or the memory efficient version. - -```java -public interface List extends SequencedCollection { - void add(int index, E element); - E remove(int index); - int size(); - void clear(); - ListIterator listIterator(); -} -``` - -The following example shows two implementations of a `List`. One that uses an array, and one that uses a linked list. The two lists can be passed to a function, `addAndPrint` in this case, that doesn't know anything about the implementation of the list, it just knows that it can call the interface's `add` method. - -```java -import java.util.List; -import java.util.ArrayList; -import java.util.LinkedList; - -public class ListExample { - public void listExample() { - // Represent two different implementations of the List interface. - List list1 = new ArrayList<>(); - List list2 = new LinkedList<>(); - - addAndPrint(list1, "vanilla"); - addAndPrint(list2, "taco"); - } - - // This function takes any implementation of the List interface. - private void addAndPrint(List list, String value) { - // The add method is defined on the list interface. - list.add(value); - System.out.println(value); - } -} -``` - -Note that, because `addAndPrint()` doesn't know anything about `list`'s type except that it implements the `List` interface, it can only call methods on `list` that are declared in the interface. If `LinkedList` had an additional method that was not declared in the interface, and `addAndPrint()` tried to call that method on `list`, it would not compile, even if it was passed a `LinkedList`. - -## Writing Your Own Interface - -In addition to using a class that implements one of the JDK standard interfaces, you can write your own interface implementations, and even define completely new interfaces. Creating an interface is similar to creating a class, except you use the `interface` keyword and only define the signature of the methods that the interface represents. - -For example, if you wanted to create a specialized iterator that returned each character in a string you could write the following: - -```java -public interface CharIterator { - /** Returns true if there is another character to iterate. */ - boolean hasNext(); - - /** Returns the next character. */ - char next(); -} -``` - -You can then implement the `CharIterator` interface by specifying the `implements` keyword after the class name declaration, and writing each of the methods defined by the interface. The `@Override` annotation is not technically necessary, but it makes it clear that the method is part of an interface. - -```java -public class AlphabetIterator implements CharIterator { - int current = 0; - String charString = "abcdefg"; - - @Override - public boolean hasNext() { - return current < charString.length(); - } - - @Override - public char next() { - return charString.charAt(current++); - } -} -``` - -## Extending Classes - -In the discussion for classes and objects we showed how you can inherit code from another class and treat it as if the code was included in a derived class. By default, all classes in Java derive from the Object class. That means they `inherit` the Object classes fields and methods. You can also explicitly state what class you derive from by using the `extends` keyword. In the following example, the `SubClass` extends the `SuperClass` and uses the SuperClass's toString method to implement its toString method. SubClass can do this because everything in the derived class literally becomes part of the subclass just as if the code had been written in the subclass. - -```java -public static class SuperClass extends Object { - String name = "super"; - - public String toString() { - return name; - } -} - -public static class SubClass extends SuperClass { - public String toString() { - return "Sub-class of " + super.toString(); - } -} -``` - -## Abstract Classes - -Abstract classes provide another type of polymorphism. However, unlike interfaces, where the subclass implements all of the functionality of the interface, a base class that is an abstract class provides some of the implementation and leaves other methods to be implemented by the subclass. - -The JDK's `Iterator` interface allows you to walk through, or iterate, through a collection of objects. - -```java -public interface Iterator { - boolean hasNext(); - E next(); -``` - -We can create a class that implements the iterator interface by returning the characters of a string, but also defines a new abstract method for iterating that allows for a string to be prefixed to each iteration result. This is done by specifying the `abstract` keyword on the `nextWithPrefix` method, without providing an implementation of the method. - -You can think of abstract classes as a class/interface hybrid. - -```java -/** - * The abstract keyword signifies that this class contains methods - * that must be implemented by a subclass - */ -public static abstract class AlphabetIterator implements Iterator { - int current = 0; - String charString = "abcdefg"; - - public boolean hasNext() { - return current < charString.length(); - } - - public Object next() { - return charString.substring(current, ++current); - } - - /** - * This method is not implemented by the abstract class and - * so it must be implemented by the subclass. - */ - public abstract String nextWithPrefix(String prefix); -} -``` - -A subclass `extends` the abstract class by providing an implementation of the abstract `nextWithPrefix` method. Additionally, for instructive purposes, we also override the `next` method to include a default prefix that represents the numerical order of the iterated items. - -Note the use of the `super` keyword in the `nextWithPrefix` function. `super` allows you to access methods in the abstract base class when you have methods with the same name as the subclass. In this example, it is used to access the abstract class's `next` function instead of the `next` function implemented by `PrefixAlphabetIterator`. Without the use of `super`, the call to `next` would have created an infinite loop. - -```java -public static class PrefixAlphabetIterator extends AlphabetIterator { - public String next() { - return nextWithPrefix(String.format("%d.", current + 1)); - } - - public String nextWithPrefix(String prefix) { - return String.format("%s. %s", prefix, super.next()); - } -} -``` - -Like interfaces, the name of the abstract class can be used to represent the subclass when passed to functions that expect the abstract class. In the following code, we create an object of the type `PrefixAlphabetIterator` and then pass it to a function that expects the abstract class `AlphabetIterator`. - -```java -public static void main(String[] args) { - var iter = new PrefixAlphabetIterator(); - print(new PrefixAlphabetIterator()); -} - - -public static void print(AlphabetIterator iter) { - while (iter.hasNext()) { - System.out.println(iter.nextWithPrefix("+ ")); - } -} -``` - -## instanceof - -Polymorphism is great because it makes it so code only needs to know about the provided interface. For example, if you want to have a list that can contain any type of object that extends the `Object` class, it can safely ignore the fact that those objects are also things like String, Integer, Person, or Map classes. However, sometimes you need to know if an object is of a specific type so that you can use it in different ways. This is where the `instanceof` operator comes in handy. `instanceof` will return true, if the provided variable is of the given type (including if it extends or implements it). A simple example of its use is demonstrated with a test to see if a string literal is an instance of type `String`. - -```java -if ("I am a string" instanceof String) { - // Always true -} -``` - -In the following example, we create a list that contains objects of different primitive types. We then iterate over this list and use the `instanceof` operator to execute different code based on the type of the list item. - -```java -public static void main(String[] args) { - List list = List.of('a', "b", 3); - - for (var item : list) { - if (item instanceof String) { - System.out.println("String"); - } else if (item instanceof Integer) { - System.out.println("Integer"); - } else if (item instanceof Character) { - System.out.println("Character"); - } - } -} -``` - -Starting in Java version 17 the pattern matching version of instanceof that automatically casts the object if it is of the specified type. This makes it very convenient to both test and cast in the one statement. - -```java -public class PatternMatchInstanceOfExample { - public static void main(String[] args) { - List list = List.of('a', "b", 3); - for (var item : list) { - if (item instanceof String stringItem) { - System.out.println(stringItem.toUpperCase()); - } else if (item instanceof Integer intItem) { - System.out.println(intItem + 100); - } else if (item instanceof Character charItem) { - System.out.println(charItem.compareTo('a')); - } - } - } -} -``` - -## final - -If you don't want a subclass to override a method in a base class then you can prefix the method with the keyword `final`. You can also use the final keyword to make a class's field value immutable. (You can still call methods on final fields, however, so it's not the same as the C++ `const`.) - -```java -public class FinalExample { - /** This variable cannot be changed */ - final double PI = 3.14; - - /** This method cannot be overridden */ - final public double getPI() { - return PI; - } -} -``` - -## Thinking about Chess - -With what you have learned here, consider the Chess program. How should chess pieces be abstracted? Should the piece type be represented as a data field? - -```mermaid -classDiagram - - class ChessPiece { - TeamColor - PieceType - pieceMoves() - } -``` - -Or would it be more appropriate to represent it using abstract class inheritance? - -```mermaid -classDiagram - - class ChessPiece { - TeamColor - pieceMoves() - } - - ChessPiece <|-- King - ChessPiece <|-- Queen - ChessPiece <|-- Pawn - - class King { - pieceMoves() - } - class Queen { - pieceMoves() - } - - class Pawn { - pieceMoves() - } - -``` - -Or should the rules be abstracted out of the chess so that the chess piece only represents the properties of the piece and not the rules of a game? - -```mermaid -classDiagram - - class ChessPiece { - TeamColor - pieceMoves() - } - - - class Rule { - <> - pieceMoves() - } - - KingRule --|> Rule - QueenRule --|> Rule - PawnRule --|> Rule - - class KingRule { - pieceMoves() - } - class QueenRule { - pieceMoves() - } - - class PawnRule { - pieceMoves() - } -``` - -Can I also use abstract classes, interfaces, and inheritances to build something that turns the dial even more? Or is this taking things too far? All of these questions are part of learning how to design software. - -Here is a possible design to incorporates all of the abstraction concepts into an architecture for representing rules. - -```mermaid -classDiagram - - class Rules { - getRule() - } - - Rules --> MovementRule - - class MovementRule { - <> - pieceMoves() - } - - class BaseMovementRule { - <> - private calculateMoves() - pieceMoves() - } - BaseMovementRule --|> MovementRule - - KingRule --|> BaseMovementRule - QueenRule --|> BaseMovementRule - PawnRule --|> BaseMovementRule - - class KingRule { - pieceMoves() - } - class QueenRule { - pieceMoves() - } - - class PawnRule { - pieceMoves() - } -``` - -## Things to Understand - -- What polymorphism is -- What abstract classes are and when to use them -- What interfaces are and when to use them -- How interfaces and abstract classes are both similar and different -- How to implement an interface in a class -- How to create an interface -- How to do inheritance in Java - -## Videos - -- 🎥 [Polymorphism (5:53)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=23d2e58e-9628-43a4-9aaa-ad640141e7dc&start=0) - [[transcript]](https://github.com/user-attachments/files/17804824/CS_240_Polymorphism.pdf) -- 🎥 [Polymorphism Example Part 1 (3:33)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=88adc709-e900-47d6-9e9a-ad64014400ad&start=0) - [[transcript]](https://github.com/user-attachments/files/17804825/CS_240_Polymorphism_Example_Part1.pdf) -- 🎥 [Polymorphism Example Part 2 (5:55)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=ebfcd403-53e4-4b68-8a3d-ad6401453df4&start=0) - [[transcript]](https://github.com/user-attachments/files/17738597/CS_240_Polymorphism_Example_Part_2_Transcript.pdf) -- 🎥 [Polymorphism Example Part 3 (9:33)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=f451dd38-e32d-445f-be0d-ad6401470c45&start=0) - [[transcript]](https://github.com/user-attachments/files/17804827/CS_240_Polymorphism_Example_Part3.pdf) -- 🎥 [Creating an Interface (3:03)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=2da0fb3a-7aca-4344-a42b-ad640149f9e2&start=0) - [[transcript]](https://github.com/user-attachments/files/17804828/CS_240_Creating_an_Interface.pdf) -- 🎥 [Implementing an Interface (2:27)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=f7ec17c1-c815-429b-8ffd-ad64014b0921&start=0) - [[transcript]](https://github.com/user-attachments/files/17804829/CS_240_Implementing_an_Interface.pdf) diff --git a/instruction/introduction/CoreJavaForTheImpatient4thEdition.png b/instruction/introduction/CoreJavaForTheImpatient4thEdition.png deleted file mode 100644 index 53cbcc9d..00000000 Binary files a/instruction/introduction/CoreJavaForTheImpatient4thEdition.png and /dev/null differ diff --git a/instruction/introduction/canvasCourse.jpg b/instruction/introduction/canvasCourse.jpg deleted file mode 100644 index f510a6b4..00000000 Binary files a/instruction/introduction/canvasCourse.jpg and /dev/null differ diff --git a/instruction/introduction/essentialsLearning.png b/instruction/introduction/essentialsLearning.png deleted file mode 100644 index a76be131..00000000 Binary files a/instruction/introduction/essentialsLearning.png and /dev/null differ diff --git a/instruction/introduction/highlight-moves.png b/instruction/introduction/highlight-moves.png deleted file mode 100644 index eb5ec59a..00000000 Binary files a/instruction/introduction/highlight-moves.png and /dev/null differ diff --git a/instruction/introduction/introduction.md b/instruction/introduction/introduction.md deleted file mode 100644 index f22831eb..00000000 --- a/instruction/introduction/introduction.md +++ /dev/null @@ -1,122 +0,0 @@ -# Introduction - -🖥️ [Slides - Jensen](https://docs.google.com/presentation/d/1hn9IpJT1DMQ1fECSt1CY7EdoDi4OQgRn/edit?usp=sharing&ouid=114081115660452804792&rtpof=true&sd=true) - -🖥️ [Slides - Rodham](https://docs.google.com/presentation/d/1fbz2fJwlQGvG4V4FTyJsKeDWIl6J7DSx/edit) - -🖥️ [Slides - Wilkerson](https://docs.google.com/presentation/d/16w_6hFRhAnNUg20Cnq8HEEnBeLawh3Iw/edit?usp=sharing&ouid=110961336761942794636&rtpof=true&sd=true) - -🖥️ [Lecture Videos](#videos) - -Welcome to Computer Science 240: `Advanced Software Construction`. This course focuses on learning how professional software developers build applications. As part of this instruction you will gain experience with the skills and technologies used in the real world of software construction. This includes: Software design, data modeling, object oriented programming, distributed communication, relational databases, and testing. - -In previous courses you have probably focused on building small programs that targeted learning a particular concept. While these programs teach you a specific concept, they fail to provide you with the skills necessary to create applications that require careful design, engineering, and tooling. - -## Software Engineering - -The term software engineering was first used in conjunction with the software created for the Apollo moon landings. Margaret Hamilton, the director of the software division, described their work as being similar to hardware engineering in complexity and design, and therefore should be called `software engineering`. Her careful design of the landing system's redundancy capabilities is credited with saving the Apollo 11 mission from aborting during the final minutes of the historic first moon landing. - -![Margaret Hamilton](margaret-hamilton.jpg) - -> _Source: Wikipedia_ - -> “Looking back, we were the luckiest people in the world. There was no choice but to be pioneers; no time to be beginners.” -> -> — Margaret Hamilton - -## Chess Project - -We use the game of [chess](../../chess/chess.md) to help you develop and demonstrate mastery during this course. Your development work is divided into different phases. Each phase demonstrates a different architectural concept or technology. The first phases implements the rules of chess. - -After implementing the first phase of the chess project, you will rewrite the code, from the base project template, without external help or resources, during a timed exam. This demonstrates your ability to work independently under pressure. Being able to efficiently write code under a deadline is an essential skill that will prepare you for the realities of programming professionally. - -The remainder of the chess phases implement a chess server that allows multiple client player programs to connect, register users, and play games. - -![Chess game](highlight-moves.png) - -## Java - -You will use the Java programming language for all of your work in this course. Java has been a popular language for multiple decades. According to the [2025 Stack Overflow survey](https://survey.stackoverflow.co/2025/technology#most-popular-technologies), Java is used by 30% of professional developers. Java has some nice properties. It is object oriented, compiled, has garbage collection, and is strongly typed. In short, Java is a good language to help you round out your skill set and resume. - -![alt text](popularTechnologies.png) - -In order to properly learn Java, you will need to reference selected chapters of the book `Core Java for the Impatient`. This book is available for free on the Safari Books collection available through the Harold B. Lee Library. You can also reference the many resources available on the web for mastering the different concepts found in the Java programming language. - -![Java for the Impatient](CoreJavaForTheImpatient4thEdition.png) - -> [!NOTE] -> -> Note that it is critical that you reserve a significant amount of your time to learn Java outside of class. In class we focus on concepts that are needed for the projects, hard concepts, and things that tend to confuse students. It is assumed that you already learned the basics of Java on your own. - -## Enrichment Lectures - -Towards the end of the course, while you are hammering away on your chess program, the course topics will focus on additional enrichment material that you should be familiar with as a professional developer. These topics will not be reflected in your project work, but you will need to be familiar with their content since they will represent the bulk of the material covered by the final exam. These include topics such as security, concurrency, and Java command line tools. - -## Canvas - -All of the course instruction is represented on GitHub, however we use Canvas to send out notifications, submit your projects, take exams, and view your grades. - -![Canvas](canvasCourse.jpg) - -> [!IMPORTANT] -> -> Make sure you have enabled Canvas to send notifications to an email account that you monitor regularly. Failure to do this will mean that you miss important notifications that could impact your efforts and grade. - -## Well Rounded Software Engineers - -The key to learning how to be an exceptional software engineer rests in your ability to continually improve in four areas. - -![learning](essentialsLearning.png) - -1. **`Capable`** - You need to know the technology. The better you know it the better you will be able to leverage its abilities and apply it correctly. Knowing who the experts are, and discerning between meaningful technology and fads, driven by marketeers, allows you to quickly find the valuable and avoid the distractions. Knowing technology will enable you to find the right tool for the job, maximize its performance, and automate its execution. -1. **`Creative`** - We often think of artistic skills when considering creativity. However, there is just as much art in making software usable, efficient, and maintainable. Knowing how to organize and sculpt your code is incredibly creative. Well designed systems are often referred to as beautiful or elegant, and a reflection of the creativity of their authors. -1. **`Collaborative`** - Web applications are rarely created and used by one person. Usually you build an application for a large group of customers, and they almost always are created by a team of contributors with different backgrounds and roles. The ability for that team to work together and interact with customers is essential. These are social skills. The more skilled you are at talking, writing, reading, presenting, expressing body language, projecting a good appearance, and most importantly, listening, the more successful you will be. -1. **`Curious`** - Having a mind that is always questioning will make all the difference. Simply doing the job is not enough. Wanting to know why the job is useful, searching for alternative directions, digging into the inner workings of a black box, and questioning accepted facts are all where progress is made. Cultivating a love for life long learning will take you from adequate to exceptional. - -> “When hiring we look for the ability to collaborate, creativity, curiosity, and expertise” -> -> — Tim Cook, ([source](https://appleinsider.com/articles/22/10/03/if-you-want-to-work-for-apple-you-need-these-four-traits)) - -## Thinking Celestial - -By developing and utilizing software engineering skills you can have a significant impact for good. However, you can take this to a whole new level by learning additional principles. - -1. **Divine Inspiration** - Seeking for divine help and direction in your efforts, enables you to avoid paths that would otherwise diminish your impact, and instead create results that otherwise would have been beyond your abilities. -1. **Eternal Perspective** - If you look beyond a project due date, problem to solve, diploma, employer, career, or even this mortal existence, you will find your focus gravitating towards a purpose that is guided by the eternal rather than the moment. - -As you learn to tap into these two principles, you will find greater motivation and enjoyment in your efforts to acquire and apply your skills as a software engineer. Make sure you emphasis being `Christlike` when making your journey through life. - -> “The temple is a place of revelation. There you are shown how to progress toward a celestial life. There you are drawn closer to the Savior and given greater access to His power. There you are guided in solving the problems in your life, even your most perplexing problems.” -> -> — President Russell M. Nelson, ([source](https://www.churchofjesuschrist.org/study/general-conference/2023/10/51nelson)) - -## Making mistakes - -Making mistakes is a key component for learning. Recognizing and embracing the power of making mistakes will help you learn faster, and at a deeper level. Just decide that you are going to make mistakes and that is fine, even preferable. Many of the most important discoveries of all time were a result of making and understanding mistakes. No one learns to walk without falling down. With that said, you should acquire a framework where you can make mistakes while minimizing their ability to slow your progress. Things such as version repositories, notebooks, simulations, working with peers, automation, and reproducibility are all useful for safely making mistakes. - -Whenever you approach something new, approach it with the attitude that you will learn by making mistakes. This will keep them from being a barrier to your progress. - -> “To make no mistakes is not in the power of man; but from their errors and mistakes the wise and good learn wisdom for the future.” -> -> — Plutarch - -## Mastery Demonstration - -Your mastery of advanced software construction is demonstrated by the following three areas and percentages. - -| Area | Percentage | -| ------------ | ---------- | -| Chess | 90% | -| Phase 0 exam | 5% | -| Final exam | 5% | - -More important than the actual grade you receive from this course is the degree to which you stretch yourself. Software construction is an area that takes decades of effort to master. If you approach this subject matter intentionally, with effort and curiosity, you will find your value as a software engineer greatly increased. - -Take the time during the course to dive deeper into topics that you find interesting. Learn from external sources and gain a wide perspective of understanding. Question what is being taught and seek to find a better way to construct software. With this attitude, **you** might be the next leader of a new revolution in software construction. - -## Videos - -- 🎥 [Course Overview (10:34)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=080df794-9d59-426b-b7c8-b19c0109e6f1) - [[transcript]](https://github.com/user-attachments/files/17738690/CS_240_Course_Overview_Transcript.pdf) -- 🎥 [Course Policies (14:19)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=ac43c852-5712-4dca-9003-b19c010d56e7) - [[transcript]](https://github.com/user-attachments/files/17738697/CS_240_Course_Policies_Transcript.pdf) -- 🎥 [Keys to Success (5:53)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=4eba6882-83ff-4e95-b498-b19c0111a009) - [[transcript]](https://github.com/user-attachments/files/17738704/CS_240_Keys_to_Success_in_CS_240_Transcript.pdf) -- 🎥 [Github Site Review (14:29)](https://byu.hosted.panopto.com/Panopto/Pages/Viewer.aspx?id=07624a65-7b70-4198-904b-b19c0113f64a) - [[transcript]](https://github.com/user-attachments/files/17738706/CS_240_Github_Site_Review_Transcript.pdf) diff --git a/instruction/introduction/margaret-hamilton.jpg b/instruction/introduction/margaret-hamilton.jpg deleted file mode 100644 index 574d30da..00000000 Binary files a/instruction/introduction/margaret-hamilton.jpg and /dev/null differ diff --git a/instruction/introduction/popularTechnologies.png b/instruction/introduction/popularTechnologies.png deleted file mode 100644 index 8e2f2607..00000000 Binary files a/instruction/introduction/popularTechnologies.png and /dev/null differ diff --git a/instruction/io/InputOutputClasses.jpg b/instruction/io/InputOutputClasses.jpg deleted file mode 100644 index 98791206..00000000 Binary files a/instruction/io/InputOutputClasses.jpg and /dev/null differ diff --git a/instruction/io/diagrams.uml b/instruction/io/diagrams.uml deleted file mode 100644 index fcfa4e23..00000000 --- a/instruction/io/diagrams.uml +++ /dev/null @@ -1,18 +0,0 @@ -# https://mermaid.live/edit - -classDiagram - OutputStream <|-- ObjectOutputStream - InputStream <|-- ByteArrayInputStream - - class InputStream{ - read() byte - } - class OutputStream{ - write(byte) - } - class ObjectOutputStream{ - writeObject(Object) - } - class ByteArrayInputStream { - ByteArrayInputStream(byte[]) - } diff --git a/instruction/io/example-code/Compress.java b/instruction/io/example-code/Compress.java deleted file mode 100644 index 3bb09040..00000000 --- a/instruction/io/example-code/Compress.java +++ /dev/null @@ -1,49 +0,0 @@ -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.zip.GZIPOutputStream; - -public class Compress { - - private static final int CHUNK_SIZE = 512; - - public static void main(String[] args) { - Compress compress = new Compress(); - - if(args.length == 2) { - try { - compress.compressFile(args[0], args[1]); - } catch (IOException e) { - e.printStackTrace(); - } - } else { - compress.usage(); - } - } - - public void compressFile(String inputFilePath, String outputFilePath) throws IOException { - File inputFile = new File(inputFilePath); - File outputFile = new File(outputFilePath); - - try(FileInputStream fis = new FileInputStream(inputFile); - BufferedInputStream bis = new BufferedInputStream(fis); - - FileOutputStream fos = new FileOutputStream(outputFile); - BufferedOutputStream bos = new BufferedOutputStream(fos); - GZIPOutputStream zipos = new GZIPOutputStream(bos)) { - - byte [] chunk = new byte[CHUNK_SIZE]; - int bytesRead; - while((bytesRead = bis.read(chunk)) > 0) { - zipos.write(chunk, 0, bytesRead); - } - } - } - - private void usage() { - System.out.println("\nUSAGE: java Compress "); - } -} \ No newline at end of file diff --git a/instruction/io/example-code/CopyFileExample.java b/instruction/io/example-code/CopyFileExample.java deleted file mode 100644 index b718b40e..00000000 --- a/instruction/io/example-code/CopyFileExample.java +++ /dev/null @@ -1,41 +0,0 @@ -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; - -public class CopyFileExample { - - public static void main(String [] args) throws IOException { - if(args.length != 2) { - printUsage(); - } else { - CopyFileExample fileCopier = new CopyFileExample(); - fileCopier.copy(args[0], args[1]); - } - } - - private static void printUsage() { - System.out.println("USAGE: java CopyFileExample fromFile toFile"); - } - - private void copy(String from, String to) throws IOException { - File fromFile = new File(from); - File toFile = new File(to); - - try(FileReader fr = new FileReader(fromFile); - BufferedReader br = new BufferedReader(fr); - - FileWriter fw = new FileWriter(toFile); - BufferedWriter bw = new BufferedWriter(fw); - PrintWriter pw = new PrintWriter(bw)) { - - String line; - while((line = br.readLine()) != null) { - pw.println(line); - } - } - } -} diff --git a/instruction/io/example-code/Decompress.java b/instruction/io/example-code/Decompress.java deleted file mode 100644 index de3e135f..00000000 --- a/instruction/io/example-code/Decompress.java +++ /dev/null @@ -1,49 +0,0 @@ -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.zip.GZIPInputStream; - -public class Decompress { - - private static final int CHUNK_SIZE = 512; - - public static void main(String[] args) { - Decompress compress = new Decompress(); - - if(args.length == 2) { - try { - compress.decompressFile(args[0], args[1]); - } catch (IOException e) { - e.printStackTrace(); - } - } else { - compress.usage(); - } - } - - public void decompressFile(String inputFilePath, String outputFilePath) throws IOException { - File inputFile = new File(inputFilePath); - File outputFile = new File(outputFilePath); - - try(FileInputStream fis = new FileInputStream(inputFile); - BufferedInputStream bis = new BufferedInputStream(fis); - GZIPInputStream zipis = new GZIPInputStream(bis); - - FileOutputStream fos = new FileOutputStream(outputFile); - BufferedOutputStream bos = new BufferedOutputStream(fos)) { - - byte [] chunk = new byte[CHUNK_SIZE]; - int bytesRead; - while((bytesRead = zipis.read(chunk)) > 0) { - bos.write(chunk, 0, bytesRead); - } - } - } - - private void usage() { - System.out.println("\nUSAGE: java Compress "); - } -} \ No newline at end of file diff --git a/instruction/io/example-code/LegacyCompress.java b/instruction/io/example-code/LegacyCompress.java deleted file mode 100644 index a9d34dec..00000000 --- a/instruction/io/example-code/LegacyCompress.java +++ /dev/null @@ -1,61 +0,0 @@ -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.zip.GZIPOutputStream; - -public class LegacyCompress { - - private static final int CHUNK_SIZE = 512; - - public static void main(String[] args) { - LegacyCompress compress = new LegacyCompress(); - - if(args.length == 2) { - try { - compress.compressFile(args[0], args[1]); - } catch (IOException e) { - e.printStackTrace(); - } - } else { - compress.usage(); - } - } - - public void compressFile(String inputFilePath, String outputFilePath) throws IOException { - File inputFile = new File(inputFilePath); - File outputFile = new File(outputFilePath); - - BufferedInputStream bis = null; - GZIPOutputStream zipos = null; - - try { - FileInputStream fis = new FileInputStream(inputFile); - bis = new BufferedInputStream(fis); - - FileOutputStream fos = new FileOutputStream(outputFile); - BufferedOutputStream bos = new BufferedOutputStream(fos); - zipos = new GZIPOutputStream(bos); - - byte[] chunk = new byte[CHUNK_SIZE]; - int bytesRead; - while ((bytesRead = bis.read(chunk)) > 0) { - zipos.write(chunk, 0, bytesRead); - } - } finally { - if(bis != null) { - bis.close(); - } - - if(zipos != null) { - zipos.close(); - } - } - } - - private void usage() { - System.out.println("\nUSAGE: java LegacyCompress "); - } -} \ No newline at end of file diff --git a/instruction/io/example-code/LegacyDecompress.java b/instruction/io/example-code/LegacyDecompress.java deleted file mode 100644 index f7fb932a..00000000 --- a/instruction/io/example-code/LegacyDecompress.java +++ /dev/null @@ -1,62 +0,0 @@ -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; - -public class LegacyDecompress { - - private static final int CHUNK_SIZE = 512; - - public static void main(String[] args) { - LegacyDecompress compress = new LegacyDecompress(); - - if(args.length == 2) { - try { - compress.decompressFile(args[0], args[1]); - } catch (IOException e) { - e.printStackTrace(); - } - } else { - compress.usage(); - } - } - - public void decompressFile(String inputFilePath, String outputFilePath) throws IOException { - File inputFile = new File(inputFilePath); - File outputFile = new File(outputFilePath); - - GZIPInputStream zipis = null; - BufferedOutputStream bos = null; - - try { - FileInputStream fis = new FileInputStream(inputFile); - BufferedInputStream bis = new BufferedInputStream(fis); - zipis = new GZIPInputStream(bis); - - FileOutputStream fos = new FileOutputStream(outputFile); - bos = new BufferedOutputStream(fos); - - byte[] chunk = new byte[CHUNK_SIZE]; - int bytesRead; - while ((bytesRead = zipis.read(chunk)) > 0) { - bos.write(chunk, 0, bytesRead); - } - } finally { - if(zipis != null) { - zipis.close(); - } - - if(bos != null) { - bos.close(); - } - } - } - - private void usage() { - System.out.println("\nUSAGE: java LegacyCompress "); - } -} \ No newline at end of file diff --git a/instruction/io/example-code/ScannerExample1.java b/instruction/io/example-code/ScannerExample1.java deleted file mode 100644 index 64b7f6a2..00000000 --- a/instruction/io/example-code/ScannerExample1.java +++ /dev/null @@ -1,30 +0,0 @@ -import java.io.File; -import java.io.FileNotFoundException; -import java.util.Scanner; - -public class ScannerExample1 { - public static void main(String[] args) throws FileNotFoundException { - ScannerExample1 scannerExample = new ScannerExample1(); - - if(args.length == 1) { - scannerExample.processFile(args[0]); - } else { - scannerExample.usage(); - } - } - - public void processFile(String filePath) throws FileNotFoundException { - File file = new File(filePath); - - try(Scanner scanner = new Scanner(file)) { - while (scanner.hasNext()) { - String str = scanner.next(); - System.out.println(str); - } - } - } - - private void usage() { - System.out.println("\nUSAGE: java ScannerExample2 "); - } -} diff --git a/instruction/io/example-code/ScannerExample2.java b/instruction/io/example-code/ScannerExample2.java deleted file mode 100644 index 9193c23a..00000000 --- a/instruction/io/example-code/ScannerExample2.java +++ /dev/null @@ -1,32 +0,0 @@ -import java.io.File; -import java.io.FileNotFoundException; -import java.util.Scanner; - -public class ScannerExample2 { - public static void main(String[] args) throws FileNotFoundException { - ScannerExample2 scannerExample = new ScannerExample2(); - - if(args.length == 1) { - scannerExample.processFile(args[0]); - } else { - scannerExample.usage(); - } - } - - public void processFile(String filePath) throws FileNotFoundException { - File file = new File(filePath); - - try(Scanner scanner = new Scanner(file)) { - scanner.useDelimiter("((#[^\\n]*\\n)|(\\s+))+"); - - while (scanner.hasNext()) { - String str = scanner.next(); - System.out.println(str); - } - } - } - - private void usage() { - System.out.println("\nUSAGE: java ScannerExample2 "); - } -} diff --git a/instruction/io/io.md b/instruction/io/io.md index 3952d3b4..400020c2 100644 --- a/instruction/io/io.md +++ b/instruction/io/io.md @@ -34,7 +34,30 @@ At the lowest level, Java represents I/O with a data abstraction known as a stre The two base classes for dealing with Streams in Java are [InputStream](https://docs.oracle.com/javase/20/docs/api/java/io/InputStream.html) and [OutputStream](https://docs.oracle.com/javase/20/docs/api/java/io/OutputStream.html). You read data from an `InputStream` and your write data to an `OutputStream`. Both of these classes are abstract classes and require some subclass in order to use their functionality. For example, you can use a `FileInputStream` to read bytes of data from a file. Likewise you can use a `FileOutputStream` to write data to a file. Other subclasses include `ByteArrayOutputStream`, `ObjectOutputStream`, `SequenceInputStream`, or `StringBufferInputStream`. -![Input Output Classes](InputOutputClasses.jpg) +```mermaid +classDiagram +%%{init: { 'theme': 'neutral', 'themeVariables': { 'lineColor': '#000000', 'primaryTextColor': '#000000', 'actorBorder': '#000000', 'participantBorder': '#000000', 'noteBorderColor': '#000000' } }}%% + + + class OutputStream { + +write(byte) + } + + class ObjectOutputStream { + +writeObject(Object) + } + + class InputStream { + +read() byte + } + + class ByteArrayInputStream { + +ByteArrayInputStream(byte[]) + } + + OutputStream <|-- ObjectOutputStream + InputStream <|-- ByteArrayInputStream +``` ## System Out and In diff --git a/instruction/object-oriented-design/classRelationshipDiagram.jpg b/instruction/object-oriented-design/classRelationshipDiagram.jpg deleted file mode 100644 index 89c2e331..00000000 Binary files a/instruction/object-oriented-design/classRelationshipDiagram.jpg and /dev/null differ diff --git a/instruction/object-oriented-design/object-oriented-design.md b/instruction/object-oriented-design/object-oriented-design.md index 4bb547fe..afc98b76 100644 --- a/instruction/object-oriented-design/object-oriented-design.md +++ b/instruction/object-oriented-design/object-oriented-design.md @@ -6,7 +6,15 @@ `Object Oriented` design focuses on describing objects in the application domain as literal programming constructs. That means if your application contains people who eat fruit. Then you model the application by creating a `Person` and `Fruit` object. Those objects will have properties such as name, ripeness, and color. The objects will also have operations such as eat, plant, grow, or purchase. You then write your code as real world interactions between the core application domain objects. To continue our example, you would have interactions where a `Person` will either `plant`, or `purchase`, a `Fruit` object and then `eat` the fruit. -![Person Fruit Model](personFruitModel.jpg) +```mermaid +%%{init: { 'theme': 'neutral', 'themeVariables': { 'lineColor': '#000000', 'primaryTextColor': '#000000', 'actorBorder': '#000000', 'participantBorder': '#000000', 'noteBorderColor': '#000000' } }}%% + +sequenceDiagram + Person->>Fruit:plant + Fruit-->>Fruit:grow + Person->>Fruit:isRipe + Person->>Fruit:eat +``` > Eating fruit sequence diagram @@ -32,7 +40,48 @@ In order to fully model the real world with your objects, you need to describe t The following is an example of the relationships between a number of objects. Note that there are many ways that you can represent the real world with object oriented design. -![Class Diagram](classRelationshipDiagram.jpg) +```mermaid +%%{init: { 'theme': 'neutral', 'themeVariables': { 'lineColor': '#000000', 'primaryTextColor': '#000000', 'actorBorder': '#000000', 'participantBorder': '#000000', 'noteBorderColor': '#000000' } }}%% + + +classDiagram + + class Car { + +travel(Person, Route) + } + + class Programmer { + +GitHubRepo + +Computer + +writeCode() + } + + class Computer { + +type + +save(code) + +run(code) + } + + class Person { + +name + +birthPlace + } + + class GitHubRepo { + +push() + +pull() + } + + class Route + + Car ..> Route : uses-a + Car ..> Person : uses-a + + Programmer --|> Person : is-a + + Programmer o-- Computer : has-a + Programmer o-- GitHubRepo : has-a +``` The key is to understand your domain and distill the important object fields, operations, and interactions down to the minimal representation that meets the application needs. That might mean that your model doesn't perfectly fit real world objects, but you can often make your model easier to use and understand if you skip some of the important details. Likewise, sometimes the most literal domain representation does not fit the model of how users interact with their domain. When that happens, go with the users. It is their mental model you are trying to represent. @@ -58,11 +107,40 @@ Of course you can simplify too far and end up with thousands of classes that eac **Too many classes** -![Verbose Object](verboseObject.png) +```mermaid +%%{init: { 'theme': 'neutral', 'themeVariables': { 'lineColor': '#000000', 'primaryTextColor': '#000000', 'actorBorder': '#000000', 'participantBorder': '#000000', 'noteBorderColor': '#000000' } }}%% + + +classDiagram + object <|-- Organism + Organism <|-- Animal + Animal <|-- Mammal + Mammal <|-- Person + + Animal *-- Soul : has-a + Animal *-- Body : has-a + + Body *-- Head : has-a + Body *-- Torso : has-a + Body *-- Appendage : has-a + + Appendage *-- Leg : has-a + Appendage *-- Arm : has-a +``` **Not enough classes** -![Ultimate Object](ultimateObject.jpg) +```mermaid +%%{init: { 'theme': 'neutral', 'themeVariables': { 'lineColor': '#000000', 'primaryTextColor': '#000000', 'actorBorder': '#000000', 'participantBorder': '#000000', 'noteBorderColor': '#000000' } }}%% + + +classDiagram + class Object { + +value + } + + Object --> Object : has-a +``` ## Things to Understand diff --git a/instruction/object-oriented-design/personFruitModel.jpg b/instruction/object-oriented-design/personFruitModel.jpg deleted file mode 100644 index 607a1239..00000000 Binary files a/instruction/object-oriented-design/personFruitModel.jpg and /dev/null differ diff --git a/instruction/object-oriented-design/ultimateObject.jpg b/instruction/object-oriented-design/ultimateObject.jpg deleted file mode 100644 index 134093d5..00000000 Binary files a/instruction/object-oriented-design/ultimateObject.jpg and /dev/null differ diff --git a/instruction/object-oriented-design/verboseObject.png b/instruction/object-oriented-design/verboseObject.png deleted file mode 100644 index 80631d9a..00000000 Binary files a/instruction/object-oriented-design/verboseObject.png and /dev/null differ diff --git a/schedule/archive/fall2024-wilkerson.md b/schedule/archive/fall2024-wilkerson.md deleted file mode 100644 index 23a969b8..00000000 --- a/schedule/archive/fall2024-wilkerson.md +++ /dev/null @@ -1,32 +0,0 @@ -# Fall 2024 Schedule - Dr. Wilkerson - -| Week | Day | Date | Discussion Topics | Video Lecture Topics | Deliverable | -| :--: | :-: | ---------- | ----------------------------------------------------------------- | ------------------------------- | ---------------------------------------- | -| 1 | 1 | Thu Sep 5 | [Introduction](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/introduction/introduction.md)
[Git](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/git/git.md)
[Chess GitHub Repository](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/chess-github-repository/chess-github-repository.md) | [Git](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/git/git.md)
(Watch the last 8 videos, starting with "Basic Git Commands") | _Due: Sep 6_ - [Chess GitHub Repository](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/chess-github-repository/chess-github-repository.md) | -| 2 | 2 | Tue Sep 10 | [Java Fundamentals](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/java-fundamentals/java-fundamentals.md)
[`Phase 0: Chess Moves`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/0-chess-moves/chess-moves.md) | | | -| | 3 | Thu Sep 12 | [Java Fundamentals (continued)](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/java-fundamentals/java-fundamentals.md)
[Classes and Objects](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/classes-and-objects/classes-and-objects.md) | | | -| 3 | 4 | Tue Sep 17 | [Classes and Objects (continued)](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/classes-and-objects/classes-and-objects.md)
| [Classes and Objects](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/classes-and-objects/classes-and-objects.md)
(Whatever we didn't cover in class) | | -| | 5 | Thu Sep 19 | [Records](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/records/records.md)
[`Programming Exam`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/programming-exam/programming-exam.md)
[Exceptions](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/exceptions/exceptions.md) | [Interfaces and Abstract Classes](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/interfaces-abstract-classes/interfaces-and-abstract-classes.md)
(6 videos - 30:44) | _Due: Sep 20_ - [Phase 0: Chess Moves](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/0-chess-moves/chess-moves.md) | -| 4 | 6 | Tue Sep 24 | [Collections](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/collections/collections.md)
[Copying Objects](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/copying-objects/copying-objects.md) | | _Due: Sep 24_ - [Programming Exam](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/programming-exam-review/programming-exam-review.md) | -| | 7 | Thu Sep 26 | [Inner Classes](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/inner-classes/inner-classes.md)
[`Phase 1: Chess Game`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/1-chess-game/chess-game.md)
[Design Principles](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/design-principles/design-principles.md) | | | -| 5 | 8 | Tue Oct 1 | [Input/Output](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/io/io.md) | | _Due: Oct 1_ - [Programming Exam - 1st Retake](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/programming-exam-review/programming-exam-review.md) (if needed) | -| | 9 | Thu Oct 3 | [JSON & Serialization](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/json/json.md)
[`Phase 2: Chess Design`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/2-server-design/server-design.md) | [Generics](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/generics/generics.md) (3 videos - 12:48)
[Lambdas](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/lambdas/lambdas.md) (8 videos - 34:42) | _Due: Oct 4_ - [Phase 1: Chess Game](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/1-chess-game/chess-game.md) | -| 6 | 10 | Tue Oct 8 | [HTTP](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/http/http.md)
[Curl](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/curl/curl.md) | | _Due: Oct 9_ - [Phase 2: Chess Design](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/2-server-design/server-design.md) | -| | 11 | Thu Oct 10 | [Web API](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/web-api/web-api.md)
[`Phase 3: Chess Web-API`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/3-web-api/web-api.md) | | | -| 7 | 12 | Tue Oct 15 | [Writing Quality Code](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/quality-code/quality-code.md)
[Code Style Checker](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/style-checker/style-checker.md) | | | -| | 13 | Thu Oct 17 | [Unit Testing](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/unit-testing/unit-testing.md)
[Code Coverage](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/code-coverage/code-coverage.md) | | | -| 8 | 14 | Tue Oct 22 | [Relational Databases: Model](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/db-model/db-model.md)
[Relational Databases: SQL](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/db-sql/db-sql.md)| | _Due: Oct 22_ - [Phase 3: Chess Web-API](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/3-web-api/web-api.md) | -| | 15 | Thu Oct 24 | [Relational Databases: JDBC](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/db-jdbc/db-jdbc.md)
[`Phase 4: Chess Database`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/4-database/database.md) | | | -| 9 | 16 | Tue Oct 29 | [MySQL](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/mysql/mysql.md)
[Securing Passwords](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/securing-passwords/securing-passwords.md) | | | -| | 17 | Thu Oct 31 | [Debugging](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/debugging/debugging.md) | | _Due: Nov 1_ - [Phase 4: Chess Database](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/4-database/database.md) | -| 10 | 18 | Tue Nov 5 | [Console UI](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/console-ui/console-ui.md)
[`Phase 5: Chess Pregame`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/5-pregame/pregame.md) | | | -| | 19 | Thu Nov 7 | [Client HTTP](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/web-api/web-api.md)
[Logging](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/logging/logging.md) | | | -| 11 | 20 | Tue Nov 12 | [Defensive Programming](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/defensive-programming/defensive-programming.md) | | | -| | 21 | Thu Nov 14 | [WebSocket](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/websocket/websocket.md)
[`Phase 6: Chess Gameplay`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/6-gameplay/gameplay.md) | | _Due: Nov 14_ - [Phase 5: Chess Pregame](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/5-pregame/pregame.md) | -| 12 | 22 | Tue Nov 19 | [Security: Hashing](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/computer-security/computer-security.md)
[Security: Encrypting](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/computer-security/computer-security.md) | | | -| | 23 | Thu Nov 21 | [Concurrency](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/concurrency/concurrency.md) | | _Due: Nov 22_ - [Programming Exam - 2nd Retake](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/programming-exam-review/programming-exam-review.md) (if needed)

_Nov 25_ - Withdrawal Deadline | -| 13 | | Tue Nov 26 | No Class | | | -| | | Thu Nov 28 | No Class - Thanksgiving | | | -| 14 | 25 | Tue Dec 3 | [Command-Line Builds](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/command-line-builds/command-line-builds.md) | | | -| | 26 | Thu Dec 5 | [Deploying Your Chess Server on AWS](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/aws-chess-server/aws-chess-server.md) | | _Due: Dec 5_ - [Phase 6: Chess Gameplay](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/6-gameplay/gameplay.md) | -| 15 | 27 | Tue Dec 10 | Final Exam Review | | _Dec 12 - 18_ - Final Exam | diff --git a/schedule/archive/fall2024.md b/schedule/archive/fall2024.md deleted file mode 100644 index 5d5590b1..00000000 --- a/schedule/archive/fall2024.md +++ /dev/null @@ -1,34 +0,0 @@ -# 📅 Fall 2024 Schedule - -| Week | Day | Date | Discussion Topics | Deliverable Due Dates | Slides | -| :--: | :-: | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 1 | 1 | | | | | -| | 2 | **Sept** 4/5 | [Introduction](../instruction/introduction/introduction.md), [Git](../instruction/git/git.md), [Chess GitHub Repository](../chess/chess-github-repository/chess-github-repository.md) | _Sept 6_ - Chess GitHub Repository | [Introduction](https://docs.google.com/presentation/d/1hV2h_kNk6dOdod_n4ps6Fv9iHS8QYbITv4sg27U600w) | -| 2 | 3 | 9/10 | [Java Fundamentals](../instruction/java-fundamentals/java-fundamentals.md)
[`Phase 0: Chess Moves`](../chess/0-chess-moves/chess-moves.md) | | [Java Fundamentals](https://docs.google.com/presentation/d/1SPIGPSSajy0CMh2b5nucOCAhAkXtRPkUgtewQh3tqZw) | -| | 4 | 11/12 | [Object Class](../instruction/java-object-class/java-object-class.md), [Classes and Objects](../instruction/classes-and-objects/classes-and-objects.md), [Records](../instruction/records/records.md) | | [Objects](https://docs.google.com/presentation/d/1-sGH73aNqlKM_ONUi6urI8h3buSkISBY4o1T7ph7jKw) | -| 3 | 5 | 16/17 | [Interfaces and Abstract Classes](../instruction/interfaces-abstract-classes/interfaces-and-abstract-classes.md), [Copying Objects](../instruction/copying-objects/copying-objects.md) | | [Abstraction](https://docs.google.com/presentation/d/15mC8spOF9Y_pfPlUZfEg7qH_VUB2E6rEnmBwGd_Ac2g) | -| | 6 | 18/19 | [Exceptions](../instruction/exceptions/exceptions.md), [Collections](../instruction/collections/collections.md)
[Programming Exam](../instruction/programming-exam/programming-exam.md) | _Sept 20_ - Phase 0: Chess Moves | [Collections and Exceptions](https://docs.google.com/presentation/d/14-QmgQznammEe-QbN8uvpL4OyywLdGDNeEYzxLoH62g) | -| 4 | 7 | 23/24 | [Object Oriented Design](../instruction/object-oriented-design/object-oriented-design.md), [Design Principles](../instruction/design-principles/design-principles.md) | _Sept 24_ - Programming Exam | [Design](https://docs.google.com/presentation/d/1JGnm9YViJkXa0Ic32VaLU4-pFk51o13TDfZnwkL-uJs) | -| | 8 | 25/26 | [Inner Classes](../instruction/inner-classes/inner-classes.md), [Lambdas](../instruction/lambdas/lambdas.md)
[`Phase 1: Chess Game`](../chess/1-chess-game/chess-game.md) | | [Inner Classes](https://docs.google.com/presentation/d/1PSfmZh1kLuMZHJIyuWYBogRNu9H05-ycocfdxd6rpGM) | -| 5 | 9 | 30/**Oct** 1 | [Input/Output](../instruction/io/io.md), [Generics](../instruction/generics/generics.md), [JSON & Serialization](../instruction/json/json.md) | | [IO & Generics](https://docs.google.com/presentation/d/1U8kYn3LBTQ7TOO-wMa01Dj6S4m44CA2woJcJ9Rn98M4), [Serialization](https://docs.google.com/presentation/d/1JnN0E-3P21VXCxW9Vz7Ugv2incM48brNTu8xOJRuS9Q) | -| | 10 | 2/3 | [`Phase 2: Chess Design`](../chess/2-server-design/server-design.md) | _Oct 4_ - Phase 1: Chess Game | [Chess Design](https://docs.google.com/presentation/d/1yQNr55p3nz_HvrP6fmHqinHWMf2mUnZLPtG7Mra3mE8) | -| 6 | 11 | 7/8 | [HTTP](../instruction/http/http.md), [Curl](../instruction/curl/curl.md), [Web API](../instruction/web-api/web-api.md) | | [HTTP](https://docs.google.com/presentation/d/1XhQk-BvhcdNVOpVkv16kXr07q4lJpkVbbTf62_DbYU8), [WebAPI](https://docs.google.com/presentation/d/1bACOxSEMp-kEUTf2sxFXdlg7dfNOeosq5yaSz7juC7Q) | -| | 12 | 9/10 | [Pet Shop](../petshop/petshop.md)
[`Phase 3: Chess Web-API`](../chess/3-web-api/web-api.md) | _Oct 9_ - Phase 2: Chess Design | [Petshop & Chess 3](https://docs.google.com/presentation/d/1oFyZMUqh4dYBAAi0wUtS4rGxh4czF-8E5wFFseC77LE) | -| 7 | 13 | 14/15 | [Writing Quality](../instruction/quality-code/quality-code.md), [Code Style Checker](../instruction/style-checker/style-checker.md) | | [Code Quality](https://docs.google.com/presentation/d/1BL8fSa7Evd5gdqNIpGub03YoulWM_zBIRIe9k82w5DI) | -| | 14 | 16/17 | [Unit Testing](../instruction/unit-testing/unit-testing.md), [Code Coverage](../instruction/code-coverage/code-coverage.md) | | [Testing](https://docs.google.com/presentation/d/10UAz0tZo8HXoaewgk3CDq8ACCBQPI2pmYbr6nVBvRRU) | -| 8 | 15 | 21/22 | [Relational Model](../instruction/db-model/db-model.md) | _Oct 22_ - Phase 3: Chess Web-API | [Relational Model](https://docs.google.com/presentation/d/1URzOUT09zQ1YR8vgxAsGgxnj_5KnRb6CUvhBv2RiUhk) | -| | 16 | 23/24 | [MySQL](../instruction/mysql/mysql.md), [SQL](../instruction/db-sql/db-sql.md)
[`Phase 4: Chess Database`](../chess/4-database/database.md) | | [SQL](https://docs.google.com/presentation/d/1WVLMOK4arzmqS6r2SsBRRmSvW984gIoBWiKtz7mnnUY) | -| 9 | 17 | 28/29 | [JDBC](../instruction/db-jdbc/db-jdbc.md), [Securing Passwords](../instruction/securing-passwords/securing-passwords.md) | | [JDBC](https://docs.google.com/presentation/d/1Yj9dwQUIWexTtnnSNAc64o2iRRZ7ETBIFWGxibw5rEs) | -| | 18 | 30/31 | [Console UI](../instruction/console-ui/console-ui.md), [Client HTTP](../instruction/web-api/web-api.md), [`Phase 5: Chess Pregame`](../chess/5-pregame/pregame.md) | _Nov 1_ - Phase 4: Chess Database | [Client](https://docs.google.com/presentation/d/1T6l8iPi3RhMEYnUzeftLR8mMUFkbOzIhh6PjDNUHQvo) | -| 10 | 19 | **Nov** 4/5 | [Logging](../instruction/logging/logging.md), [Debugging](../instruction/debugging/debugging.md), [Defensive Programming](../instruction/defensive-programming/defensive-programming.md) | | [Logging & Debugging](https://docs.google.com/presentation/d/1ZVp56cAxA9FX_ldNZQxXNbVmMyTW-VQHYbe_RstFmcY) | -| | 20 | 6/7 | [WebSocket](../instruction/websocket/websocket.md) | | [WebSocket](https://docs.google.com/presentation/d/19r2fC1VHMMTp7qUmRGh89swp7ZLgf3JcOUkEXIndKMg) | -| 11 | 21 | 11/12 | [`Phase 6: Chess Gameplay`](../chess/6-gameplay/gameplay.md) | | [Gameplay](https://docs.google.com/presentation/d/1xXsH2eCmbI0n6xW0Q6ClyXy2p5ZnaKf0nbOBuNN_exw) | -| | 22 | 13/14 | [Computer Security](../instruction/computer-security/computer-security.md) | _Nov 14_ - Phase 5: Chess Pregame | [Hashing](https://docs.google.com/presentation/d/1mWgXs0u2Lr7ducLhPEALvu3DlINNzMY_ZZk0NGoku58), [Encryption](https://docs.google.com/presentation/d/1rXrgWisZYZKIXz5Mh1t7PUA8mMNYL6e0ovY8hldKnLA) | -| 12 | 23 | 18/19 | **NO CLASS** | | | -| | 24 | 20/21 | **NO CLASS** | | | -| 13 | 25 | 25/26 | _Thanksgiving_ **NO CLASS** | | | -| | 26 | 27/28 | _Thanksgiving_ **NO CLASS** | | | -| 14 | 27 | **Dec** 2/3 | [Concurrency](../instruction/concurrency/concurrency.md) | | [Concurrency](https://docs.google.com/presentation/d/1OcH2XYen-U0f1sBAxaaCswwzp_OergGhq7b9mopszRM) | -| | 28 | 4/5 | [Command line tools](../instruction/command-line-builds/command-line-builds.md) | _Dec 5_ - Phase 6: Chess Gameplay | [Maven](https://docs.google.com/presentation/d/1zgt9rpNWEpgxkP-FQ1wXsEFA8974AV3oElUXlUZZaZo) | -| 15 | 29 | 9/10 | Protips, [Final Exam Review](../instruction/final-exam-review/final-exam-review.md) | | [Protips](https://docs.google.com/presentation/d/1HitFGYCbV01poP2Ib2FzhPMGxiYFRtZNu2UmUrSqTOM) | -| | | 11 | | _Dec 12-18_ - Final | | diff --git a/schedule/archive/fall2025-rodham.md b/schedule/archive/fall2025-rodham.md deleted file mode 100644 index 2f616bbe..00000000 --- a/schedule/archive/fall2025-rodham.md +++ /dev/null @@ -1,37 +0,0 @@ -# Fall 2025 Schedule - Dr. Rodham - -This schedule applies to all of Dr. Rodham's CS 240 sections (blended/in-person and online). For blended/in-person sections, the "Video Lecture Topics" column lists lecture topics that will not be covered in class. Students will need to watch the videos on these topics. Entries in this column may be updated throughout the semester depending on how far we get in in-class lectures. - -Students in online sections should watch all videos for all topics, including those listed under "Discussion Topics" and any additional topics listed under "Video Lecture Topics". - - -| Week | Day | Date | Discussion Topics | Video Lecture Topics | Deliverable | -| :--: | :-: | ---------- | ----------------------------------------------------------------- | ------------------------------- | ---------------------------------------- | -| 1 | 1 | Thu Sep 4 | [Introduction](../instruction/introduction/introduction.md)
[Git](../instruction/git/git.md)
[Chess GitHub Repository](../chess/chess-github-repository/chess-github-repository.md) | [Git](../instruction/git/git.md)
(Watch the last 8 videos, starting with "Basic Git Commands") | _Due: Fri Sep 5_ - [Chess GitHub Repository](../chess/chess-github-repository/chess-github-repository.md) and Honorlock Setup | -| 2 | 2 | Tue Sep 9 | [Java Fundamentals](../instruction/java-fundamentals/java-fundamentals.md)
[`Phase 0: Chess Moves`](../chess/0-chess-moves/chess-moves.md) | | | -| | 3 | Thu Sep 11 | [Java Fundamentals (continued)](../instruction/java-fundamentals/java-fundamentals.md)
[Classes and Objects](../instruction/classes-and-objects/classes-and-objects.md) | [Classes and Objects](../instruction/classes-and-objects/classes-and-objects.md)
(Whatever we didn't cover in class) | | -| 3 | 4 | Tue Sep 16 | [`Programming Exam`](../instruction/programming-exam/programming-exam.md)
[Records](../instruction/records/records.md)
[Interfaces and Abstract Classes](../instruction/interfaces-abstract-classes/interfaces-and-abstract-classes.md)
| [Interfaces and Abstract Classes](../instruction/interfaces-abstract-classes/interfaces-and-abstract-classes.md)
(Whatever we didn't cover in class) | | -| | 5 | Thu Sep 18 | [Copying Objects](../instruction/copying-objects/copying-objects.md)
[Exceptions](../instruction/exceptions/exceptions.md) | | _Due: Fri Sep 19_ - [Phase 0: Chess Moves](../chess/0-chess-moves/chess-moves.md) | -| 4 | 6 | Tue Sep 23 |[`Phase 1: Chess Game`](../chess/1-chess-game/chess-game.md)
[Collections](../instruction/collections/collections.md)
[Inner Classes](../instruction/inner-classes/inner-classes.md)
| | _Due: Tue Sep 23_ - [Programming Exam](../instruction/programming-exam/programming-exam.md) | -| | 7 | Thu Sep 25 | [Generics](../instruction/generics/generics.md)
[Lambdas](../instruction/lambdas/lambdas.md)
[Input/Output](../instruction/io/io.md)
| [Generics](../instruction/generics/generics.md)
(Whatever we didn't cover in class)
[Lambdas](../instruction/lambdas/lambdas.md)
(Whatever we didn't cover in class) | | -| 5 | 8 | Tue Sep 30 | [JSON & Serialization](../instruction/json/json.md)
[Design Principles](../instruction/design-principles/design-principles.md) | | | -| | 9 | Thu Oct 2 | [`Phase 2: Chess Design`](../chess/2-server-design/server-design.md)
| | _Due: Fri Oct 3_ - [Phase 1: Chess Game](../chess/1-chess-game/chess-game.md) | -| 6 | 10 | Tue Oct 7 | [HTTP](../instruction/http/http.md)
[Curl](../instruction/curl/curl.md)
| | _Due: Tue Oct 7_ - [Programming Exam - 1st Retake](../instruction/programming-exam/programming-exam.md) (if needed)
_Due: Wed Oct 8_ - [Phase 2: Chess Design](../chess/2-server-design/server-design.md) | -| | 11 | Thu Oct 9 | [Web API](../instruction/web-api/web-api.md)
[`Phase 3: Chess Web-API`](../chess/3-web-api/web-api.md) | | | -| 7 | 12 | Tue Oct 14 | [Unit Testing](../instruction/unit-testing/unit-testing.md)
[Code Coverage](../instruction/code-coverage/code-coverage.md) | | | -| | 13 | Thu Oct 16 | [Writing Quality Code](../instruction/quality-code/quality-code.md)
[Code Style Checker](../instruction/style-checker/style-checker.md) | | | -| 8 | 14 | Tue Oct 21 | [Relational Databases: Model](../instruction/db-model/db-model.md)
[Relational Databases: SQL](../instruction/db-sql/db-sql.md)| | _Due: Wed Oct 22_ - [Phase 3: Chess Web-API](../chess/3-web-api/web-api.md) | -| | 15 | Thu Oct 23 | [Relational Databases: JDBC](../instruction/db-jdbc/db-jdbc.md)
[`Phase 4: Chess Database`](../chess/4-database/database.md) | | | -| 9 | 16 | Tue Oct 28 | [MySQL](../instruction/mysql/mysql.md)
[Securing Passwords](../instruction/securing-passwords/securing-passwords.md) | | | -| | 17 | Thu Oct 30 | [Debugging](../instruction/debugging/debugging.md)
[Logging](../instruction/logging/logging.md)
[Defensive Programming](../instruction/defensive-programming/defensive-programming.md)
| | _Due: Fri Oct 31_ - [Phase 4: Chess Database](../chess/4-database/database.md) | -| 10 | 18 | Tue Nov 4 | [`Phase 5: Chess Pregame`](../chess/5-pregame/pregame.md)
[Console UI](../instruction/console-ui/console-ui.md)
[Client HTTP](../instruction/web-api/web-api.md)
| | | -| | 19 | Thu Nov 6 | [Security: Hashing](../instruction/computer-security/computer-security.md)
| | | -| 11 | 20 | Tue Nov 11 | No Class - Work on Phase 5 | | | -| | 21 | Thu Nov 13 | [WebSocket](../instruction/websocket/websocket.md)
[`Phase 6: Chess Gameplay`](../chess/6-gameplay/gameplay.md) | | _Due: Fri Nov 14_ - [Phase 5: Chess Pregame](../chess/5-pregame/pregame.md) | -| 12 | 22 | Tue Nov 18 | [Security: Encryption](../instruction/computer-security/computer-security.md) | | | -| | 23 | Thu Nov 20 | [Concurrency](../instruction/concurrency/concurrency.md) | | _Due: Thu Nov 20_ - [Programming Exam - 2nd Retake](../instruction/programming-exam/programming-exam.md) (if needed)

| -| 13 | 24 | Tue Nov 25 | Flex Day
(Catch up if needed) | | _Mon Nov 24_ - Withdrawal Deadline | -| | | Thu Nov 27 | No Class - Holiday | | | -| 14 | 25 | Tue Dec 2 | [Command-Line Builds](../instruction/command-line-builds/command-line-builds.md)
[Deploying Your Chess Server on AWS](../instruction/aws-chess-server/aws-chess-server.md)
[Final Exam Review](../instruction/final-exam-review/final-exam-review.md)
| | | -| | 26 | Thu Dec 4 | No Class - Work on Phase 6 | | _Due: Fri Dec 5_ - [Phase 6: Chess Gameplay](../chess/6-gameplay/gameplay.md) | -| 15 | 27 | Tue Dec 9 | No Class - Work on Phase 6 | | _Dec 11 - 17_ - Final Exam | diff --git a/schedule/archive/fall2025.md b/schedule/archive/fall2025.md deleted file mode 100644 index 3f9f31b9..00000000 --- a/schedule/archive/fall2025.md +++ /dev/null @@ -1,43 +0,0 @@ -# 📅 Fall 2025 Schedule - -| Week | Day | Date | Discussion Topics | Deliverable Due Dates | Slides | -| :--: | :-: | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 1 | 1 | | | | | -| | 2 | **Sept** 3/4 | [Introduction](../instruction/introduction/introduction.md), [Git](../instruction/git/git.md), [Chess GitHub Repository](../chess/chess-github-repository/chess-github-repository.md) | _Sept 5_ - Chess GitHub Repository,
Honorlock setup | [Introduction](https://docs.google.com/presentation/d/1hV2h_kNk6dOdod_n4ps6Fv9iHS8QYbITv4sg27U600w) | -| 2 | 3 | 8/9 | [Java Fundamentals](../instruction/java-fundamentals/java-fundamentals.md)
[`Phase 0: Chess Moves`](../chess/0-chess-moves/chess-moves.md) | | [Java Fundamentals](https://docs.google.com/presentation/d/1SPIGPSSajy0CMh2b5nucOCAhAkXtRPkUgtewQh3tqZw) | -| | 4 | 10/11 | [Object Class](../instruction/java-object-class/java-object-class.md), [Classes and Objects](../instruction/classes-and-objects/classes-and-objects.md), [Records](../instruction/records/records.md) | | [Objects](https://docs.google.com/presentation/d/1-sGH73aNqlKM_ONUi6urI8h3buSkISBY4o1T7ph7jKw) | -| 3 | 5 | 15/16 | [Interfaces and Abstract Classes](../instruction/interfaces-abstract-classes/interfaces-and-abstract-classes.md), [Copying Objects](../instruction/copying-objects/copying-objects.md) | | [Abstraction](https://docs.google.com/presentation/d/15mC8spOF9Y_pfPlUZfEg7qH_VUB2E6rEnmBwGd_Ac2g) | -| | 6 | 17/18 | [Exceptions](../instruction/exceptions/exceptions.md), [Collections](../instruction/collections/collections.md)
[Programming Exam](../instruction/programming-exam/programming-exam.md) | _Sept 19_ - Phase 0: Chess Moves | [Collections and Exceptions](https://docs.google.com/presentation/d/14-QmgQznammEe-QbN8uvpL4OyywLdGDNeEYzxLoH62g) | -| 4 | 7 | 22/23 | [Object Oriented Design](../instruction/object-oriented-design/object-oriented-design.md), [Design Principles](../instruction/design-principles/design-principles.md) | _Sept 23_ - Programming Exam | [Design](https://docs.google.com/presentation/d/1JGnm9YViJkXa0Ic32VaLU4-pFk51o13TDfZnwkL-uJs) | -| | 8 | 24/25 | [Inner Classes](../instruction/inner-classes/inner-classes.md), [Lambdas](../instruction/lambdas/lambdas.md)
[`Phase 1: Chess Game`](../chess/1-chess-game/chess-game.md) | | [Inner Classes](https://docs.google.com/presentation/d/1PSfmZh1kLuMZHJIyuWYBogRNu9H05-ycocfdxd6rpGM) | -| 5 | 9 | 29/30 | [Input/Output](../instruction/io/io.md), [Generics](../instruction/generics/generics.md), [JSON & Serialization](../instruction/json/json.md) | | [IO & Generics](https://docs.google.com/presentation/d/1U8kYn3LBTQ7TOO-wMa01Dj6S4m44CA2woJcJ9Rn98M4), [Serialization](https://docs.google.com/presentation/d/1JnN0E-3P21VXCxW9Vz7Ugv2incM48brNTu8xOJRuS9Q) | -| | 10 | **Oct** 1/2 | [`Phase 2: Chess Design`](../chess/2-server-design/server-design.md) | _Oct 3_ - Phase 1: Chess Game | [Chess Design](https://docs.google.com/presentation/d/1yQNr55p3nz_HvrP6fmHqinHWMf2mUnZLPtG7Mra3mE8) | -| 6 | 11 | 6/7 | [HTTP](../instruction/http/http.md), [Curl](../instruction/curl/curl.md), [Web API](../instruction/web-api/web-api.md) | _Oct 7_ - 1st Programming Exam retake | [HTTP](https://docs.google.com/presentation/d/1XhQk-BvhcdNVOpVkv16kXr07q4lJpkVbbTf62_DbYU8), [WebAPI](https://docs.google.com/presentation/d/1bACOxSEMp-kEUTf2sxFXdlg7dfNOeosq5yaSz7juC7Q) | -| | 12 | 8/9 | [Pet Shop](../petshop/petshop.md)
[`Phase 3: Chess Web-API`](../chess/3-web-api/web-api.md) | _Oct 8_ - Phase 2: Chess Design | [Petshop & Chess 3](https://docs.google.com/presentation/d/1oFyZMUqh4dYBAAi0wUtS4rGxh4czF-8E5wFFseC77LE) | -| 7 | 13 | 13/14 | [Writing Quality](../instruction/quality-code/quality-code.md), [Code Style Checker](../instruction/style-checker/style-checker.md) | | [Code Quality](https://docs.google.com/presentation/d/1BL8fSa7Evd5gdqNIpGub03YoulWM_zBIRIe9k82w5DI) | -| | 14 | 15/16 | [Unit Testing](../instruction/unit-testing/unit-testing.md), [Code Coverage](../instruction/code-coverage/code-coverage.md) | | [Testing](https://docs.google.com/presentation/d/10UAz0tZo8HXoaewgk3CDq8ACCBQPI2pmYbr6nVBvRRU) | -| 8 | 15 | 20/21 | [Relational Model](../instruction/db-model/db-model.md), [MySQL](../instruction/mysql/mysql.md), [SQL](../instruction/db-sql/db-sql.md) | _Oct 22_ - Phase 3: Chess Web-API | [Relational Model](https://docs.google.com/presentation/d/1URzOUT09zQ1YR8vgxAsGgxnj_5KnRb6CUvhBv2RiUhk), [SQL](https://docs.google.com/presentation/d/1WVLMOK4arzmqS6r2SsBRRmSvW984gIoBWiKtz7mnnUY) | -| | 16 | 22/23 | [`Phase 4: Chess Database`](../chess/4-database/database.md), [JDBC](../instruction/db-jdbc/db-jdbc.md), [Securing Passwords](../instruction/securing-passwords/securing-passwords.md) | | [JDBC](https://docs.google.com/presentation/d/1Yj9dwQUIWexTtnnSNAc64o2iRRZ7ETBIFWGxibw5rEs) | -| 9 | 17 | 27/28 | In class help session | | | -| | 18 | 29/30 | [Console UI](../instruction/console-ui/console-ui.md), [Client HTTP](../instruction/web-api/web-api.md), [`Phase 5: Chess Pregame`](../chess/5-pregame/pregame.md) | _Oct 31_ - Phase 4: Chess Database | [Client](https://docs.google.com/presentation/d/1T6l8iPi3RhMEYnUzeftLR8mMUFkbOzIhh6PjDNUHQvo) | -| 10 | 19 | **Nov** 3/4 | [Logging](../instruction/logging/logging.md), [Debugging](../instruction/debugging/debugging.md), [Defensive Programming](../instruction/defensive-programming/defensive-programming.md) | | [Logging & Debugging](https://docs.google.com/presentation/d/1ZVp56cAxA9FX_ldNZQxXNbVmMyTW-VQHYbe_RstFmcY) | -| | 20 | 5/6 | [WebSocket](../instruction/websocket/websocket.md) | | [WebSocket](https://docs.google.com/presentation/d/19r2fC1VHMMTp7qUmRGh89swp7ZLgf3JcOUkEXIndKMg) | -| 11 | 21 | 10/11 | [`Phase 6: Chess Gameplay`](../chess/6-gameplay/gameplay.md) | | [Gameplay](https://docs.google.com/presentation/d/1xXsH2eCmbI0n6xW0Q6ClyXy2p5ZnaKf0nbOBuNN_exw) | -| | 22 | 12/13 | [Computer Security](../instruction/computer-security/computer-security.md) | _Nov 14_ - Phase 5: Chess Pregame | [Hashing](https://docs.google.com/presentation/d/1mWgXs0u2Lr7ducLhPEALvu3DlINNzMY_ZZk0NGoku58) | -| 12 | 23 | 17/18 | [Computer Security](../instruction/computer-security/computer-security.md) | | [Encryption](https://docs.google.com/presentation/d/1rXrgWisZYZKIXz5Mh1t7PUA8mMNYL6e0ovY8hldKnLA) | -| | 24 | 19/20 | In class help session | _Nov 20_ - 2nd Programming Exam retake | | -| 13 | 25 | 24/25 | _Thanksgiving_ **NO CLASS** | | | -| | 26 | 26/27 | _Thanksgiving_ **NO CLASS** | | | -| 14 | 27 | **Dec** 1/2 | [Concurrency](../instruction/concurrency/concurrency.md) | | [Concurrency](https://docs.google.com/presentation/d/1OcH2XYen-U0f1sBAxaaCswwzp_OergGhq7b9mopszRM) | -| | 28 | 3/4 | [Command line tools](../instruction/command-line-builds/command-line-builds.md) | _Dec 5_ - Phase 6: Chess Gameplay | [Maven](https://docs.google.com/presentation/d/1zgt9rpNWEpgxkP-FQ1wXsEFA8974AV3oElUXlUZZaZo) | -| 15 | 29 | 8/9 | Protips, [Final Exam Review](../instruction/final-exam-review/final-exam-review.md) | | [Protips](https://docs.google.com/presentation/d/1HitFGYCbV01poP2Ib2FzhPMGxiYFRtZNu2UmUrSqTOM), [Employment](https://docs.google.com/presentation/d/1CQD6biLpKW2SCHutBmrpwdy5tqMgpZVB_jr7vBd6qNY) | -| | | 10/11 | | _Dec 11-17_ - Final | | - -## Special days - -- **Sept 3**: First day of class -- **Nov 24**: Withdraw deadline -- **Nov 26**: No classes -- **Nov 27-28**: Holiday -- **Dec 10**: Last day of class -- **Dec 17**: Last day of finals diff --git a/schedule/archive/spring2025-wilkerson.md b/schedule/archive/spring2025-wilkerson.md deleted file mode 100644 index bd5875ff..00000000 --- a/schedule/archive/spring2025-wilkerson.md +++ /dev/null @@ -1,34 +0,0 @@ -# Spring 2025 Schedule - Dr. Wilkerson -This course is fully online with all lectures being on-demand video lectures. Videos can be found at the bottom of the lecture topic pages listed in the "Lecture Topics" column. The dates listed for lecture topics indicate where you should be in the course content on each date. Lecture topic dates are intended to help you keep pace with the course. The "Deliverable" column lists the due dates for each assignment. You will receive late penalties according to the course late policy for assignments submitted after these dates. - - -| Week | Day | Date | Lecture Topics | Deliverable | -| :-: | :-: | :-: | :-: | :-: | -| 1 | 1 | Tue Apr 29 | [Introduction](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/introduction/introduction.md)
[Git](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/git/git.md)
[Chess GitHub Repository](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/chess-github-repository/chess-github-repository.md) | | -| | 2 | Wed Apr 30 | [Java Fundamentals](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/java-fundamentals/java-fundamentals.md) | _Due: Apr 30_ - [Chess GitHub Repository](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/chess-github-repository/chess-github-repository.md)| -| | 3 | Thu May 1 | [`Phase 0: Chess Moves`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/0-chess-moves/chess-moves.md)
[Classes and Objects](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/classes-and-objects/classes-and-objects.md) | | -| 2 | 4 | Mon May 5 | [Classes and Objects (continued)](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/classes-and-objects/classes-and-objects.md)
[Records](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/records/records.md) | | -| | 5 | Tue May 6 | [`Programming Exam`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/programming-exam/programming-exam.md)
[Exceptions](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/exceptions/exceptions.md)
[Interfaces and Abstract Classes](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/interfaces-abstract-classes/interfaces-and-abstract-classes.md)| _Due: May 6_ - [Phase 0: Chess Moves](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/0-chess-moves/chess-moves.md) | -| | 6 | Wed May 7 | [Collections](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/collections/collections.md)
[Copying Objects](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/copying-objects/copying-objects.md) | | -| | 7 | Thu May 8 | [Inner Classes](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/inner-classes/inner-classes.md)
[`Phase 1: Chess Game`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/1-chess-game/chess-game.md)
[Design Principles](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/design-principles/design-principles.md) | _Due: May 8_ - [Programming Exam](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/programming-exam/programming-exam.md) | -| 3 | 8 | Mon May 12 | [Input/Output](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/io/io.md) | _Due: May 12_ - [Programming Exam - 1st Retake](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/programming-exam/programming-exam.md) (if needed) | -| | 9 | Tue May 13 | [JSON & Serialization](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/json/json.md)
[`Phase 2: Chess Design`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/2-server-design/server-design.md) | | -| | 10 | Wed May 14 | [HTTP](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/http/http.md)
[Curl](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/curl/curl.md)
[Generics](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/generics/generics.md)
[Lambdas](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/lambdas/lambdas.md) | _Due: May 14_ - [Phase 1: Chess Game](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/1-chess-game/chess-game.md) | -| | 11 | Thu May 15 | [Web API](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/web-api/web-api.md)
[`Phase 3: Chess Web-API`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/3-web-api/web-api.md) | _Due: May 16_ - [Phase 2: Chess Design](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/2-server-design/server-design.md) | -| 4 | 12 | Mon May 19 | [Writing Quality Code](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/quality-code/quality-code.md)
[Code Style Checker](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/style-checker/style-checker.md) | | -| | 13 | Tue May 20 | [Unit Testing](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/unit-testing/unit-testing.md)
[Code Coverage](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/code-coverage/code-coverage.md) | | -| | 14 | Wed May 21 | [Relational Databases: Model](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/db-model/db-model.md)
[Relational Databases: SQL](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/db-sql/db-sql.md)| _Due: May 21_ - [Phase 3: Chess Web-API](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/3-web-api/web-api.md) | -| | 15 | Thu May 22 | [Relational Databases: JDBC](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/db-jdbc/db-jdbc.md)
[`Phase 4: Chess Database`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/4-database/database.md) | | -| 5 | | Mon May 26 | Memorial Day | | -| | 16 | Tue May 27 | [MySQL](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/mysql/mysql.md)
[Securing Passwords](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/securing-passwords/securing-passwords.md) | | -| | 17 | Wed May 28 | [Debugging](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/debugging/debugging.md) | _Due: May 28_ - [Phase 4: Chess Database](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/4-database/database.md) | -| | 18 | Thu May 29 | [Console UI](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/console-ui/console-ui.md)
[`Phase 5: Chess Pregame`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/5-pregame/pregame.md) | _Due: May 30_ - [Programming Exam - 2nd Retake](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/programming-exam/programming-exam.md) (if needed) | -| 6 | 19 | Mon Jun 2 | [Client HTTP](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/web-api/web-api.md)
[Logging](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/logging/logging.md) | | -| | 20 | Tue Jun 3 | [Defensive Programming](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/defensive-programming/defensive-programming.md) | _Jun 3_ - Withdrawal Deadline | -| | 21 | Wed Jun 4 | [WebSocket](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/websocket/websocket.md)
[`Phase 6: Chess Gameplay`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/6-gameplay/gameplay.md) | _Due: Jun 4_ - [Phase 5: Chess Pregame](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/5-pregame/pregame.md) | -| | 22 | Thu Jun 5 | [Security: Hashing](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/computer-security/computer-security.md)
[Security: Encrypting](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/computer-security/computer-security.md) | | -| 7 | 23 | Mon Jun 9 | [Concurrency](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/concurrency/concurrency.md) | | -| | 24 | Tue Jun 10 | [Command-Line Builds](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/command-line-builds/command-line-builds.md) | | -| | 25 | Wed Jun 11 | [Deploying Your Chess Server on AWS](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/aws-chess-server/aws-chess-server.md) | | -| | 26 | Thu Jun 12 | [Work on Phase 6](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/6-gameplay/gameplay.md) | _Due: Jun 12_ - [Phase 6: Chess Gameplay](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/6-gameplay/gameplay.md) | -| 8 | 27 | Mon Jun 16 | [Final Exam Review](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/final-exam-review/final-exam-review.md) | _Jun 17 - 20_ - Final Exam | diff --git a/schedule/archive/summer2024-rodham.md b/schedule/archive/summer2024-rodham.md deleted file mode 100644 index b2c791de..00000000 --- a/schedule/archive/summer2024-rodham.md +++ /dev/null @@ -1,27 +0,0 @@ -# Summer 2024 Schedule - Dr. Rodham - -| Week | Day | Date | Discussion Topics | Video Lecture Topics | Deliverable | -| :--: | :-: | ---------- | ----------------------------------------------------------------- | ------------------------------- | ---------------------------------------- | -| 1 | 1 | Mon June 24 | [Introduction](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/introduction/introduction.md)
[Git](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/git/git.md)
[Chess GitHub Repository](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/chess-github-repository/chess-github-repository.md)
[Java Fundamentals](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/java-fundamentals/java-fundamentals.md) | | _Due: Tue June 25_ - [Chess GitHub Repository](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/chess-github-repository/chess-github-repository.md) | -| | 2 | Wed June 26 | [Java Fundamentals (continued)](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/java-fundamentals/java-fundamentals.md)
[`Phase 0: Chess Moves`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/0-chess-moves/chess-moves.md) | [Java Fundamentals](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/java-fundamentals/java-fundamentals.md)
(Whatever we didn't cover in class) | | -| | 3 | Fri June 28 | [Classes and Objects](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/classes-and-objects/classes-and-objects.md)
[Records](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/records/records.md) | | | -| 2 | 4 | Mon July 1 |[Interfaces and Abstract Classes](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/interfaces-abstract-classes/interfaces-and-abstract-classes.md)
[`Programming Exam`](https://byu.instructure.com/courses/24410/assignments)
[Copying Objects](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/copying-objects/copying-objects.md)| _TBA_ | _Due: Mon July 1_ - [Phase 0: Chess Moves](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/0-chess-moves/chess-moves.md) | -| | 5 | Wed July 3 | [Exceptions](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/exceptions/exceptions.md)
[Collections](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/collections/collections.md)
[Inner Classes](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/inner-classes/inner-classes.md)
[`Phase 1: Chess Game`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/1-chess-game/chess-game.md)| _TBA_ | | -| | 6 | Fri July 5 | No Class - Programming Exam | | _Due: Fri July 5_ - [Programming Exam](https://byu.instructure.com/courses/26141/assignments) | -| 3 | 7 | Mon July 8 | [Design Principles](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/design-principles/design-principles.md)
[Input/Output](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/io/io.md)
[JSON & Serialization](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/json/json.md) | | _Due: Tue July 9_ - [Programming Exam - 1st Retake](https://byu.instructure.com/courses/26141/assignments) (if needed) | -| | 8 | Wed July 10 | [`Phase 2: Chess Design`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/2-server-design/server-design.md) | _TBA_ | _Due: Thu July 11_ - [Phase 1: Chess Game](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/1-chess-game/chess-game.md) | -| | 9 | Fri July 12 | [Generics](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/generics/generics.md)
[Lambdas](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/lambdas/lambdas.md)
[HTTP](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/http/http.md)
[Curl](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/curl/curl.md) | | | -| 4 | 10 | Mon July 15 | [Web API](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/web-api/web-api.md)
[`Phase 3: Chess Web-API`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/3-web-api/web-api.md) | _TBA_ | _Due: Mon July 15_ - [Phase 2: Chess Design](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/2-server-design/server-design.md) | -| | 11 | Wed July 17 | [Writing Quality Code](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/quality-code/quality-code.md)
[Code Style Checker](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/style-checker/style-checker.md)
[Unit Testing](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/unit-testing/unit-testing.md)
[Code Coverage](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/code-coverage/code-coverage.md) | | | -| | 12 | Fri July 19 | [Relational Databases: Model](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/db-model/db-model.md)
[Relational Databases: SQL](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/db-sql/db-sql.md)
[Relational Databases: JDBC](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/db-jdbc/db-jdbc.md) | _TBA_ | | -| 5 | 13 | Mon July 22 | [MySQL](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/mysql/mysql.md)
[`Phase 4: Chess Database`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/4-database/database.md)
[Securing Passwords](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/securing-passwords/securing-passwords.md) | | _Due: Tue July 23_ - [Phase 3: Chess Web-API](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/3-web-api/web-api.md) | -| | - | Wed July 24 | No Class - Pioneer Day | | | -| | 14 | Fri July 26 | [Debugging](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/debugging/debugging.md)
[Logging](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/logging/logging.md)
[Defensive Programming](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/defensive-programming/defensive-programming.md) | | _Due: Sat July 27_ - [Programming Exam - 2nd Retake](https://byu.instructure.com/courses/26141/assignments) (if needed) | -| 6 | 15 | Mon July 29 | [Command-Line Builds](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/command-line-builds/command-line-builds.md)
[Client HTTP](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/web-api/web-api.md)
[Console UI](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/console-ui/console-ui.md)
[`Phase 5: Chess Pregame`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/5-pregame/pregame.md) | | _Tue July 30_ - Withdrawal Deadline | -| | 16 | Wed July 31 | No Class | | _Due: Wed July 31_ - [Phase 4: Chess Database](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/4-database/database.md)| -| | 17 | Fri Aug 2 | [WebSocket](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/websocket/websocket.md)
[`Phase 6: Chess Gameplay`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/6-gameplay/gameplay.md) | | | -| 7 | 18 | Mon Aug 5 | [Security: Hashing](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/computer-security/computer-security.md)
[Security: Encryption](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/computer-security/computer-security.md) | | _Due: Mon Aug 5_ - [Phase 5: Chess Pregame](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/5-pregame/pregame.md) | -| | 19 | Wed Aug 7 | [Concurrency](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/concurrency/concurrency.md) | | | -| | 20 | Fri Aug 9 | Final Exam Review
[Deploying Your Chess Server on AWS](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/aws-chess-server/aws-chess-server.md) | | | -| 8 | 21 | Mon Aug 12 | No Class - Work on Phase 6 | | _Due: Mon Aug 12_ - [Phase 6: Chess Gameplay](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/6-gameplay/gameplay.md)
_Aug 13 - 15_ - Final Exam | - diff --git a/schedule/archive/summer2025-rodham.md b/schedule/archive/summer2025-rodham.md deleted file mode 100644 index 8df224a0..00000000 --- a/schedule/archive/summer2025-rodham.md +++ /dev/null @@ -1,37 +0,0 @@ -# Summer 2025 Schedule - Dr. Rodham - -Students should watch all videos for all topics. Links to the videos are on the instruction page for each topic. - - -| Week | Date | Discussion Topics | Deliverable | -| :--: | ---------- | ----------------------------------------------------------------- | ---------------------------------------- | -| 1 | Mon Jun 23 | [Introduction](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/introduction/introduction.md)
[Git](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/git/git.md)
[Chess GitHub Repository](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/chess-github-repository/chess-github-repository.md) | | -| | Tue Jun 24 | [Java Fundamentals](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/java-fundamentals/java-fundamentals.md)
[`Phase 0: Chess Moves`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/0-chess-moves/chess-moves.md) | _Due: Tue Jun 24_ - [Chess GitHub Repository](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/chess-github-repository/chess-github-repository.md) | -| | Wed Jun 25 | [Java Fundamentals (continued)](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/java-fundamentals/java-fundamentals.md)
[Classes and Objects](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/classes-and-objects/classes-and-objects.md) | | -| | Thu Jun 26 | [`Programming Exam`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/programming-exam/programming-exam.md)
[Records](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/records/records.md)
[Interfaces and Abstract Classes](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/interfaces-abstract-classes/interfaces-and-abstract-classes.md)
| | -| 2 | Mon Jun 30 | [Copying Objects](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/copying-objects/copying-objects.md)
[Exceptions](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/exceptions/exceptions.md) | _Due: Mon Jun 30_ - [Phase 0: Chess Moves](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/0-chess-moves/chess-moves.md) | -| | Tue Jul 01 |[`Phase 1: Chess Game`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/1-chess-game/chess-game.md)
[Collections](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/collections/collections.md)
[Inner Classes](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/inner-classes/inner-classes.md)
| | -| | Wed Jul 02 | [Generics](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/generics/generics.md)
[Lambdas](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/lambdas/lambdas.md)
[Input/Output](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/io/io.md)
| _Due: **5:00 PM** on Wed Jul 02_ - [Programming Exam](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/programming-exam/programming-exam.md) | -| | Fri Jul 04 | HOLIDAY | | -| 3 | Mon Jul 07 | [JSON & Serialization](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/json/json.md)
[Design Principles](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/design-principles/design-principles.md) | _Due: Mon Jul 07_ - [Programming Exam - 1st Retake](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/programming-exam/programming-exam.md) (if needed) | -| | Tue Jul 08 | [`Phase 2: Chess Design`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/2-server-design/server-design.md)
| _Due: Tue Jul 08_ - [Phase 1: Chess Game](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/1-chess-game/chess-game.md) | -| | Wed Jul 09 | [HTTP](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/http/http.md)
[Curl](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/curl/curl.md)
| | -| | Thu Jul 10 | [Web API](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/web-api/web-api.md)
[`Phase 3: Chess Web-API`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/3-web-api/web-api.md) | | -| | Fri Jul 11 | | _Due: Fri Jul 11_ - [Phase 2: Chess Design](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/2-server-design/server-design.md) | -| 4 | Mon Jul 14 | [Unit Testing](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/unit-testing/unit-testing.md)
[Code Coverage](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/code-coverage/code-coverage.md) | | -| | Tue Jul 15 | [Writing Quality Code](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/quality-code/quality-code.md)
[Code Style Checker](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/style-checker/style-checker.md) | | -| | Wed Jul 16 | [Relational Databases: Model](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/db-model/db-model.md)
[Relational Databases: SQL](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/db-sql/db-sql.md) | _Due: Wed Jul 16_ - [Phase 3: Chess Web-API](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/3-web-api/web-api.md) | -| | Thu Jul 17 | [Relational Databases: JDBC](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/db-jdbc/db-jdbc.md)
[`Phase 4: Chess Database`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/4-database/database.md) | | -| 5 | Mon Jul 21 | [MySQL](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/mysql/mysql.md)
[Securing Passwords](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/securing-passwords/securing-passwords.md) | | -| | Tue Jul 22 | [Debugging](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/debugging/debugging.md)
[Logging](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/logging/logging.md)
[Defensive Programming](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/defensive-programming/defensive-programming.md)
| _Due: Tue Jul 22_ - [Phase 4: Chess Database](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/4-database/database.md) | -| | Wed Jul 23 | [`Phase 5: Chess Pregame`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/5-pregame/pregame.md)
[Console UI](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/console-ui/console-ui.md)
[Client HTTP](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/web-api/web-api.md)
| | -| | Thu Jul 24 | HOLIDAY | | -| | Fri Jul 25 | | _Due: Fri Jul 25_ - [Programming Exam - 2nd Retake](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/programming-exam/programming-exam.md) (if needed) | -| 6 | Mon Jul 28 | [Security: Hashing](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/computer-security/computer-security.md)
| | -| | Tue Jul 29 | [WebSocket](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/websocket/websocket.md)
[`Phase 6: Chess Gameplay`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/6-gameplay/gameplay.md) | _Due: Tue Jul 29_ - [Phase 5: Chess Pregame](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/5-pregame/pregame.md)
_Tue Jul 29 - Withdraw Deadline_ | -| | Wed Jul 30 | [Security: Encryption](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/computer-security/computer-security.md) | | -| 7 | Mon Aug 04 | [Concurrency](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/concurrency/concurrency.md) | | -| | Tue Aug 05 | [Command-Line Builds](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/command-line-builds/command-line-builds.md) | | -| | Wed Aug 06 | [Deploying Your Chess Server on AWS](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/aws-chess-server/aws-chess-server.md)
| | -| | Thu Aug 07 | | _Due: Thu Aug 07_ - [Phase 6: Chess Gameplay](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/6-gameplay/gameplay.md) | -| 8 | Mon Aug 11 | [Final Exam Review](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/final-exam-review/final-exam-review.md) | _Aug 12 - 14_ - Final Exam | diff --git a/schedule/archive/winter2024-rodham.md b/schedule/archive/winter2024-rodham.md deleted file mode 100644 index a721034f..00000000 --- a/schedule/archive/winter2024-rodham.md +++ /dev/null @@ -1,34 +0,0 @@ -# Winter 2024 Schedule - -| Week | Day | Date | Discussion Topics | Deliverable Due Dates | -| :--: | :-: | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | -| 1 | 1 | Mon Jan 8 | [Introduction](../instruction/introduction/introduction.md), [Git](../instruction/git/git.md), [Chess Github Repository](../chess/chess-github-repository/chess-github-repository.md) | _Jan 10_ - Chess Github Repository | -| | 2 | Wed Jan 10 | Java Fundamentals
`Phase 0: Chess Moves` | | -| 2 | 3 | Mon Jan 15 | _Holiday - No class_ | | -| | 4 | Wed Jan 17 | Object Class, Classes and Objects, Records | | -| 3 | 5 | Mon Jan 22 | Interfaces and Abstract Classes, Copying Objects
`Programming Exam` | _Jan 23_ - Phase 0: Chess Moves | -| | 6 | Wed Jan 24 | Exceptions, Collections | _Jan 26_ - Programming Exam | -| 4 | 7 | Mon Jan 29 | Design Principles
Writing Quality, Code Style Checker
`Phase 1: Chess Game` | | -| | 8 | Wed Jan 31 | Inner Classes, Generics, Lambdas | | -| 5 | 9 | Mon Feb 5 | `Phase 2: Chess Design`
Javadoc | _Feb 6_ - Phase 1: Chess Game | -| | 10 | Wed Feb 7 | Input/Output
JSON & Serialization | | -| 6 | 11 | Mon Feb 12 | HTTP, Curl | _Feb 13_ - Phase 2: Chess Design | -| | 12 | Wed Feb 14 | Web API, Pet Shop
`Phase 3: Chess Web-API` | | -| 7 | 13 | Tue Feb 20 | Unit Testing, Code Coverage | | -| | 14 | Wed Feb 21 | _No Class_ | | -| 8 | 15 | Mon Feb 26 | Relational Model | _Feb 27_ - Phase 3: Chess Web-API | -| | 16 | Wed Feb 28 | SQL, JDBC
`Phase 4: Chess Database` | | -| 9 | 17 | Mon Mar 4 | MySQL, Securing Passwords | | -| | 18 | Wed Mar 6 | Logging, Debugging, Defensive Programming | _Mar 7_ - Phase 4: Chess Database | -| 10 | 19 | Mon Mar 11 | Console UI, Client HTTP
`Phase 5: Chess Pregame` | | -| | 20 | Wed Mar 13 | _TBD_ | | -| 11 | 21 | Mon Mar 18 | WebSocket | | -| | 22 | Wed Mar 20 | `Phase 6: Chess Gameplay` | _Mar 22_ - Phase 5: Chess Pregame | -| 12 | 23 | Mon Mar 25 | Security: Hashing | | -| | 24 | Wed Mar 27 | Security: Encrypting | | -| 13 | 25 | Mon Apr 1 | Concurrency | | -| | 26 | Wed Apr 3 | Command line tools, Final Exam Review | | -| 14 | 27 | Mon Apr 8 | _TBD_ | | -| | 28 | Wed Apr 10 | _TBD_ | _Apr 11_ - Phase 6: Chess Gameplay | -| 15 | 29 | Mon Apr 15 | _No Class_ | | -| | 30 | Wed Apr 17 | _No Class_ | _Apr 18-24_ - Final | diff --git a/schedule/archive/winter2024.md b/schedule/archive/winter2024.md deleted file mode 100644 index d46d1f89..00000000 --- a/schedule/archive/winter2024.md +++ /dev/null @@ -1,33 +0,0 @@ -# Winter 2024 Schedule - -| Week | Day | Date | Discussion Topics | Deliverable Due Dates | Slides | -| :--: | :-: | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 1 | 1 | Tue Jan 9 | [Introduction](../instruction/introduction/introduction.md), [Git](../instruction/git/git.md), [Chess GitHub Repository](../chess/chess-github-repository/chess-github-repository.md) | _Jan 10_ - Chess GitHub Repository | [Introduction](https://docs.google.com/presentation/d/1hV2h_kNk6dOdod_n4ps6Fv9iHS8QYbITv4sg27U600w) | -| | 2 | Thu Jan 11 | [Java Fundamentals](../instruction/java-fundamentals/java-fundamentals.md)
[`Phase 0: Chess Moves`](../chess/0-chess-moves/chess-moves.md) | | [Java Fundamentals](https://docs.google.com/presentation/d/1SPIGPSSajy0CMh2b5nucOCAhAkXtRPkUgtewQh3tqZw) | -| 2 | 3 | Tue Jan 16 | [Object Class](../instruction/java-object-class/java-object-class.md), [Classes and Objects](../instruction/classes-and-objects/classes-and-objects.md), [Records](../instruction/records/records.md) | | [Objects](https://docs.google.com/presentation/d/1-sGH73aNqlKM_ONUi6urI8h3buSkISBY4o1T7ph7jKw) | -| | 4 | Thu Jan 18 | [Interfaces and Abstract Classes](../instruction/interfaces-abstract-classes/interfaces-and-abstract-classes.md), [Copying Objects](../instruction/copying-objects/copying-objects.md) | | [Polymorphism](https://docs.google.com/presentation/d/15mC8spOF9Y_pfPlUZfEg7qH_VUB2E6rEnmBwGd_Ac2g) | -| 3 | 5 | Tue Jan 23 | [Exceptions](../instruction/exceptions/exceptions.md), [Collections](../instruction/collections/collections.md)
`Programming Exam` | _Jan 23_ - Phase 0: Chess Moves | [Collections and Exceptions](https://docs.google.com/presentation/d/14-QmgQznammEe-QbN8uvpL4OyywLdGDNeEYzxLoH62g) | -| | 6 | Thu Jan 25 | [Object Oriented Design](../instruction/object-oriented-design/object-oriented-design.md), [Design Principles](../instruction/design-principles/design-principles.md) | _Jan 26_ - Programming Exam | [Design](https://docs.google.com/presentation/d/1JGnm9YViJkXa0Ic32VaLU4-pFk51o13TDfZnwkL-uJs) | -| 4 | 7 | Tue Jan 30 | [Inner Classes](../instruction/inner-classes/inner-classes.md), [Lambdas](../instruction/lambdas/lambdas.md)
[`Phase 1: Chess Game`](../chess/1-chess-game/chess-game.md) | | [Inner Classes](https://docs.google.com/presentation/d/1PSfmZh1kLuMZHJIyuWYBogRNu9H05-ycocfdxd6rpGM) | -| | 8 | Thu Feb 1 | [Input/Output](../instruction/io/io.md), [Generics](../instruction/generics/generics.md), [JSON & Serialization](../instruction/json/json.md) | | [IO & Generics](https://docs.google.com/presentation/d/1U8kYn3LBTQ7TOO-wMa01Dj6S4m44CA2woJcJ9Rn98M4), [Serialization](https://docs.google.com/presentation/d/1JnN0E-3P21VXCxW9Vz7Ugv2incM48brNTu8xOJRuS9Q) | -| 5 | 9 | Tue Feb 6 | [`Phase 2: Chess Design`](../chess/2-server-design/server-design.md) | _Feb 6_ - Phase 1: Chess Game | [Design](https://docs.google.com/presentation/d/1yQNr55p3nz_HvrP6fmHqinHWMf2mUnZLPtG7Mra3mE8) | -| | 10 | Thu Feb 8 | [HTTP](../instruction/http/http.md), [Curl](../instruction/curl/curl.md), [Web API](../instruction/web-api/web-api.md) | | [HTTP](https://docs.google.com/presentation/d/1XhQk-BvhcdNVOpVkv16kXr07q4lJpkVbbTf62_DbYU8), [WebAPI](https://docs.google.com/presentation/d/1bACOxSEMp-kEUTf2sxFXdlg7dfNOeosq5yaSz7juC7Q) | -| 6 | 11 | Tue Feb 13 | [Pet Shop](../petshop/petshop.md)
[`Phase 3: Chess Web-API`](../chess/3-web-api/web-api.md) | _Feb 13_ - Phase 2: Chess Design | [Petshop & Chess 3](https://docs.google.com/presentation/d/1oFyZMUqh4dYBAAi0wUtS4rGxh4czF-8E5wFFseC77LE) | -| | 12 | Thu Feb 15 | [Writing Quality](../instruction/quality-code/quality-code.md), [Code Style Checker](../instruction/style-checker/style-checker.md) | | [Code Quality](https://docs.google.com/presentation/d/1BL8fSa7Evd5gdqNIpGub03YoulWM_zBIRIe9k82w5DI) | -| 7 | 13 | Tue Feb 20 | _Holiday - Monday instruction_ | | | -| | 14 | Thu Feb 22 | [Unit Testing](../instruction/unit-testing/unit-testing.md), [Code Coverage](../instruction/code-coverage/code-coverage.md) | | [Testing](https://docs.google.com/presentation/d/10UAz0tZo8HXoaewgk3CDq8ACCBQPI2pmYbr6nVBvRRU) | -| 8 | 15 | Tue Feb 27 | [Relational Model](../instruction/db-model/db-model.md) | _Feb 27_ - Phase 3: Chess Web-API | [Relational Model](https://docs.google.com/presentation/d/1URzOUT09zQ1YR8vgxAsGgxnj_5KnRb6CUvhBv2RiUhk) | -| | 16 | Thu Feb 29 | [MySQL](../instruction/mysql/mysql.md), [SQL](../instruction/db-sql/db-sql.md)
[`Phase 4: Chess Database`](../chess/4-database/database.md) | | [SQL](https://docs.google.com/presentation/d/1WVLMOK4arzmqS6r2SsBRRmSvW984gIoBWiKtz7mnnUY) | -| 9 | 17 | Tue Mar 5 | [JDBC](../instruction/db-jdbc/db-jdbc.md), [Securing Passwords](../instruction/securing-passwords/securing-passwords.md) | | [JDBC](https://docs.google.com/presentation/d/1Yj9dwQUIWexTtnnSNAc64o2iRRZ7ETBIFWGxibw5rEs) | -| | 18 | Thu Mar 7 | _In class help session_ | _Mar 7_ - Phase 4: Chess Database | | -| 10 | 19 | Tue Mar 12 | [Console UI](../instruction/console-ui/console-ui.md), [Client HTTP](../instruction/web-api/web-api.md), [`Phase 5: Chess Pregame`](../chess/5-pregame/pregame.md) | | [Console UI](https://docs.google.com/presentation/d/1T6l8iPi3RhMEYnUzeftLR8mMUFkbOzIhh6PjDNUHQvo) | -| | 20 | Thu Mar 14 | [Logging](../instruction/logging/logging.md), [Debugging](../instruction/debugging/debugging.md), [Defensive Programming](../instruction/defensive-programming/defensive-programming.md) | | [Logging & Debugging](https://docs.google.com/presentation/d/1ZVp56cAxA9FX_ldNZQxXNbVmMyTW-VQHYbe_RstFmcY) | -| 11 | 21 | Tue Mar 19 | [WebSocket](../instruction/websocket/websocket.md) | | [WebSocket](https://docs.google.com/presentation/d/19r2fC1VHMMTp7qUmRGh89swp7ZLgf3JcOUkEXIndKMg) | -| | 22 | Thu Mar 21 | [`Phase 6: Chess Gameplay`](../chess/6-gameplay/gameplay.md) | _Mar 22_ - Phase 5: Chess Pregame | [Gameplay](https://docs.google.com/presentation/d/1xXsH2eCmbI0n6xW0Q6ClyXy2p5ZnaKf0nbOBuNN_exw) | -| 12 | 25 | Tue Mar 26 | [Computer Security](../instruction/computer-security/computer-security.md) | | [Hashing](https://docs.google.com/presentation/d/1mWgXs0u2Lr7ducLhPEALvu3DlINNzMY_ZZk0NGoku58) | -| | 26 | Thu Mar 28 | [Computer Security](../instruction/computer-security/computer-security.md) | | [Encryption](https://docs.google.com/presentation/d/1rXrgWisZYZKIXz5Mh1t7PUA8mMNYL6e0ovY8hldKnLA) | -| 13 | 27 | Tue Apr 2 | [Concurrency](../instruction/concurrency/concurrency.md) | | [Concurrency](https://docs.google.com/presentation/d/1OcH2XYen-U0f1sBAxaaCswwzp_OergGhq7b9mopszRM) | -| | 28 | Thu Apr 4 | _No class_ | | | -| 14 | 29 | Tue Apr 9 | [AWS Chess Server](../instruction/aws-chess-server/aws-chess-server.md) | | | -| | 30 | Thu Apr 11 | Protips | _Apr 11_ - Phase 6: Chess Gameplay | [Protips](https://docs.google.com/presentation/d/1HitFGYCbV01poP2Ib2FzhPMGxiYFRtZNu2UmUrSqTOM) | -| 15 | 31 | Tue Apr 16 | [Command line tools](../instruction/command-line-builds/command-line-builds.md), [Final Exam Review](../instruction/final-exam-review/final-exam-review.md) | _Apr 18-24_ - Final | [Maven](https://docs.google.com/presentation/d/1zgt9rpNWEpgxkP-FQ1wXsEFA8974AV3oElUXlUZZaZo) | diff --git a/schedule/archive/winter2025-rodham.md b/schedule/archive/winter2025-rodham.md deleted file mode 100644 index def69644..00000000 --- a/schedule/archive/winter2025-rodham.md +++ /dev/null @@ -1,36 +0,0 @@ -# Winter 2025 Schedule - Dr. Rodham - -This schedule applies to all of Dr. Rodham's CS 240 sections (blended/in-person and online). For blended/in-person sections, the "Video Lecture Topics" column lists lecture topics that will not be covered in class. Students will need to watch the videos on these topics. Entries in this column may be updated throughout the semester depending on how far we get in in-class lectures. - -Students in online sections should watch all videos for all topics, including those listed under "Discussion Topics" and any additional topics listed under "Video Lecture Topics". - -| Week | Day | Date | Discussion Topics | Video Lecture Topics | Deliverable | -| :--: | :-: | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | -| 1 | 1 | Wed Jan 8 | [Introduction](../instruction/introduction/introduction.md)
[Git](../instruction/git/git.md)
[Chess GitHub Repository](../chess/chess-github-repository/chess-github-repository.md) | [Git](../instruction/git/git.md)
(Watch the last 8 videos, starting with "Basic Git Commands") | _Due: Fri Jan 10_ - [Chess GitHub Repository](../chess/chess-github-repository/chess-github-repository.md) | -| 2 | 2 | Mon Jan 13 | [Java Fundamentals](../instruction/java-fundamentals/java-fundamentals.md)
[`Phase 0: Chess Moves`](../chess/0-chess-moves/chess-moves.md) | | | -| | 3 | Wed Jan 15 | [Java Fundamentals (continued)](../instruction/java-fundamentals/java-fundamentals.md)
[Classes and Objects](../instruction/classes-and-objects/classes-and-objects.md) | [Classes and Objects](../instruction/classes-and-objects/classes-and-objects.md)
(Whatever we didn't cover in class) | | -| 3 | | Mon Jan 20 | No Class - Holiday | | | -| | 4 | Wed Jan 22 | [`Programming Exam`](../instruction/programming-exam/programming-exam.md)
[Records](../instruction/records/records.md)
[Interfaces and Abstract Classes](../instruction/interfaces-abstract-classes/interfaces-and-abstract-classes.md)
| [Interfaces and Abstract Classes](../instruction/interfaces-abstract-classes/interfaces-and-abstract-classes.md)
(Whatever we didn't cover in class) | _Due: Fri Jan 24_ - [Phase 0: Chess Moves](../chess/0-chess-moves/chess-moves.md) | -| 4 | 5 | Mon Jan 27 | [Copying Objects](../instruction/copying-objects/copying-objects.md)
[Exceptions](../instruction/exceptions/exceptions.md) | | _Due: Tue Jan 28_ - [Programming Exam](../instruction/programming-exam/programming-exam.md) | -| | 6 | Wed Jan 29 | [`Phase 1: Chess Game`](../chess/1-chess-game/chess-game.md)
[Collections](../instruction/collections/collections.md)
[Inner Classes](../instruction/inner-classes/inner-classes.md)
| | | -| 5 | 7 | Mon Feb 3 | [Generics](../instruction/generics/generics.md)
[Lambdas](../instruction/lambdas/lambdas.md)
[Input/Output](../instruction/io/io.md)
| [Generics](../instruction/generics/generics.md)
(Whatever we didn't cover in class)
[Lambdas](../instruction/lambdas/lambdas.md)
(Whatever we didn't cover in class) | _Due: Tue Feb 4_ - [Programming Exam - 1st Retake](../instruction/programming-exam/programming-exam.md) (if needed) | -| | 8 | Wed Feb 5 | [JSON & Serialization](../instruction/json/json.md)
[Design Principles](../instruction/design-principles/design-principles.md) | | _Due: Fri Feb 7_ - [Phase 1: Chess Game](../chess/1-chess-game/chess-game.md) | -| 6 | 9 | Mon Feb 10 | [`Phase 2: Chess Design`](../chess/2-server-design/server-design.md)
| | | -| | 10 | Wed Feb 12 | [HTTP](../instruction/http/http.md)
[Curl](../instruction/curl/curl.md)
| | _Due: Wed Feb 12_ - [Phase 2: Chess Design](../chess/2-server-design/server-design.md) | -| 7 | 11 | Tue Feb 18 | [Web API](../instruction/web-api/web-api.md)
[`Phase 3: Chess Web-API`](../chess/3-web-api/web-api.md) | | | -| | 12 | Wed Feb 19 | [Unit Testing](../instruction/unit-testing/unit-testing.md)
[Code Coverage](../instruction/code-coverage/code-coverage.md) | | | -| 8 | 13 | Mon Feb 24 | [Writing Quality Code](../instruction/quality-code/quality-code.md)
[Code Style Checker](../instruction/style-checker/style-checker.md) | | | -| | 14 | Wed Feb 26 | [Relational Databases: Model](../instruction/db-model/db-model.md)
[Relational Databases: SQL](../instruction/db-sql/db-sql.md) | | | -| 9 | 15 | Mon Mar 3 | [Relational Databases: JDBC](../instruction/db-jdbc/db-jdbc.md)
[`Phase 4: Chess Database`](../chess/4-database/database.md) | | _Due: Mon Mar 03_ - [Phase 3: Chess Web-API](../chess/3-web-api/web-api.md) | -| | 16 | Wed Mar 5 | [MySQL](../instruction/mysql/mysql.md)
[Securing Passwords](../instruction/securing-passwords/securing-passwords.md) | | | -| 10 | 17 | Mon Mar 10 | [Debugging](../instruction/debugging/debugging.md)
[Logging](../instruction/logging/logging.md)
[Defensive Programming](../instruction/defensive-programming/defensive-programming.md)
| | | -| | 18 | Wed Mar 12 | [`Phase 5: Chess Pregame`](../chess/5-pregame/pregame.md)
[Console UI](../instruction/console-ui/console-ui.md)
[Client HTTP](../instruction/web-api/web-api.md)
| | _Due: Wed Mar 12_ - [Phase 4: Chess Database](../chess/4-database/database.md) | -| 11 | 19 | Mon Mar 17 | [Security: Hashing](../instruction/computer-security/computer-security.md)
| | | -| | 20 | Wed Mar 19 | No Class - Work on Phase 5 | | | -| 12 | 21 | Mon Mar 24 | [WebSocket](../instruction/websocket/websocket.md)
[`Phase 6: Chess Gameplay`](../chess/6-gameplay/gameplay.md) | | _Due: Tue Mar 25_ - [Phase 5: Chess Pregame](../chess/5-pregame/pregame.md) | -| | 22 | Wed Mar 26 | [Security: Encryption](../instruction/computer-security/computer-security.md) | | | -| 13 | 23 | Mon Mar 31 | [Concurrency](../instruction/concurrency/concurrency.md) | | _Due: Tue Apr 1_ - [Programming Exam - 2nd Retake](../instruction/programming-exam/programming-exam.md) (if needed)

| -| | 24 | Wed Apr 2 | Flex Day
(Catch up if needed) | | Thu _Apr 3_ - Withdrawal Deadline | -| 14 | 25 | Mon Apr 7 | [Command-Line Builds](../instruction/command-line-builds/command-line-builds.md)
[Deploying Your Chess Server on AWS](../instruction/aws-chess-server/aws-chess-server.md)
| | | -| | 26 | Wed Apr 9 | No Class - Work on Phase 6 | | _Due: Thu Apr 10_ - [Phase 6: Chess Gameplay](../chess/6-gameplay/gameplay.md) | -| 15 | 27 | Mon Apr 14 | Final Exam Review | | _Apr 17 - 23_ - Final Exam | diff --git a/schedule/archive/winter2025-wilkerson.md b/schedule/archive/winter2025-wilkerson.md deleted file mode 100644 index e4b2a99d..00000000 --- a/schedule/archive/winter2025-wilkerson.md +++ /dev/null @@ -1,36 +0,0 @@ -# Winter 2025 Schedule - Dr. Wilkerson -This schedule applies to all of Dr. Wilkerson's CS 240 sections (blended/in-person and online). For blended/in-person sections, the "Video Lecture Topics" column lists lecture topics that will not be covered in class. Students will need to watch the videos on these topics. Entries in this column may be updated throughout the semester depending on how far we get in in-class lectures. - -Students in online sections should watch all videos for all topics, including those listed under "Discussion Topics" and any additional topics listed under "Video Lecture Topics". - - -| Week | Day | Date | Discussion Topics | Video Lecture Topics | Deliverable | -| :--: | :-: | ---------- | ----------------------------------------------------------------- | ------------------------------- | ---------------------------------------- | -| 1 | 1 | Thu Jan 9 | [Introduction](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/introduction/introduction.md)
[Git](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/git/git.md)
[Chess GitHub Repository](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/chess-github-repository/chess-github-repository.md) | [Git](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/git/git.md)
(Watch all but the first video) | _Due: Jan 10_ - [Chess GitHub Repository](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/chess-github-repository/chess-github-repository.md) | -| 2 | 2 | Tue Jan 14 | [Java Fundamentals](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/java-fundamentals/java-fundamentals.md)
[`Phase 0: Chess Moves`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/0-chess-moves/chess-moves.md) | | | -| | 3 | Thu Jan 16 | [Java Fundamentals (continued)](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/java-fundamentals/java-fundamentals.md)
[Classes and Objects](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/classes-and-objects/classes-and-objects.md) | | | -| 3 | 4 | Tue Jan 21 | [Classes and Objects (continued)](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/classes-and-objects/classes-and-objects.md)
| [Classes and Objects](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/classes-and-objects/classes-and-objects.md)
(Whatever we didn't cover in class) | | -| | 5 | Thu Jan 23 | [Records](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/records/records.md)
[`Programming Exam`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/programming-exam/programming-exam.md)
[Exceptions](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/exceptions/exceptions.md) | [Interfaces and Abstract Classes](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/interfaces-abstract-classes/interfaces-and-abstract-classes.md)
(6 videos - 30:44) | _Due: Jan 24_ - [Phase 0: Chess Moves](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/0-chess-moves/chess-moves.md) | -| 4 | 6 | Tue Jan 28 | [Collections](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/collections/collections.md)
[Copying Objects](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/copying-objects/copying-objects.md) | | _Due: Jan 28_ - [Programming Exam](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/programming-exam/programming-exam.md) | -| | 7 | Thu Jan 30 | [Inner Classes](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/inner-classes/inner-classes.md)
[`Phase 1: Chess Game`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/1-chess-game/chess-game.md)
[Design Principles](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/design-principles/design-principles.md) | | | -| 5 | 8 | Tue Feb 4 | [Input/Output](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/io/io.md) | | _Due: Feb 4_ - [Programming Exam - 1st Retake](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/programming-exam/programming-exam.md) (if needed) | -| | 9 | Thu Feb 6 | [JSON & Serialization](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/json/json.md)
[`Phase 2: Chess Design`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/2-server-design/server-design.md) | [Generics](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/generics/generics.md) (3 videos - 12:48)
[Lambdas](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/lambdas/lambdas.md) (8 videos - 34:42) | _Due: Feb 7_ - [Phase 1: Chess Game](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/1-chess-game/chess-game.md) | -| 6 | 10 | Tue Feb 11 | [HTTP](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/http/http.md)
[Curl](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/curl/curl.md) | | _Due: Feb 12_ - [Phase 2: Chess Design](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/2-server-design/server-design.md) | -| | 11 | Thu Feb 13 | [Web API](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/web-api/web-api.md)
[`Phase 3: Chess Web-API`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/3-web-api/web-api.md) | | | -| 7 | | Tue Feb 18 | No Class - Monday Instruction | | | -| | 12 | Thu Feb 20 | [Writing Quality Code](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/quality-code/quality-code.md)
[Code Style Checker](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/style-checker/style-checker.md) | | | -| 8 | 13 | Tue Feb 25 | [Unit Testing](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/unit-testing/unit-testing.md)
[Code Coverage](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/code-coverage/code-coverage.md) | | | -| | 14 | Thu Feb 27 | [Relational Databases: Model](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/db-model/db-model.md)
[Relational Databases: SQL](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/db-sql/db-sql.md)| Dr. Wilkerson out of town. Watch videos in place of class. | _Due: Mar 3_ - [Phase 3: Chess Web-API](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/3-web-api/web-api.md) | -| 9 | 15 | Tue Mar 4 | [Relational Databases: JDBC](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/db-jdbc/db-jdbc.md)
[`Phase 4: Chess Database`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/4-database/database.md) | | | -| | 16 | Thu Mar 6 | [MySQL](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/mysql/mysql.md)
[Securing Passwords](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/securing-passwords/securing-passwords.md) | | | -| 10 | 17 | Tue Mar 11 | [Debugging](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/debugging/debugging.md) | | _Due: Mar 12_ - [Phase 4: Chess Database](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/4-database/database.md) | -| | 18 | Thu Mar 13 | [Console UI](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/console-ui/console-ui.md)
[`Phase 5: Chess Pregame`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/5-pregame/pregame.md) | | | -| 11 | 19 | Tue Mar 18 | [Client HTTP](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/web-api/web-api.md)
[Logging](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/logging/logging.md) | | | -| | 20 | Thu Mar 20 | [Defensive Programming](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/defensive-programming/defensive-programming.md) | | | -| 12 | 21 | Tue Mar 25 | [WebSocket](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/websocket/websocket.md)
[`Phase 6: Chess Gameplay`](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/6-gameplay/gameplay.md) | | _Due: Mar 25_ - [Phase 5: Chess Pregame](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/5-pregame/pregame.md) | -| | 22 | Thu Mar 27 | [Security: Hashing](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/computer-security/computer-security.md)
[Security: Encrypting](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/computer-security/computer-security.md) | | | -| 13 | 23 | Tue Apr 1 | [Concurrency](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/concurrency/concurrency.md) | | _Due: Apr 1_ - [Programming Exam - 2nd Retake](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/programming-exam/programming-exam.md) (if needed)

| -| | 24 | Thu Apr 3 | [Command-Line Builds](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/command-line-builds/command-line-builds.md) | | _Apr 3_ - Withdrawal Deadline | -| 14 | 25 | Tue Apr 8 | [Deploying Your Chess Server on AWS](https://github.com/softwareconstruction240/softwareconstruction/blob/main/instruction/aws-chess-server/aws-chess-server.md) | | | -| | 26 | Thu Apr 10 | No Class - Work on Phase 6 | | _Due: Apr 10_ - [Phase 6: Chess Gameplay](https://github.com/softwareconstruction240/softwareconstruction/blob/main/chess/6-gameplay/gameplay.md) | -| 15 | 27 | Tue Apr 15 | Final Exam Review | | _Apr 17 - 23_ - Final Exam | diff --git a/schedule/archive/winter2026-jensen.md b/schedule/archive/winter2026-jensen.md deleted file mode 100644 index d148d101..00000000 --- a/schedule/archive/winter2026-jensen.md +++ /dev/null @@ -1,46 +0,0 @@ -# 📅 Winter 2026 Schedule - -[BYU Academic Calendar](https://academiccalendar.byu.edu/) - -| Week | Day | Date | Discussion Topics | Deliverable Due Dates | Slides | -| :--: | :-: | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 1 | 1 | **Jan 7** | [Introduction](../instruction/introduction/introduction.md), [Git](../instruction/git/git.md), [Chess GitHub Repository](../chess/chess-github-repository/chess-github-repository.md) | _Jan 9_ - Chess GitHub Repository,
Honorlock setup | [Introduction](https://docs.google.com/presentation/d/1hV2h_kNk6dOdod_n4ps6Fv9iHS8QYbITv4sg27U600w) | -| | 2 | 12 | [Java Fundamentals](../instruction/java-fundamentals/java-fundamentals.md), [`Phase 0: Chess Moves`](../chess/0-chess-moves/chess-moves.md) | | [Java Fundamentals](https://docs.google.com/presentation/d/1SPIGPSSajy0CMh2b5nucOCAhAkXtRPkUgtewQh3tqZw) | -| 2 | 3 | 14 | [Object Class](../instruction/java-object-class/java-object-class.md), [Classes and Objects](../instruction/classes-and-objects/classes-and-objects.md), [Records](../instruction/records/records.md) | | [Objects](https://docs.google.com/presentation/d/1-sGH73aNqlKM_ONUi6urI8h3buSkISBY4o1T7ph7jKw) | -| | 4 | 19 | _Holiday_ | | | -| 3 | 5 | 21 | [Interfaces and Abstract Classes](../instruction/interfaces-abstract-classes/interfaces-and-abstract-classes.md), [Programming Exam](../instruction/programming-exam/programming-exam.md) | _Jan 23_ - Phase 0: Chess Moves | [Abstraction](https://docs.google.com/presentation/d/15mC8spOF9Y_pfPlUZfEg7qH_VUB2E6rEnmBwGd_Ac2g) | -| | 6 | 26 | [Exceptions](../instruction/exceptions/exceptions.md), [Collections](../instruction/collections/collections.md), [Copying Objects](../instruction/copying-objects/copying-objects.md) | _Jan 27_ - Programming Exam | [Collections and Exceptions](https://docs.google.com/presentation/d/14-QmgQznammEe-QbN8uvpL4OyywLdGDNeEYzxLoH62g) | -| 4 | 7 | 28 | [Inner Classes](../instruction/inner-classes/inner-classes.md), [Lambdas](../instruction/lambdas/lambdas.md), [`Phase 1: Chess Game`](../chess/1-chess-game/chess-game.md) | | [Inner Classes](https://docs.google.com/presentation/d/1PSfmZh1kLuMZHJIyuWYBogRNu9H05-ycocfdxd6rpGM) | -| | 8 | **Feb 2** | [Object Oriented Design](../instruction/object-oriented-design/object-oriented-design.md), [Design Principles](../instruction/design-principles/design-principles.md) | _Feb 3_ - 1st Programming Exam retake | [Design](https://docs.google.com/presentation/d/1JGnm9YViJkXa0Ic32VaLU4-pFk51o13TDfZnwkL-uJs) | -| 5 | 9 | 4 | [Generics](../instruction/generics/generics.md), [`Phase 2: Chess Design`](../chess/2-server-design/server-design.md) ) | _Feb 6_ - Phase 1: Chess Game | [Generics](https://docs.google.com/presentation/d/1U8kYn3LBTQ7TOO-wMa01Dj6S4m44CA2woJcJ9Rn98M4), [Chess Design](https://docs.google.com/presentation/d/1yQNr55p3nz_HvrP6fmHqinHWMf2mUnZLPtG7Mra3mE8) | -| | 10 | 9 | [Input/Output](../instruction/io/io.md), [JSON & Serialization](../instruction/json/json.md | | [IO & Serialization](https://docs.google.com/presentation/d/1JnN0E-3P21VXCxW9Vz7Ugv2incM48brNTu8xOJRuS9Q) | -| 6 | 11 | 11 | [HTTP](../instruction/http/http.md), [Curl](../instruction/curl/curl.md), [Web API](../instruction/web-api/web-api.md) | _Feb 11_ - Phase 2: Chess Design | [HTTP](https://docs.google.com/presentation/d/1XhQk-BvhcdNVOpVkv16kXr07q4lJpkVbbTf62_DbYU8), [WebAPI](https://docs.google.com/presentation/d/1bACOxSEMp-kEUTf2sxFXdlg7dfNOeosq5yaSz7juC7Q) | -| | 12 | Tue 17 | [Pet Shop](../petshop/petshop.md), [`Phase 3: Chess Web-API`](../chess/3-web-api/web-api.md) | | [Petshop & Chess 3](https://docs.google.com/presentation/d/1oFyZMUqh4dYBAAi0wUtS4rGxh4czF-8E5wFFseC77LE) | -| 7 | 13 | 18 | [Writing Quality](../instruction/quality-code/quality-code.md), [Code Style Checker](../instruction/style-checker/style-checker.md) | | [Code Quality](https://docs.google.com/presentation/d/1BL8fSa7Evd5gdqNIpGub03YoulWM_zBIRIe9k82w5DI) | -| | 14 | 23 | [Unit Testing](../instruction/unit-testing/unit-testing.md), [Code Coverage](../instruction/code-coverage/code-coverage.md) | | [Testing](https://docs.google.com/presentation/d/10UAz0tZo8HXoaewgk3CDq8ACCBQPI2pmYbr6nVBvRRU) | -| 8 | 15 | 25 | [Relational Model](../instruction/db-model/db-model.md), [SQL](../instruction/db-sql/db-sql.md), [MySQL](../instruction/mysql/mysql.md) | | [Relational Model](https://docs.google.com/presentation/d/1URzOUT09zQ1YR8vgxAsGgxnj_5KnRb6CUvhBv2RiUhk), [SQL](https://docs.google.com/presentation/d/1WVLMOK4arzmqS6r2SsBRRmSvW984gIoBWiKtz7mnnUY) | -| | 16 | **Mar 2** | [JDBC](../instruction/db-jdbc/db-jdbc.md) | _Mar 2_ - Phase 3: Chess Web-API | [JDBC](https://docs.google.com/presentation/d/1Yj9dwQUIWexTtnnSNAc64o2iRRZ7ETBIFWGxibw5rEs) | -| 9 | 17 | 4 | [`Phase 4: Chess Database`](../chess/4-database/database.md), [Securing Passwords](../instruction/securing-passwords/securing-passwords.md) | | [Chess 4](https://docs.google.com/presentation/d/1SxFq2LjXYJo5QKd9ueMoDMLQHLoCRKmHaKkJwnMVg5w) | -| | 18 | 9 | [Console UI](../instruction/console-ui/console-ui.md), [Client HTTP](../instruction/web-api/web-api.md) | | [Client](https://docs.google.com/presentation/d/1T6l8iPi3RhMEYnUzeftLR8mMUFkbOzIhh6PjDNUHQvo) | -| 10 | 19 | 11 | [`Phase 5: Chess Pregame`](../chess/5-pregame/pregame.md) | _Mar 11_ - Phase 4: Chess Database | [Chess 5](https://docs.google.com/presentation/d/1NcqFkAkVQBKROifz9ALEHvXCh8uja3gEYGN5Sh8r8oo) | -| | 20 | 16 | [Logging](../instruction/logging/logging.md), [Debugging](../instruction/debugging/debugging.md), [Defensive Programming](../instruction/defensive-programming/defensive-programming.md) | | [Logging & Debugging](https://docs.google.com/presentation/d/1ZVp56cAxA9FX_ldNZQxXNbVmMyTW-VQHYbe_RstFmcY) | -| 11 | 21 | 18 | [WebSocket](../instruction/websocket/websocket.md) | | [WebSocket](https://docs.google.com/presentation/d/19r2fC1VHMMTp7qUmRGh89swp7ZLgf3JcOUkEXIndKMg) | -| | 22 | 23 | No class - work on Phase 5 | | | -| 12 | 23 | 25 | [`Phase 6: Chess Gameplay`](../chess/6-gameplay/gameplay.md) | _Mar 25_ - Phase 5: Chess Pregame | [Gameplay](https://docs.google.com/presentation/d/1xXsH2eCmbI0n6xW0Q6ClyXy2p5ZnaKf0nbOBuNN_exw) | -| | 24 | 30 | [Computer Security](../instruction/computer-security/computer-security.md) | _Mar 31_ - 2nd Programming Exam retake | [Hashing](https://docs.google.com/presentation/d/1mWgXs0u2Lr7ducLhPEALvu3DlINNzMY_ZZk0NGoku58) | -| 13 | 25 | **Apr 1** | [Computer Security](../instruction/computer-security/computer-security.md) | | [Encryption](https://docs.google.com/presentation/d/1rXrgWisZYZKIXz5Mh1t7PUA8mMNYL6e0ovY8hldKnLA) | -| | 26 | 6 | [Concurrency](../instruction/concurrency/concurrency.md) | | [Concurrency](https://docs.google.com/presentation/d/1OcH2XYen-U0f1sBAxaaCswwzp_OergGhq7b9mopszRM) | -| 14 | 27 | 8 | [Command line tools](../instruction/command-line-builds/command-line-builds.md) | _Apr 9_ - Phase 6: Chess Gameplay | [Maven](https://docs.google.com/presentation/d/1zgt9rpNWEpgxkP-FQ1wXsEFA8974AV3oElUXlUZZaZo) | -| | 28 | 13 | Protips, [Final Exam Review](../instruction/final-exam-review/final-exam-review.md) | | [Protips](https://docs.google.com/presentation/d/1HitFGYCbV01poP2Ib2FzhPMGxiYFRtZNu2UmUrSqTOM), [Employment](https://docs.google.com/presentation/d/1CQD6biLpKW2SCHutBmrpwdy5tqMgpZVB_jr7vBd6qNY) | -| 15 | 29 | 15 | No class | **No assignments accepted after this day**
_Apr 16-22_ - Final | | - -## Special days - -- **Jan 7**: First day of class -- **Jan 14**: Drop deadline -- **Jan 19**: Holiday -- **Feb 16**: Holiday (Monday class on 17th) - -- **Apr 1**: Withdraw deadline -- **Apr 15**: Last day of class -- **Apr 22**: Last day of finals