├── .github
└── workflows
│ └── manual.yml
├── .gitignore
├── CODEOWNERS
├── LICENSE.md
├── README.md
├── UdaSecurity.png
├── code_coverage_1.png
├── code_coverage_2.png
├── gui_1.png
├── gui_2.png
├── jar.png
├── pom_xml.png
└── starter
├── README.md
├── UdaSecurity.png
├── catpoint-parent
├── pom.xml
├── sample-cat.jpg
├── sample-not-a-cat-fail.jpg
├── sample-not-cat.jpg
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── udacity
│ │ │ └── catpoint
│ │ │ ├── application
│ │ │ ├── CatpointApp.java
│ │ │ ├── CatpointGui.java
│ │ │ ├── ControlPanel.java
│ │ │ ├── DisplayPanel.java
│ │ │ ├── ImagePanel.java
│ │ │ ├── SensorPanel.java
│ │ │ └── StatusListener.java
│ │ │ ├── data
│ │ │ ├── AlarmStatus.java
│ │ │ ├── ArmingStatus.java
│ │ │ ├── PretendDatabaseSecurityRepositoryImpl.java
│ │ │ ├── SecurityRepository.java
│ │ │ ├── Sensor.java
│ │ │ └── SensorType.java
│ │ │ └── service
│ │ │ ├── AwsImageService.java
│ │ │ ├── FakeImageService.java
│ │ │ ├── SecurityService.java
│ │ │ └── StyleService.java
│ └── resources
│ │ └── log4j.properties
│ └── test
│ └── java
│ └── com
│ └── udacity
│ └── catpoint
│ └── AppTest.java
├── code_coverage_1.png
├── code_coverage_2.png
├── gui_1.png
├── gui_2.png
├── jar.png
└── pom_xml.png
/.github/workflows/manual.yml:
--------------------------------------------------------------------------------
1 | # Workflow to ensure whenever a Github PR is submitted,
2 | # a JIRA ticket gets created automatically.
3 | name: Manual Workflow
4 |
5 | # Controls when the action will run.
6 | on:
7 | # Triggers the workflow on pull request events but only for the master branch
8 | pull_request_target:
9 | types: [opened, reopened]
10 |
11 | # Allows you to run this workflow manually from the Actions tab
12 | workflow_dispatch:
13 |
14 | jobs:
15 | test-transition-issue:
16 | name: Convert Github Issue to Jira Issue
17 | runs-on: ubuntu-latest
18 | steps:
19 | - name: Checkout
20 | uses: actions/checkout@master
21 |
22 | - name: Login
23 | uses: atlassian/gajira-login@master
24 | env:
25 | JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
26 | JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }}
27 | JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
28 |
29 | - name: Create NEW JIRA ticket
30 | id: create
31 | uses: atlassian/gajira-create@master
32 | with:
33 | project: CONUPDATE
34 | issuetype: Task
35 | summary: |
36 | Github PR - [Assign the NDKey] | Repo: ${{ github.repository }} | PR# ${{github.event.number}}
37 | description: |
38 | Repo link: https://github.com/${{ github.repository }}
39 | PR no. ${{ github.event.pull_request.number }}
40 | PR title: ${{ github.event.pull_request.title }}
41 | PR description: ${{ github.event.pull_request.description }}
42 | In addition, please resolve other issues, if any.
43 | fields: '{"components": [{"name":"cd0384 - Java Application Deployment"}], "customfield_16449":"https://classroom.udacity.com/", "customfield_16450":"Resolve the PR", "labels": ["github"], "priority":{"id": "4"}}'
44 |
45 | - name: Log created issue
46 | run: echo "Issue ${{ steps.create.outputs.issue }} was created"
47 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Intellij
2 | .idea/
3 | *.iml
4 | *.iws
5 |
6 | # Maven
7 | log/
8 | target/
9 |
10 | # Java
11 | config.properties
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @udacity/active-public-content
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 |
2 | Copyright © 2012 - 2020, Udacity, Inc.
3 |
4 | Udacity hereby grants you a license in and to the Educational Content, including but not limited to homework assignments, programming assignments, code samples, and other educational materials and tools (as further described in the Udacity Terms of Use), subject to, as modified herein, the terms and conditions of the Creative Commons Attribution-NonCommercial- NoDerivs 3.0 License located at http://creativecommons.org/licenses/by-nc-nd/4.0 and successor locations for such license (the "CC License") provided that, in each case, the Educational Content is specifically marked as being subject to the CC License.
5 | Udacity expressly defines the following as falling outside the definition of "non-commercial":
6 | (a) the sale or rental of (i) any part of the Educational Content, (ii) any derivative works based at least in part on the Educational Content, or (iii) any collective work that includes any part of the Educational Content;
7 | (b) the sale of access or a link to any part of the Educational Content without first obtaining informed consent from the buyer (that the buyer is aware that the Educational Content, or such part thereof, is available at the Website free of charge);
8 | (c) providing training, support, or editorial services that use or reference the Educational Content in exchange for a fee;
9 | (d) the sale of advertisements, sponsorships, or promotions placed on the Educational Content, or any part thereof, or the sale of advertisements, sponsorships, or promotions on any website or blog containing any part of the Educational Material, including without limitation any "pop-up advertisements";
10 | (e) the use of Educational Content by a college, university, school, or other educational institution for instruction where tuition is charged; and
11 | (f) the use of Educational Content by a for-profit corporation or non-profit entity for internal professional development or training.
12 |
13 |
14 |
15 | THE SERVICES AND ONLINE COURSES (INCLUDING ANY CONTENT) ARE PROVIDED "AS IS" AND "AS AVAILABLE" WITH NO REPRESENTATIONS OR WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. YOU ASSUME TOTAL RESPONSIBILITY AND THE ENTIRE RISK FOR YOUR USE OF THE SERVICES, ONLINE COURSES, AND CONTENT. WITHOUT LIMITING THE FOREGOING, WE DO NOT WARRANT THAT (A) THE SERVICES, WEBSITES, CONTENT, OR THE ONLINE COURSES WILL MEET YOUR REQUIREMENTS OR EXPECTATIONS OR ACHIEVE THE INTENDED PURPOSES, (B) THE WEBSITES OR THE ONLINE COURSES WILL NOT EXPERIENCE OUTAGES OR OTHERWISE BE UNINTERRUPTED, TIMELY, SECURE OR ERROR-FREE, (C) THE INFORMATION OR CONTENT OBTAINED THROUGH THE SERVICES, SUCH AS CHAT ROOM SERVICES, WILL BE ACCURATE, COMPLETE, CURRENT, ERROR- FREE, COMPLETELY SECURE OR RELIABLE, OR (D) THAT DEFECTS IN OR ON THE SERVICES OR CONTENT WILL BE CORRECTED. YOU ASSUME ALL RISK OF PERSONAL INJURY, INCLUDING DEATH AND DAMAGE TO PERSONAL PROPERTY, SUSTAINED FROM USE OF SERVICES.
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # UdaSecurity
2 |
3 | 
4 |
5 | Your company, **Udasecurity**, has created a home security application. This application tracks the status of sensors, monitors camera input, and changes the alarm state of the system based on inputs. Users can arm the system for when they’re home or away as well as disarm the system.
6 |
7 | The wild success of your application means that you have to prepare to scale your software. You’ll need to write unit tests for all of the major operations the application performs so that you can safely make more changes in the future. You also need to use maven to streamline the build process and automate your tests and code analysis. More urgently, you need to make sure your application actually does what it’s supposed to do, and so one of writing thorough unit tests will help you find any bugs that already exist.
8 |
9 | The image analysis service used by this application has proven popular as well, and another team wants to use it in their project. To accomplish this, you must separate the Image Service from the program and package it as a separate module to be included both in your own project and in other projects.
10 |
11 | The end goal for this assignment is to split the project into multiple modules, refactor it to be unit-testable, write unit tests to cover all the main requirements for the Security portion of the application and fix any bugs that you find in the process. You’ll also update the build process to automatically run unit tests, perform static code analysis, and build the code into an executable jar file.
12 |
13 | ## Section 1: Update `pom.xml` with Missing Dependencies
14 | This app was initially built by including jar files for each dependency manually, but now we are modernizing the dependency management by using Maven to manage our dependencies and their versions for us.
15 |
16 | The project has already been moved into a maven file structure for you, but you’ll need to identify missing dependencies and add their artifacts to your pom.xml until you can run the project successfully. Look throughout the project directory in order to make sure you find and add all the appropriate dependencies.
17 |
18 | You'll know you've added all of the correct dependencies when the project runs without errors.
19 |
20 | 
21 |
22 | ## Section 2: Split the Image Service into its Own Project
23 |
24 | Now that you have identified all the dependencies and can run the project, it’s time to split things up! Remember another team wants to use the Image Service in their project. To accomplish this, you must separate the Image Service from the program and package it as a separate module to be included both in your own project and in other projects
25 |
26 | ### Splitting Things Up
27 |
28 | 1. Use either maven or your IDE to create a new maven project that will be the parent project for the two modules you will be creating.
29 | 1. Inside of the parent project, create one module for your Security Security and one module for your Image service. (*Note: Use one parent pom at the top level and one child pom for each module.*)
30 | 1. Move all components into their proper modules.
31 | 1. Update dependencies in the poms so that shared dependencies are in the parent pom, but unshared dependencies are in the child poms.
32 | 1. Use the pluginManagement tag in the parent pom to set the latest versions for the core plugins used by the maven lifecycle, such as the maven-compiler-plugin.
33 | 1. Create a module descriptor for each package. You will have to provide the correct `export` and `requires` statements in each of these descriptors.
34 | 1. Address transitive dependencies. Now that your project uses modules, you may need to open your packages to dependencies or explicitly include transitive dependencies that are required by your dependencies that do not declare them all in a `modules-info.java`. *(Note: In particular, some amazon SDK dependencies do not provide modular jars but may require your project to reference the libraries they use. You might need to add **`requires`** statement to your modules-info.java to reference those dependencies. See this discussion thread on modularization of **aws 2**.)*
35 | 1. Make sure the project still runs!
36 |
37 | ## Section 3: Write Unit Tests and Refactor Project to Support Unit Tests
38 |
39 | In this section, you will write unit tests for the Security Service. Each of the requirements below should be verified by one or more unit tests. Make sure to put these unit tests in a new package that has the same name as the package containing the Security Service.
40 |
41 | You do **NOT** need to test the Image Service or the Repository, so you should use `@Mock`s to help substitute dependencies and keep the scope of each unit test narrow. You should use JUnit 5 features like `@ParameterizedTest` and `ArgumentMatchers` to ensure your tests cover branching conditions.
42 |
43 | Each of the requirements below should be verified by one or more unit tests. All of these test the **Security Service**, so make sure your tests don't depend on the implementation of the Repository or the Image Service. *Remember, you can use ****`Mocks`**** to replace these services in your unit tests.*
44 |
45 | You should also write interfaces to describe the necessary behaviors of your dependencies to make them easier to Mock. We’re already using a SecurityRepository interface, but we have no interface to describe the behavior of our Image Service. Create an interface that makes it easy to test our application regardless of whether we’re using the `AwsImageService` or `FakeImageService`.
46 |
47 | ### *Optional Stand Out Task:* Connect Your Project to the AWS Image Recognition Library
48 |
49 | > Once you have created an interface for your image service, complete the steps described in the AwsImageService to create credentials and provide them in a properties file for your application. Change the ImageService implementation class in the CatpointGui class to use the AwsImageService instead of the FakeImageService. Try submitting different types of images and see what comes back!
50 |
51 | 
52 |
53 | **While you are writing tests, it's possible you may need to refactor the application in order to make all of the requirements testable.** For example, parts of the business logic may be contained in the GUI or repository classes. You may have to move this logic into the security service to be tested.
54 |
55 | Remember, a failing unit test could mean one of two things:
56 |
57 | 1. Your unit test is faulty.
58 | 1. Something in your program isn't working.
59 |
60 | Some of these requirements might not be properly implemented, so, even if you write the correct unit test, it might still fail. You will fix any faulty or missing requirements in the next section.
61 |
62 | #### Application Requirements to Test:
63 |
64 | 1. If alarm is armed *and* a sensor becomes activated, put the system into pending alarm status.
65 | 1. If alarm is armed *and* a sensor becomes activated *and* the system is already pending alarm, set off the alarm.
66 | 1. If pending alarm *and* all sensors are inactive, return to no alarm state.
67 | 1. If alarm is active, change in sensor state should not affect the alarm state.
68 | 1. If a sensor is activated *while* already active *and* the system is in pending state, change it to alarm state.
69 | 1. If a sensor is deactivated *while* already inactive, make no changes to the alarm state.
70 | 1. If the camera image contains a cat *while* the system is armed-home, put the system into alarm status.
71 | 1. If the camera image does not contain a cat, change the status to no alarm *as long as* the sensors are not active.
72 | 1. If the system is disarmed, set the status to no alarm.
73 | 1. If the system is armed, reset all sensors to inactive.
74 | 1. If the system is armed-home *while* the camera shows a cat, set the alarm status to alarm.
75 |
76 | *Reminder*: If you find yourself relying on the behavior of another service, you may want to consider using a Mock!
77 |
78 | ## Section 4: Fix Any Bugs You Find With Your Unit Tests!
79 | As we stated in the previous section, a failing unit test could mean one of two things:
80 | 1. Your unit test is faulty.
81 | 2. Something in your program isn't working.
82 |
83 | Your task is to make sure all of the Application Requirements are properly implemented. Some requirements may not be performed and some bugs may produce unexpected behavior. After you fix any broken requirements, all of your unit tests should pass!
84 |
85 | ### Application Requirements to Test:
86 | 1. If alarm is armed _and_ a sensor becomes activated, put the system into pending alarm status.
87 | 2. If alarm is armed _and_ a sensor becomes activated _and_ the system is already pending alarm, set off the alarm.
88 | 3. If pending alarm _and_ all sensors are inactive, return to no alarm state.
89 | 4. If alarm is active, change in sensor state should not affect the alarm state.
90 | 5. If a sensor is activated _while_ already active _and_ the system is in pending state, change it to alarm state.
91 | 6. If a sensor is deactivated _while_ already inactive, make no changes to the alarm state.
92 | 7. If the camera image contains a cat _while_ the system is armed-home, put the system into alarm status.
93 | 8. If the camera image does not contain a cat, change the status to no alarm _as long as_ the sensors are not active.
94 | 9. If the system is disarmed, set the status to no alarm.
95 | 10. If the system is armed, reset all sensors to inactive.
96 | 11. If the system is armed-home _while_ the camera shows a cat, set the alarm status to alarm.
97 |
98 | 
99 |
100 | ## Section 5: Check Unit Test Coverage
101 | Use IntelliJ to check code coverage. Our goal is to cover everything in the Security Service. Other teams will be maintaining our Image Service so we’ll focus strictly on the behavior of the Security Service.
102 |
103 | 
104 |
105 | **Your goal is to provide full coverage of all methods that implement the application requirements.** You don’t need to test trivial methods like getters or setters, but you do need to make sure that all the lines in your other methods are reachable by the unit tests.
106 |
107 | 
108 |
109 | ### *Optional Stand Out Task:* Integration Tests
110 |
111 | > Create a FakeSecurityRepository class that works just like the `PretendDatabaseSecurityRepository` class (except without the property files). Create a second test class called `SecurityServiceIntegrationTest.java` and write methods that test our requirements as integration tests.
112 |
113 | > These tests can call service methods and then use JUnit Assertions to verify that the values you retrieve after performing operations are the expected values.
114 |
115 | ## Section 6: Build the Application into an Executable JAR
116 | Update your `pom.xml` to use a maven plugin that allows you to compile your application into an executable JAR. Confirm that you can run the program by running the jar file. Execute the Maven goal that builds the JAR and start the application from the command line.
117 |
118 | Submit a screenshot titled `executable_jar.png` that shows you running the executable jar from the command line and the application launching. Use the command `java -jar [yourjarname]` to run it.
119 |
120 | 
121 |
122 | ## Section 7: Add Static Analysis to Build
123 | Add a Reporting tag to your pom that contains the `spotbugs-maven-plugin` and use it to generate a `spotbugs.html` report in your project’s `/target/site` directory.
124 |
125 | You should fix any of the errors it finds that are High priority. You are welcome, though not required, to address any other errors you find as well!
126 |
127 | ### Project Submission
128 |
129 | For your submission, please submit the following:
130 | - Completed project code should be uploaded either to GitHub or a .zip file. Make sure to include the entire project folder.
131 |
132 | ### Double-Check the Rubric
133 | Make sure you have completed all the rubric items [here](https://review.udacity.com/#!/rubrics/3010/view).
134 |
135 | ### Submit your Project
136 |
137 | You can submit your project by uploading a zip file or selecting your GitHub repo.
138 |
139 |
--------------------------------------------------------------------------------
/UdaSecurity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/udacity/cd0384-java-application-deployment-projectstarter/2e46f912af681aac29254b594706e42c15aabfdb/UdaSecurity.png
--------------------------------------------------------------------------------
/code_coverage_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/udacity/cd0384-java-application-deployment-projectstarter/2e46f912af681aac29254b594706e42c15aabfdb/code_coverage_1.png
--------------------------------------------------------------------------------
/code_coverage_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/udacity/cd0384-java-application-deployment-projectstarter/2e46f912af681aac29254b594706e42c15aabfdb/code_coverage_2.png
--------------------------------------------------------------------------------
/gui_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/udacity/cd0384-java-application-deployment-projectstarter/2e46f912af681aac29254b594706e42c15aabfdb/gui_1.png
--------------------------------------------------------------------------------
/gui_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/udacity/cd0384-java-application-deployment-projectstarter/2e46f912af681aac29254b594706e42c15aabfdb/gui_2.png
--------------------------------------------------------------------------------
/jar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/udacity/cd0384-java-application-deployment-projectstarter/2e46f912af681aac29254b594706e42c15aabfdb/jar.png
--------------------------------------------------------------------------------
/pom_xml.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/udacity/cd0384-java-application-deployment-projectstarter/2e46f912af681aac29254b594706e42c15aabfdb/pom_xml.png
--------------------------------------------------------------------------------
/starter/README.md:
--------------------------------------------------------------------------------
1 | # UdaSecurity
2 |
3 | 
4 |
5 | Your company, **Udasecurity**, has created a home security application. This application tracks the status of sensors, monitors camera input, and changes the alarm state of the system based on inputs. Users can arm the system for when they’re home or away as well as disarm the system.
6 |
7 | The wild success of your application means that you have to prepare to scale your software. You’ll need to write unit tests for all of the major operations the application performs so that you can safely make more changes in the future. You also need to use maven to streamline the build process and automate your tests and code analysis. More urgently, you need to make sure your application actually does what it’s supposed to do, and so one of writing thorough unit tests will help you find any bugs that already exist.
8 |
9 | The image analysis service used by this application has proven popular as well, and another team wants to use it in their project. To accomplish this, you must separate the Image Service from the program and package it as a separate module to be included both in your own project and in other projects.
10 |
11 | The end goal for this assignment is to split the project into multiple modules, refactor it to be unit-testable, write unit tests to cover all the main requirements for the Security portion of the application and fix any bugs that you find in the process. You’ll also update the build process to automatically run unit tests, perform static code analysis, and build the code into an executable jar file.
12 |
13 | ## Section 1: Update `pom.xml` with Missing Dependencies
14 | This app was initially built by including jar files for each dependency manually, but now we are modernizing the dependency management by using Maven to manage our dependencies and their versions for us.
15 |
16 | The project has already been moved into a maven file structure for you, but you’ll need to identify missing dependencies and add their artifacts to your pom.xml until you can run the project successfully. Look throughout the project directory in order to make sure you find and add all the appropriate dependencies.
17 |
18 | You'll know you've added all of the correct dependencies when the project runs without errors.
19 |
20 | 
21 |
22 | ## Section 2: Split the Image Service into its Own Project
23 |
24 | Now that you have identified all the dependencies and can run the project, it’s time to split things up! Remember another team wants to use the Image Service in their project. To accomplish this, you must separate the Image Service from the program and package it as a separate module to be included both in your own project and in other projects
25 |
26 | ### Splitting Things Up
27 |
28 | 1. Use either maven or your IDE to create a new maven project that will be the parent project for the two modules you will be creating.
29 | 1. Inside of the parent project, create one module for your Security Security and one module for your Image service. (*Note: Use one parent pom at the top level and one child pom for each module.*)
30 | 1. Move all components into their proper modules.
31 | 1. Update dependencies in the poms so that shared dependencies are in the parent pom, but unshared dependencies are in the child poms.
32 | 1. Use the pluginManagement tag in the parent pom to set the latest versions for the core plugins used by the maven lifecycle, such as the maven-compiler-plugin.
33 | 1. Create a module descriptor for each package. You will have to provide the correct `export` and `requires` statements in each of these descriptors.
34 | 1. Address transitive dependencies. Now that your project uses modules, you may need to open your packages to dependencies or explicitly include transitive dependencies that are required by your dependencies that do not declare them all in a `modules-info.java`. *(Note: In particular, some amazon SDK dependencies do not provide modular jars but may require your project to reference the libraries they use. You might need to add **`requires`** statement to your modules-info.java to reference those dependencies. See this discussion thread on modularization of **aws 2**.)*
35 | 1. Make sure the project still runs!
36 |
37 | ## Section 3: Write Unit Tests and Refactor Project to Support Unit Tests
38 |
39 | In this section, you will write unit tests for the Security Service. Each of the requirements below should be verified by one or more unit tests. Make sure to put these unit tests in a new package that has the same name as the package containing the Security Service.
40 |
41 | You do **NOT** need to test the Image Service or the Repository, so you should use `@Mock`s to help substitute dependencies and keep the scope of each unit test narrow. You should use JUnit 5 features like `@ParameterizedTest` and `ArgumentMatchers` to ensure your tests cover branching conditions.
42 |
43 | Each of the requirements below should be verified by one or more unit tests. All of these test the **Security Service**, so make sure your tests don't depend on the implementation of the Repository or the Image Service. *Remember, you can use ****`Mocks`**** to replace these services in your unit tests.*
44 |
45 | You should also write interfaces to describe the necessary behaviors of your dependencies to make them easier to Mock. We’re already using a SecurityRepository interface, but we have no interface to describe the behavior of our Image Service. Create an interface that makes it easy to test our application regardless of whether we’re using the `AwsImageService` or `FakeImageService`.
46 |
47 | ### *Optional Stand Out Task:* Connect Your Project to the AWS Image Recognition Library
48 |
49 | > Once you have created an interface for your image service, complete the steps described in the AwsImageService to create credentials and provide them in a properties file for your application. Change the ImageService implementation class in the CatpointGui class to use the AwsImageService instead of the FakeImageService. Try submitting different types of images and see what comes back!
50 |
51 | 
52 |
53 | **While you are writing tests, it's possible you may need to refactor the application in order to make all of the requirements testable.** For example, parts of the business logic may be contained in the GUI or repository classes. You may have to move this logic into the security service to be tested.
54 |
55 | Remember, a failing unit test could mean one of two things:
56 |
57 | 1. Your unit test is faulty.
58 | 1. Something in your program isn't working.
59 |
60 | Some of these requirements might not be properly implemented, so, even if you write the correct unit test, it might still fail. You will fix any faulty or missing requirements in the next section.
61 |
62 | #### Application Requirements to Test:
63 |
64 | 1. If alarm is armed *and* a sensor becomes activated, put the system into pending alarm status.
65 | 1. If alarm is armed *and* a sensor becomes activated *and* the system is already pending alarm, set off the alarm.
66 | 1. If pending alarm *and* all sensors are inactive, return to no alarm state.
67 | 1. If alarm is active, change in sensor state should not affect the alarm state.
68 | 1. If a sensor is activated *while* already active *and* the system is in pending state, change it to alarm state.
69 | 1. If a sensor is deactivated *while* already inactive, make no changes to the alarm state.
70 | 1. If the camera image contains a cat *while* the system is armed-home, put the system into alarm status.
71 | 1. If the camera image does not contain a cat, change the status to no alarm *as long as* the sensors are not active.
72 | 1. If the system is disarmed, set the status to no alarm.
73 | 1. If the system is armed, reset all sensors to inactive.
74 | 1. If the system is armed-home *while* the camera shows a cat, set the alarm status to alarm.
75 |
76 | *Reminder*: If you find yourself relying on the behavior of another service, you may want to consider using a Mock!
77 |
78 | ## Section 4: Fix Any Bugs You Find With Your Unit Tests!
79 | As we stated in the previous section, a failing unit test could mean one of two things:
80 | 1. Your unit test is faulty.
81 | 2. Something in your program isn't working.
82 |
83 | Your task is to make sure all of the Application Requirements are properly implemented. Some requirements may not be performed and some bugs may produce unexpected behavior. After you fix any broken requirements, all of your unit tests should pass!
84 |
85 | ### Application Requirements to Test:
86 | 1. If alarm is armed _and_ a sensor becomes activated, put the system into pending alarm status.
87 | 2. If alarm is armed _and_ a sensor becomes activated _and_ the system is already pending alarm, set off the alarm.
88 | 3. If pending alarm _and_ all sensors are inactive, return to no alarm state.
89 | 4. If alarm is active, change in sensor state should not affect the alarm state.
90 | 5. If a sensor is activated _while_ already active _and_ the system is in pending state, change it to alarm state.
91 | 6. If a sensor is deactivated _while_ already inactive, make no changes to the alarm state.
92 | 7. If the camera image contains a cat _while_ the system is armed-home, put the system into alarm status.
93 | 8. If the camera image does not contain a cat, change the status to no alarm _as long as_ the sensors are not active.
94 | 9. If the system is disarmed, set the status to no alarm.
95 | 10. If the system is armed, reset all sensors to inactive.
96 | 11. If the system is armed-home _while_ the camera shows a cat, set the alarm status to alarm.
97 |
98 | 
99 |
100 | ## Section 5: Check Unit Test Coverage
101 | Use IntelliJ to check code coverage. Our goal is to cover everything in the Security Service. Other teams will be maintaining our Image Service so we’ll focus strictly on the behavior of the Security Service.
102 |
103 | 
104 |
105 | **Your goal is to provide full coverage of all methods that implement the application requirements.** You don’t need to test trivial methods like getters or setters, but you do need to make sure that all the lines in your other methods are reachable by the unit tests.
106 |
107 | 
108 |
109 | ### *Optional Stand Out Task:* Integration Tests
110 |
111 | > Create a FakeSecurityRepository class that works just like the `PretendDatabaseSecurityRepository` class (except without the property files). Create a second test class called `SecurityServiceIntegrationTest.java` and write methods that test our requirements as integration tests.
112 |
113 | > These tests can call service methods and then use JUnit Assertions to verify that the values you retrieve after performing operations are the expected values.
114 |
115 | ## Section 6: Build the Application into an Executable JAR
116 | Update your `pom.xml` to use a maven plugin that allows you to compile your application into an executable JAR. Confirm that you can run the program by running the jar file. Execute the Maven goal that builds the JAR and start the application from the command line.
117 |
118 | Submit a screenshot titled `executable_jar.png` that shows you running the executable jar from the command line and the application launching. Use the command `java -jar [yourjarname]` to run it.
119 |
120 | 
121 |
122 | ## Section 7: Add Static Analysis to Build
123 | Add a Reporting tag to your pom that contains the `spotbugs-maven-plugin` and use it to generate a `spotbugs.html` report in your project’s `/target/site` directory.
124 |
125 | You should fix any of the errors it finds that are High priority. You are welcome, though not required, to address any other errors you find as well!
126 |
127 | ### Project Submission
128 |
129 | For your submission, please submit the following:
130 | - Completed project code should be uploaded either to GitHub or a .zip file. Make sure to include the entire project folder.
131 |
132 | ### Double-Check the Rubric
133 | Make sure you have completed all the rubric items [here](https://review.udacity.com/#!/rubrics/3010/view).
134 |
135 | ### Submit your Project
136 |
137 | You can submit your project by uploading a zip file or selecting your GitHub repo.
138 |
139 |
140 |
--------------------------------------------------------------------------------
/starter/UdaSecurity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/udacity/cd0384-java-application-deployment-projectstarter/2e46f912af681aac29254b594706e42c15aabfdb/starter/UdaSecurity.png
--------------------------------------------------------------------------------
/starter/catpoint-parent/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 | 4.0.0
6 |
7 | com.udacity.catpoint
8 | catpoint-parent
9 | 1.0-SNAPSHOT
10 |
11 | catpoint-parent
12 | http://www.example.com
13 |
14 |
15 | UTF-8
16 | 14
17 | 14
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | maven-clean-plugin
30 | 3.1.0
31 |
32 |
33 |
34 | maven-resources-plugin
35 | 3.0.2
36 |
37 |
38 | maven-compiler-plugin
39 | 3.8.0
40 |
41 |
42 | maven-surefire-plugin
43 | 2.22.1
44 |
45 |
46 | maven-jar-plugin
47 | 3.0.2
48 |
49 |
50 | maven-install-plugin
51 | 2.5.2
52 |
53 |
54 | maven-deploy-plugin
55 | 2.8.2
56 |
57 |
58 |
59 | maven-site-plugin
60 | 3.9.1
61 |
62 |
63 | maven-project-info-reports-plugin
64 | 3.1.1
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/starter/catpoint-parent/sample-cat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/udacity/cd0384-java-application-deployment-projectstarter/2e46f912af681aac29254b594706e42c15aabfdb/starter/catpoint-parent/sample-cat.jpg
--------------------------------------------------------------------------------
/starter/catpoint-parent/sample-not-a-cat-fail.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/udacity/cd0384-java-application-deployment-projectstarter/2e46f912af681aac29254b594706e42c15aabfdb/starter/catpoint-parent/sample-not-a-cat-fail.jpg
--------------------------------------------------------------------------------
/starter/catpoint-parent/sample-not-cat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/udacity/cd0384-java-application-deployment-projectstarter/2e46f912af681aac29254b594706e42c15aabfdb/starter/catpoint-parent/sample-not-cat.jpg
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/main/java/com/udacity/catpoint/application/CatpointApp.java:
--------------------------------------------------------------------------------
1 | package com.udacity.catpoint.application;
2 |
3 | /**
4 | * This is the main class that launches the application.
5 | */
6 | public class CatpointApp {
7 | public static void main(String[] args) {
8 | CatpointGui gui = new CatpointGui();
9 | gui.setVisible(true);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/main/java/com/udacity/catpoint/application/CatpointGui.java:
--------------------------------------------------------------------------------
1 | package com.udacity.catpoint.application;
2 |
3 | import com.udacity.catpoint.data.PretendDatabaseSecurityRepositoryImpl;
4 | import com.udacity.catpoint.data.SecurityRepository;
5 | import com.udacity.catpoint.service.FakeImageService;
6 | import com.udacity.catpoint.service.SecurityService;
7 | import net.miginfocom.swing.MigLayout;
8 |
9 | import javax.swing.*;
10 |
11 | /**
12 | * This is the primary JFrame for the application that contains all the top-level JPanels.
13 | *
14 | * We're not using any dependency injection framework, so this class also handles constructing
15 | * all our dependencies and providing them to other classes as necessary.
16 | */
17 | public class CatpointGui extends JFrame {
18 | private SecurityRepository securityRepository = new PretendDatabaseSecurityRepositoryImpl();
19 | private FakeImageService imageService = new FakeImageService();
20 | private SecurityService securityService = new SecurityService(securityRepository, imageService);
21 | private DisplayPanel displayPanel = new DisplayPanel(securityService);
22 | private ControlPanel controlPanel = new ControlPanel(securityService);
23 | private SensorPanel sensorPanel = new SensorPanel(securityService);
24 | private ImagePanel imagePanel = new ImagePanel(securityService);
25 |
26 | public CatpointGui() {
27 | setLocation(100, 100);
28 | setSize(600, 850);
29 | setTitle("Very Secure App");
30 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
31 |
32 | JPanel mainPanel = new JPanel();
33 | mainPanel.setLayout(new MigLayout());
34 | mainPanel.add(displayPanel, "wrap");
35 | mainPanel.add(imagePanel, "wrap");
36 | mainPanel.add(controlPanel, "wrap");
37 | mainPanel.add(sensorPanel);
38 |
39 | getContentPane().add(mainPanel);
40 |
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/main/java/com/udacity/catpoint/application/ControlPanel.java:
--------------------------------------------------------------------------------
1 | package com.udacity.catpoint.application;
2 |
3 | import com.udacity.catpoint.data.ArmingStatus;
4 | import com.udacity.catpoint.service.SecurityService;
5 | import com.udacity.catpoint.service.StyleService;
6 | import net.miginfocom.swing.MigLayout;
7 |
8 | import javax.swing.*;
9 | import java.util.Arrays;
10 | import java.util.Map;
11 | import java.util.stream.Collectors;
12 |
13 | /**
14 | * JPanel containing the buttons to manipulate arming status of the system.
15 | */
16 | public class ControlPanel extends JPanel {
17 |
18 | private SecurityService securityService;
19 | private Map buttonMap;
20 |
21 |
22 | public ControlPanel(SecurityService securityService) {
23 | super();
24 | setLayout(new MigLayout());
25 | this.securityService = securityService;
26 |
27 | JLabel panelLabel = new JLabel("System Control");
28 | panelLabel.setFont(StyleService.HEADING_FONT);
29 |
30 | add(panelLabel, "span 3, wrap");
31 |
32 | //create a map of each status type to a corresponding JButton
33 | buttonMap = Arrays.stream(ArmingStatus.values())
34 | .collect(Collectors.toMap(status -> status, status -> new JButton(status.getDescription())));
35 |
36 | //add an action listener to each button that applies its arming status and recolors all the buttons
37 | buttonMap.forEach((k, v) -> {
38 | v.addActionListener(e -> {
39 | securityService.setArmingStatus(k);
40 | buttonMap.forEach((status, button) -> button.setBackground(status == k ? status.getColor() : null));
41 | });
42 | });
43 |
44 | //map order above is arbitrary, so loop again in order to add buttons in enum-order
45 | Arrays.stream(ArmingStatus.values()).forEach(status -> add(buttonMap.get(status)));
46 |
47 | ArmingStatus currentStatus = securityService.getArmingStatus();
48 | buttonMap.get(currentStatus).setBackground(currentStatus.getColor());
49 |
50 |
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/main/java/com/udacity/catpoint/application/DisplayPanel.java:
--------------------------------------------------------------------------------
1 | package com.udacity.catpoint.application;
2 |
3 | import com.udacity.catpoint.data.AlarmStatus;
4 | import com.udacity.catpoint.service.SecurityService;
5 | import com.udacity.catpoint.service.StyleService;
6 | import net.miginfocom.swing.MigLayout;
7 |
8 | import javax.swing.*;
9 |
10 | /**
11 | * Displays the current status of the system. Implements the StatusListener
12 | * interface so that it can be notified whenever the status changes.
13 | */
14 | public class DisplayPanel extends JPanel implements StatusListener {
15 |
16 | private JLabel currentStatusLabel;
17 |
18 | public DisplayPanel(SecurityService securityService) {
19 | super();
20 | setLayout(new MigLayout());
21 |
22 | securityService.addStatusListener(this);
23 |
24 | JLabel panelLabel = new JLabel("Very Secure Home Security");
25 | JLabel systemStatusLabel = new JLabel("System Status:");
26 | currentStatusLabel = new JLabel();
27 |
28 | panelLabel.setFont(StyleService.HEADING_FONT);
29 |
30 | notify(securityService.getAlarmStatus());
31 |
32 | add(panelLabel, "span 2, wrap");
33 | add(systemStatusLabel);
34 | add(currentStatusLabel, "wrap");
35 |
36 | }
37 |
38 | @Override
39 | public void notify(AlarmStatus status) {
40 | currentStatusLabel.setText(status.getDescription());
41 | currentStatusLabel.setBackground(status.getColor());
42 | currentStatusLabel.setOpaque(true);
43 | }
44 |
45 | @Override
46 | public void catDetected(boolean catDetected) {
47 | // no behavior necessary
48 | }
49 |
50 | @Override
51 | public void sensorStatusChanged() {
52 | // no behavior necessary
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/main/java/com/udacity/catpoint/application/ImagePanel.java:
--------------------------------------------------------------------------------
1 | package com.udacity.catpoint.application;
2 |
3 | import com.udacity.catpoint.data.AlarmStatus;
4 | import com.udacity.catpoint.service.SecurityService;
5 | import com.udacity.catpoint.service.StyleService;
6 | import net.miginfocom.swing.MigLayout;
7 |
8 | import javax.imageio.ImageIO;
9 | import javax.swing.*;
10 | import java.awt.*;
11 | import java.awt.image.BufferedImage;
12 | import java.io.File;
13 | import java.io.IOException;
14 |
15 | /** Panel containing the 'camera' output. Allows users to 'refresh' the camera
16 | * by uploading their own picture, and 'scan' the picture, sending it for image analysis
17 | */
18 | public class ImagePanel extends JPanel implements StatusListener {
19 | private SecurityService securityService;
20 |
21 | private JLabel cameraHeader;
22 | private JLabel cameraLabel;
23 | private BufferedImage currentCameraImage;
24 |
25 | private int IMAGE_WIDTH = 300;
26 | private int IMAGE_HEIGHT = 225;
27 |
28 | public ImagePanel(SecurityService securityService) {
29 | super();
30 | setLayout(new MigLayout());
31 | this.securityService = securityService;
32 | securityService.addStatusListener(this);
33 |
34 | cameraHeader = new JLabel("Camera Feed");
35 | cameraHeader.setFont(StyleService.HEADING_FONT);
36 |
37 | cameraLabel = new JLabel();
38 | cameraLabel.setBackground(Color.WHITE);
39 | cameraLabel.setPreferredSize(new Dimension(IMAGE_WIDTH, IMAGE_HEIGHT));
40 | cameraLabel.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
41 |
42 | //button allowing users to select a file to be the current camera image
43 | JButton addPictureButton = new JButton("Refresh Camera");
44 | addPictureButton.addActionListener(e -> {
45 | JFileChooser chooser = new JFileChooser();
46 | chooser.setCurrentDirectory(new File("."));
47 | chooser.setDialogTitle("Select Picture");
48 | chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
49 | if(chooser.showOpenDialog(this) != JFileChooser.APPROVE_OPTION) {
50 | return;
51 | }
52 | try {
53 | currentCameraImage = ImageIO.read(chooser.getSelectedFile());
54 | Image tmp = new ImageIcon(currentCameraImage).getImage();
55 | cameraLabel.setIcon(new ImageIcon(tmp.getScaledInstance(IMAGE_WIDTH, IMAGE_HEIGHT, Image.SCALE_SMOOTH)));
56 | } catch (IOException |NullPointerException ioe) {
57 | JOptionPane.showMessageDialog(null, "Invalid image selected.");
58 | }
59 | repaint();
60 | });
61 |
62 | //button that sends the image to the image service
63 | JButton scanPictureButton = new JButton("Scan Picture");
64 | scanPictureButton.addActionListener(e -> {
65 | securityService.processImage(currentCameraImage);
66 | });
67 |
68 | add(cameraHeader, "span 3, wrap");
69 | add(cameraLabel, "span 3, wrap");
70 | add(addPictureButton);
71 | add(scanPictureButton);
72 | }
73 |
74 | @Override
75 | public void notify(AlarmStatus status) {
76 | //no behavior necessary
77 | }
78 |
79 | @Override
80 | public void catDetected(boolean catDetected) {
81 | if(catDetected) {
82 | cameraHeader.setText("DANGER - CAT DETECTED");
83 | } else {
84 | cameraHeader.setText("Camera Feed - No Cats Detected");
85 | }
86 | }
87 |
88 | @Override
89 | public void sensorStatusChanged() {
90 | //no behavior necessary
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/main/java/com/udacity/catpoint/application/SensorPanel.java:
--------------------------------------------------------------------------------
1 | package com.udacity.catpoint.application;
2 |
3 | import com.udacity.catpoint.data.Sensor;
4 | import com.udacity.catpoint.data.SensorType;
5 | import com.udacity.catpoint.service.SecurityService;
6 | import com.udacity.catpoint.service.StyleService;
7 | import net.miginfocom.swing.MigLayout;
8 |
9 | import javax.swing.*;
10 |
11 | /**
12 | * Panel that allows users to add sensors to their system. Sensors may be
13 | * manually set to "active" and "inactive" to test the system.
14 | */
15 | public class SensorPanel extends JPanel {
16 |
17 | private SecurityService securityService;
18 |
19 | private JLabel panelLabel = new JLabel("Sensor Management");
20 | private JLabel newSensorName = new JLabel("Name:");
21 | private JLabel newSensorType = new JLabel("Sensor Type:");
22 | private JTextField newSensorNameField = new JTextField();
23 | private JComboBox newSensorTypeDropdown = new JComboBox(SensorType.values());
24 | private JButton addNewSensorButton = new JButton("Add New Sensor");
25 |
26 | private JPanel sensorListPanel;
27 | private JPanel newSensorPanel;
28 |
29 | public SensorPanel(SecurityService securityService) {
30 | super();
31 | setLayout(new MigLayout());
32 | this.securityService = securityService;
33 |
34 | panelLabel.setFont(StyleService.HEADING_FONT);
35 | addNewSensorButton.addActionListener(e ->
36 | addSensor(new Sensor(newSensorNameField.getText(),
37 | SensorType.valueOf(newSensorTypeDropdown.getSelectedItem().toString()))));
38 |
39 | newSensorPanel = buildAddSensorPanel();
40 | sensorListPanel = new JPanel();
41 | sensorListPanel.setLayout(new MigLayout());
42 |
43 | updateSensorList(sensorListPanel);
44 |
45 | add(panelLabel, "wrap");
46 | add(newSensorPanel, "span");
47 | add(sensorListPanel, "span");
48 | }
49 |
50 | /**
51 | * Builds the panel with the form for adding a new sensor
52 | */
53 | private JPanel buildAddSensorPanel() {
54 | JPanel p = new JPanel();
55 | p.setLayout(new MigLayout());
56 | p.add(newSensorName);
57 | p.add(newSensorNameField, "width 50:100:200");
58 | p.add(newSensorType);
59 | p.add(newSensorTypeDropdown, "wrap");
60 | p.add(addNewSensorButton, "span 3");
61 | return p;
62 | }
63 |
64 | /**
65 | * Requests the current list of sensors and updates the provided panel to display them. Sensors
66 | * will display in the order that they are created.
67 | * @param p The Panel to populate with the current list of sensors
68 | */
69 | private void updateSensorList(JPanel p) {
70 | p.removeAll();
71 | securityService.getSensors().stream().sorted().forEach(s -> {
72 | JLabel sensorLabel = new JLabel(String.format("%s(%s): %s", s.getName(), s.getSensorType().toString(),(s.getActive() ? "Active" : "Inactive")));
73 | JButton sensorToggleButton = new JButton((s.getActive() ? "Deactivate" : "Activate"));
74 | JButton sensorRemoveButton = new JButton("Remove Sensor");
75 |
76 | sensorToggleButton.addActionListener(e -> setSensorActivity(s, !s.getActive()) );
77 | sensorRemoveButton.addActionListener(e -> removeSensor(s));
78 |
79 | //hard code some sizes, tsk tsk
80 | p.add(sensorLabel, "width 300:300:300");
81 | p.add(sensorToggleButton, "width 100:100:100");
82 | p.add(sensorRemoveButton, "wrap");
83 | });
84 |
85 | repaint();
86 | revalidate();
87 | }
88 |
89 | /**
90 | * Asks the securityService to change a sensor activation status and then rebuilds the current sensor list
91 | * @param sensor The sensor to update
92 | * @param isActive The sensor's activation status
93 | */
94 | private void setSensorActivity(Sensor sensor, Boolean isActive) {
95 | securityService.changeSensorActivationStatus(sensor, isActive);
96 | updateSensorList(sensorListPanel);
97 | }
98 |
99 | /**
100 | * Adds a sensor to the securityService and then rebuilds the sensor list
101 | * @param sensor The sensor to add
102 | */
103 | private void addSensor(Sensor sensor) {
104 | if(securityService.getSensors().size() < 4) {
105 | securityService.addSensor(sensor);
106 | updateSensorList(sensorListPanel);
107 | } else {
108 | JOptionPane.showMessageDialog(null, "To add more than 4 sensors, please subscribe to our Premium Membership!");
109 | }
110 | }
111 |
112 | /**
113 | * Remove a sensor from the securityService and then rebuild the sensor list
114 | * @param sensor The sensor to remove
115 | */
116 | private void removeSensor(Sensor sensor) {
117 | securityService.removeSensor(sensor);
118 | updateSensorList(sensorListPanel);
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/main/java/com/udacity/catpoint/application/StatusListener.java:
--------------------------------------------------------------------------------
1 | package com.udacity.catpoint.application;
2 |
3 | import com.udacity.catpoint.data.AlarmStatus;
4 |
5 | /**
6 | * Identifies a component that should be notified whenever the system status changes
7 | */
8 | public interface StatusListener {
9 | void notify(AlarmStatus status);
10 | void catDetected(boolean catDetected);
11 | void sensorStatusChanged();
12 | }
13 |
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/main/java/com/udacity/catpoint/data/AlarmStatus.java:
--------------------------------------------------------------------------------
1 | package com.udacity.catpoint.data;
2 |
3 | import java.awt.*;
4 |
5 | /**
6 | * List of potential states the alarm can have. Also contains metadata about what
7 | * text and color is associated with the alarm.
8 | */
9 | public enum AlarmStatus {
10 | NO_ALARM("Cool and Good", new Color(120,200,30)),
11 | PENDING_ALARM("I'm in Danger...", new Color(200,150,20)),
12 | ALARM("Awooga!", new Color(250,80,50));
13 |
14 | private final String description;
15 | private final Color color;
16 |
17 | AlarmStatus(String description, Color color) {
18 | this.description = description;
19 | this.color = color;
20 | }
21 |
22 | public String getDescription() {
23 | return description;
24 | }
25 |
26 | public Color getColor() {
27 | return color;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/main/java/com/udacity/catpoint/data/ArmingStatus.java:
--------------------------------------------------------------------------------
1 | package com.udacity.catpoint.data;
2 |
3 | import java.awt.*;
4 |
5 | /**
6 | * List of potential states the security system can use to describe how the system is armed.
7 | * Also contains metadata about what text and color is associated with the arming status.
8 | */
9 | public enum ArmingStatus {
10 | DISARMED("Disarmed", new Color(120,200,30)),
11 | ARMED_HOME("Armed - At Home", new Color(190,180,50)),
12 | ARMED_AWAY("Armed - Away", new Color(170,30,150));
13 |
14 | private final String description;
15 | private final Color color;
16 |
17 | ArmingStatus(String description, Color color) {
18 | this.description = description;
19 | this.color = color;
20 | }
21 |
22 | public String getDescription() {
23 | return description;
24 | }
25 |
26 | public Color getColor() {
27 | return color;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/main/java/com/udacity/catpoint/data/PretendDatabaseSecurityRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.udacity.catpoint.data;
2 |
3 | import com.google.common.reflect.TypeToken;
4 | import com.google.gson.Gson;
5 |
6 | import java.lang.reflect.Type;
7 | import java.util.Set;
8 | import java.util.TreeSet;
9 | import java.util.prefs.Preferences;
10 |
11 | /**
12 | * Fake repository implementation for demo purposes. Stores state information in local
13 | * memory and writes it to user preferences between app loads. This implementation is
14 | * intentionally a little hard to use in unit tests, so watch out!
15 | */
16 | public class PretendDatabaseSecurityRepositoryImpl implements SecurityRepository{
17 |
18 | private Set sensors;
19 | private AlarmStatus alarmStatus;
20 | private ArmingStatus armingStatus;
21 |
22 | //preference keys
23 | private static final String SENSORS = "SENSORS";
24 | private static final String ALARM_STATUS = "ALARM_STATUS";
25 | private static final String ARMING_STATUS = "ARMING_STATUS";
26 |
27 | private static final Preferences prefs = Preferences.userNodeForPackage(PretendDatabaseSecurityRepositoryImpl.class);
28 | private static final Gson gson = new Gson(); //used to serialize objects into JSON
29 |
30 | public PretendDatabaseSecurityRepositoryImpl() {
31 | //load system state from prefs, or else default
32 | alarmStatus = AlarmStatus.valueOf(prefs.get(ALARM_STATUS, AlarmStatus.NO_ALARM.toString()));
33 | armingStatus = ArmingStatus.valueOf(prefs.get(ARMING_STATUS, ArmingStatus.DISARMED.toString()));
34 |
35 | //we've serialized our sensor objects for storage, which should be a good warning sign that
36 | // this is likely an impractical solution for a real system
37 | String sensorString = prefs.get(SENSORS, null);
38 | if(sensorString == null) {
39 | sensors = new TreeSet<>();
40 | } else {
41 | Type type = new TypeToken>() {
42 | }.getType();
43 | sensors = gson.fromJson(sensorString, type);
44 | }
45 | }
46 |
47 | @Override
48 | public void addSensor(Sensor sensor) {
49 | sensors.add(sensor);
50 | prefs.put(SENSORS, gson.toJson(sensors));
51 | }
52 |
53 | @Override
54 | public void removeSensor(Sensor sensor) {
55 | sensors.remove(sensor);
56 | prefs.put(SENSORS, gson.toJson(sensors));
57 | }
58 |
59 | @Override
60 | public void updateSensor(Sensor sensor) {
61 | sensors.remove(sensor);
62 | sensors.add(sensor);
63 | prefs.put(SENSORS, gson.toJson(sensors));
64 | }
65 |
66 | @Override
67 | public void setAlarmStatus(AlarmStatus alarmStatus) {
68 | this.alarmStatus = alarmStatus;
69 | prefs.put(ALARM_STATUS, this.alarmStatus.toString());
70 | }
71 |
72 | @Override
73 | public void setArmingStatus(ArmingStatus armingStatus) {
74 | this.armingStatus = armingStatus;
75 | prefs.put(ARMING_STATUS, this.armingStatus.toString());
76 | }
77 |
78 | @Override
79 | public Set getSensors() {
80 | return sensors;
81 | }
82 |
83 | @Override
84 | public AlarmStatus getAlarmStatus() {
85 | return alarmStatus;
86 | }
87 |
88 | @Override
89 | public ArmingStatus getArmingStatus() {
90 | return armingStatus;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/main/java/com/udacity/catpoint/data/SecurityRepository.java:
--------------------------------------------------------------------------------
1 | package com.udacity.catpoint.data;
2 |
3 | import java.util.Set;
4 |
5 | /**
6 | * Interface showing the methods our security repository will need to support
7 | */
8 | public interface SecurityRepository {
9 | void addSensor(Sensor sensor);
10 | void removeSensor(Sensor sensor);
11 | void updateSensor(Sensor sensor);
12 | void setAlarmStatus(AlarmStatus alarmStatus);
13 | void setArmingStatus(ArmingStatus armingStatus);
14 | Set getSensors();
15 | AlarmStatus getAlarmStatus();
16 | ArmingStatus getArmingStatus();
17 |
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/main/java/com/udacity/catpoint/data/Sensor.java:
--------------------------------------------------------------------------------
1 | package com.udacity.catpoint.data;
2 |
3 |
4 | import com.google.common.collect.ComparisonChain;
5 |
6 | import java.util.Objects;
7 | import java.util.UUID;
8 |
9 | /**
10 | * Sensor POJO. Needs to know how to sort itself for display purposes.
11 | */
12 | public class Sensor implements Comparable {
13 | private UUID sensorId;
14 | private String name;
15 | private Boolean active;
16 | private SensorType sensorType;
17 |
18 | public Sensor(String name, SensorType sensorType) {
19 | this.name = name;
20 | this.sensorType = sensorType;
21 | this.sensorId = UUID.randomUUID();
22 | this.active = Boolean.FALSE;
23 | }
24 |
25 | @Override
26 | public boolean equals(Object o) {
27 | if (this == o) return true;
28 | if (o == null || getClass() != o.getClass()) return false;
29 | Sensor sensor = (Sensor) o;
30 | return sensorId.equals(sensor.sensorId);
31 | }
32 |
33 | @Override
34 | public int hashCode() {
35 | return Objects.hash(sensorId);
36 | }
37 |
38 | public String getName() {
39 | return name;
40 | }
41 |
42 | public void setName(String name) {
43 | this.name = name;
44 | }
45 |
46 | public Boolean getActive() {
47 | return active;
48 | }
49 |
50 | public void setActive(Boolean active) {
51 | this.active = active;
52 | }
53 |
54 | public SensorType getSensorType() {
55 | return sensorType;
56 | }
57 |
58 | public void setSensorType(SensorType sensorType) {
59 | this.sensorType = sensorType;
60 | }
61 |
62 | public UUID getSensorId() {
63 | return sensorId;
64 | }
65 |
66 | public void setSensorId(UUID sensorId) {
67 | this.sensorId = sensorId;
68 | }
69 |
70 | @Override
71 | public int compareTo(Sensor o) {
72 | return ComparisonChain.start()
73 | .compare(this.name, o.name)
74 | .compare(this.sensorType.toString(), o.sensorType.toString())
75 | .compare(this.sensorId, o.sensorId)
76 | .result();
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/main/java/com/udacity/catpoint/data/SensorType.java:
--------------------------------------------------------------------------------
1 | package com.udacity.catpoint.data;
2 |
3 | /**
4 | * List of available sensor types. Not currently used by system, other than for display.
5 | */
6 | public enum SensorType {
7 | DOOR, WINDOW, MOTION
8 | }
9 |
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/main/java/com/udacity/catpoint/service/AwsImageService.java:
--------------------------------------------------------------------------------
1 | package com.udacity.catpoint.service;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
6 | import software.amazon.awssdk.auth.credentials.AwsCredentials;
7 | import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
8 | import software.amazon.awssdk.core.SdkBytes;
9 | import software.amazon.awssdk.regions.Region;
10 | import software.amazon.awssdk.services.rekognition.RekognitionClient;
11 | import software.amazon.awssdk.services.rekognition.model.DetectLabelsRequest;
12 | import software.amazon.awssdk.services.rekognition.model.DetectLabelsResponse;
13 | import software.amazon.awssdk.services.rekognition.model.Image;
14 |
15 | import javax.imageio.ImageIO;
16 | import java.awt.image.BufferedImage;
17 | import java.io.ByteArrayOutputStream;
18 | import java.io.IOException;
19 | import java.io.InputStream;
20 | import java.util.Properties;
21 | import java.util.stream.Collectors;
22 |
23 | /**
24 | * Image Recognition Service that can identify cats. Requires aws credentials to be entered in config.properties to work.
25 | * Steps to make work (optional):
26 | * 1. Log into AWS and navigate to the AWS console
27 | * 2. Search for IAM then click on Users in the IAM nav bar
28 | * 3. Click Add User. Enter a user name and select Programmatic access
29 | * 4. Next to Permissions. Select 'Attach existing policies directly' and attack 'AmazonRekognitionFullAccess'
30 | * 5. Next through the remaining screens. Copy the 'Access key ID' and 'Secret access key' for this user.
31 | * 6. Create a config.properties file in the src/main/resources dir containing the keys referenced in this class
32 | * aws.id=[your access key id]
33 | * aws.secret=[your Secret access key]
34 | * aws.region=[an aws region of choice. For example: us-east-2]
35 | */
36 | public class AwsImageService {
37 |
38 | private Logger log = LoggerFactory.getLogger(AwsImageService.class);
39 |
40 | //aws recommendation is to maintain only a single instance of client objects
41 | private static RekognitionClient rekognitionClient;
42 |
43 | public AwsImageService() {
44 | Properties props = new Properties();
45 | try (InputStream is = getClass().getClassLoader().getResourceAsStream("config.properties")) {
46 | props.load(is);
47 | } catch (IOException ioe ) {
48 | log.error("Unable to initialize AWS Rekognition, no properties file found", ioe);
49 | return;
50 | }
51 |
52 | String awsId = props.getProperty("aws.id");
53 | String awsSecret = props.getProperty("aws.secret");
54 | String awsRegion = props.getProperty("aws.region");
55 |
56 | AwsCredentials awsCredentials = AwsBasicCredentials.create(awsId, awsSecret);
57 | rekognitionClient = RekognitionClient.builder()
58 | .credentialsProvider(StaticCredentialsProvider.create(awsCredentials))
59 | .region(Region.of(awsRegion))
60 | .build();
61 | }
62 |
63 | /**
64 | * Returns true if the provided image contains a cat.
65 | * @param image Image to scan
66 | * @param confidenceThreshhold Minimum threshhold to consider for cat. For example, 90.0f would require 90% confidence minimum
67 | * @return
68 | */
69 | public boolean imageContainsCat(BufferedImage image, float confidenceThreshhold) {
70 | Image awsImage = null;
71 | try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
72 | ImageIO.write(image, "jpg", os);
73 | awsImage = Image.builder().bytes(SdkBytes.fromByteArray(os.toByteArray())).build();
74 | } catch (IOException ioe) {
75 | log.error("Error building image byte array", ioe);
76 | return false;
77 | }
78 | DetectLabelsRequest detectLabelsRequest = DetectLabelsRequest.builder().image(awsImage).minConfidence(confidenceThreshhold).build();
79 | DetectLabelsResponse response = rekognitionClient.detectLabels(detectLabelsRequest);
80 | logLabelsForFun(response);
81 | return response.labels().stream().filter(l -> l.name().toLowerCase().contains("cat")).findFirst().isPresent();
82 | }
83 |
84 | private void logLabelsForFun(DetectLabelsResponse response) {
85 | log.info(response.labels().stream()
86 | .map(label -> String.format("%s(%.1f%%)", label.name(), label.confidence()))
87 | .collect(Collectors.joining(", ")));
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/main/java/com/udacity/catpoint/service/FakeImageService.java:
--------------------------------------------------------------------------------
1 | package com.udacity.catpoint.service;
2 |
3 | import java.awt.image.BufferedImage;
4 | import java.util.Random;
5 |
6 | /**
7 | * Service that tries to guess if an image displays a cat.
8 | */
9 | public class FakeImageService {
10 | private final Random r = new Random();
11 |
12 | public boolean imageContainsCat(BufferedImage image, float confidenceThreshhold) {
13 | return r.nextBoolean();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/main/java/com/udacity/catpoint/service/SecurityService.java:
--------------------------------------------------------------------------------
1 | package com.udacity.catpoint.service;
2 |
3 | import com.udacity.catpoint.application.StatusListener;
4 | import com.udacity.catpoint.data.AlarmStatus;
5 | import com.udacity.catpoint.data.ArmingStatus;
6 | import com.udacity.catpoint.data.SecurityRepository;
7 | import com.udacity.catpoint.data.Sensor;
8 |
9 | import java.awt.image.BufferedImage;
10 | import java.util.HashSet;
11 | import java.util.Set;
12 |
13 | /**
14 | * Service that receives information about changes to the security system. Responsible for
15 | * forwarding updates to the repository and making any decisions about changing the system state.
16 | *
17 | * This is the class that should contain most of the business logic for our system, and it is the
18 | * class you will be writing unit tests for.
19 | */
20 | public class SecurityService {
21 |
22 | private FakeImageService imageService;
23 | private SecurityRepository securityRepository;
24 | private Set statusListeners = new HashSet<>();
25 |
26 | public SecurityService(SecurityRepository securityRepository, FakeImageService imageService) {
27 | this.securityRepository = securityRepository;
28 | this.imageService = imageService;
29 | }
30 |
31 | /**
32 | * Sets the current arming status for the system. Changing the arming status
33 | * may update both the alarm status.
34 | * @param armingStatus
35 | */
36 | public void setArmingStatus(ArmingStatus armingStatus) {
37 | if(armingStatus == ArmingStatus.DISARMED) {
38 | setAlarmStatus(AlarmStatus.NO_ALARM);
39 | }
40 | securityRepository.setArmingStatus(armingStatus);
41 | }
42 |
43 | /**
44 | * Internal method that handles alarm status changes based on whether
45 | * the camera currently shows a cat.
46 | * @param cat True if a cat is detected, otherwise false.
47 | */
48 | private void catDetected(Boolean cat) {
49 | if(cat && getArmingStatus() == ArmingStatus.ARMED_HOME) {
50 | setAlarmStatus(AlarmStatus.ALARM);
51 | } else {
52 | setAlarmStatus(AlarmStatus.NO_ALARM);
53 | }
54 |
55 | statusListeners.forEach(sl -> sl.catDetected(cat));
56 | }
57 |
58 | /**
59 | * Register the StatusListener for alarm system updates from within the SecurityService.
60 | * @param statusListener
61 | */
62 | public void addStatusListener(StatusListener statusListener) {
63 | statusListeners.add(statusListener);
64 | }
65 |
66 | public void removeStatusListener(StatusListener statusListener) {
67 | statusListeners.remove(statusListener);
68 | }
69 |
70 | /**
71 | * Change the alarm status of the system and notify all listeners.
72 | * @param status
73 | */
74 | public void setAlarmStatus(AlarmStatus status) {
75 | securityRepository.setAlarmStatus(status);
76 | statusListeners.forEach(sl -> sl.notify(status));
77 | }
78 |
79 | /**
80 | * Internal method for updating the alarm status when a sensor has been activated.
81 | */
82 | private void handleSensorActivated() {
83 | if(securityRepository.getArmingStatus() == ArmingStatus.DISARMED) {
84 | return; //no problem if the system is disarmed
85 | }
86 | switch(securityRepository.getAlarmStatus()) {
87 | case NO_ALARM -> setAlarmStatus(AlarmStatus.PENDING_ALARM);
88 | case PENDING_ALARM -> setAlarmStatus(AlarmStatus.ALARM);
89 | }
90 | }
91 |
92 | /**
93 | * Internal method for updating the alarm status when a sensor has been deactivated
94 | */
95 | private void handleSensorDeactivated() {
96 | switch(securityRepository.getAlarmStatus()) {
97 | case PENDING_ALARM -> setAlarmStatus(AlarmStatus.NO_ALARM);
98 | case ALARM -> setAlarmStatus(AlarmStatus.PENDING_ALARM);
99 | }
100 | }
101 |
102 | /**
103 | * Change the activation status for the specified sensor and update alarm status if necessary.
104 | * @param sensor
105 | * @param active
106 | */
107 | public void changeSensorActivationStatus(Sensor sensor, Boolean active) {
108 | if(!sensor.getActive() && active) {
109 | handleSensorActivated();
110 | } else if (sensor.getActive() && !active) {
111 | handleSensorDeactivated();
112 | }
113 | sensor.setActive(active);
114 | securityRepository.updateSensor(sensor);
115 | }
116 |
117 | /**
118 | * Send an image to the SecurityService for processing. The securityService will use its provided
119 | * ImageService to analyze the image for cats and update the alarm status accordingly.
120 | * @param currentCameraImage
121 | */
122 | public void processImage(BufferedImage currentCameraImage) {
123 | catDetected(imageService.imageContainsCat(currentCameraImage, 50.0f));
124 | }
125 |
126 | public AlarmStatus getAlarmStatus() {
127 | return securityRepository.getAlarmStatus();
128 | }
129 |
130 | public Set getSensors() {
131 | return securityRepository.getSensors();
132 | }
133 |
134 | public void addSensor(Sensor sensor) {
135 | securityRepository.addSensor(sensor);
136 | }
137 |
138 | public void removeSensor(Sensor sensor) {
139 | securityRepository.removeSensor(sensor);
140 | }
141 |
142 | public ArmingStatus getArmingStatus() {
143 | return securityRepository.getArmingStatus();
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/main/java/com/udacity/catpoint/service/StyleService.java:
--------------------------------------------------------------------------------
1 | package com.udacity.catpoint.service;
2 |
3 | import java.awt.*;
4 |
5 | /**
6 | * Simple "service" for providing style information.
7 | */
8 | public class StyleService {
9 |
10 | public static Font HEADING_FONT = new Font("Sans Serif", Font.BOLD, 24);
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/main/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, A1
2 |
3 | # A1 is set to be a ConsoleAppender.
4 | log4j.appender.A1=org.apache.log4j.ConsoleAppender
5 |
6 | # A1 uses PatternLayout.
7 | log4j.appender.A1.layout=org.apache.log4j.PatternLayout
8 | log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
--------------------------------------------------------------------------------
/starter/catpoint-parent/src/test/java/com/udacity/catpoint/AppTest.java:
--------------------------------------------------------------------------------
1 | package com.udacity.catpoint;
2 |
3 |
4 | import org.junit.jupiter.api.Test;
5 |
6 | import static org.junit.jupiter.api.Assertions.assertTrue;
7 |
8 | /**
9 | * Unit test for simple App.
10 | */
11 | public class AppTest
12 | {
13 | /**
14 | * Rigorous Test :-)
15 | */
16 | @Test
17 | public void shouldAnswerWithTrue()
18 | {
19 | assertTrue( true );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/starter/code_coverage_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/udacity/cd0384-java-application-deployment-projectstarter/2e46f912af681aac29254b594706e42c15aabfdb/starter/code_coverage_1.png
--------------------------------------------------------------------------------
/starter/code_coverage_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/udacity/cd0384-java-application-deployment-projectstarter/2e46f912af681aac29254b594706e42c15aabfdb/starter/code_coverage_2.png
--------------------------------------------------------------------------------
/starter/gui_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/udacity/cd0384-java-application-deployment-projectstarter/2e46f912af681aac29254b594706e42c15aabfdb/starter/gui_1.png
--------------------------------------------------------------------------------
/starter/gui_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/udacity/cd0384-java-application-deployment-projectstarter/2e46f912af681aac29254b594706e42c15aabfdb/starter/gui_2.png
--------------------------------------------------------------------------------
/starter/jar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/udacity/cd0384-java-application-deployment-projectstarter/2e46f912af681aac29254b594706e42c15aabfdb/starter/jar.png
--------------------------------------------------------------------------------
/starter/pom_xml.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/udacity/cd0384-java-application-deployment-projectstarter/2e46f912af681aac29254b594706e42c15aabfdb/starter/pom_xml.png
--------------------------------------------------------------------------------