summaryrefslogtreecommitdiff
path: root/20-implementierungsheft/assets/diagrams/classdiagram.puml
diff options
context:
space:
mode:
Diffstat (limited to '20-implementierungsheft/assets/diagrams/classdiagram.puml')
-rw-r--r--20-implementierungsheft/assets/diagrams/classdiagram.puml463
1 files changed, 463 insertions, 0 deletions
diff --git a/20-implementierungsheft/assets/diagrams/classdiagram.puml b/20-implementierungsheft/assets/diagrams/classdiagram.puml
new file mode 100644
index 0000000..4b1970a
--- /dev/null
+++ b/20-implementierungsheft/assets/diagrams/classdiagram.puml
@@ -0,0 +1,463 @@
+@startuml
+' skinparam linetype ortho
+' skinparam groupInheritance 2
+allowmixing
+
+package subscriptionsAPI <<Frame>> {
+ package subscriptionDataAccessLayer <<Frame>> {
+ class SubscriptionDataAccessService <<@Repository>> {
+ <<create>> SubscriptionDataAccessService(JpaTemplate jpaTemplate)
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+
+ interface SubscriptionDao {
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+ }
+
+ package subscriptionService <<Frame>> {
+ class SubscriptionService <<@Service>> {
+ <<create>> SubscriptionService(SubscriptionDao subscriptionDao)
+ int uploadSubscriptions(String username, List<SubscriptionAction> subscriptions)
+ List<String> getSubscriptions(String username)
+ List<String> getSubscriptionsSince(String username, LocalDateTime time)
+ int addSubscriptions(String username, List<SubscriptionAction> addedSubscriptions)
+ int removeSubscriptions(String username, List<SubscriptionAction> removedSubscriptions)
+ List<SubscriptionTitles> getTitles(String username)
+ }
+ }
+
+ package subscriptionController <<Frame>> {
+ class SubscriptionController <<@Controller>>{
+ ' @Autowired
+ <<create>> SubscriptionController(SubscriptionService subscriptionService)
+ ' @GetMapping
+ ResponseEntity<List<String>> getSubscriptions(String username, String deviceID, String functionJSONP)
+ ' @PutMapping
+ ResponseEntity<String> uploadSubscriptions(String username, String deviceID, List<String> subscriptions)
+ ' @PostMapping
+ ResponseEntity<SubscriptionDelta> applySubscriptionDelta(String username, String deviceID, SubscriptionDelta delta)
+ ' @GetMapping
+ ResponseEntity<SubscriptionDelta> getSubscriptionDelta(String username, String deviceID, long since)
+ ResponseEntity<List<SubscriptionTitles>> getTitles(String username, String deviceID)
+ }
+
+ class SubscriptionTitles {
+ <<create>> SubscriptionTitles(Subscription subscription, List<EpisodeActionPost> episodeTitles)
+ Subscription getSubscription()
+ List<EpisodeActionPost> getEpisodesTitles()
+ }
+
+ class SubscriptionDelta {
+ <<create>> SubscriptionDelta(List<String> add, List<String> remove)
+ List<String> getRemove()
+ LocalDate getTimestamp()
+ List<List<String>> getUpdate_urls()
+ }
+ }
+
+}
+
+package episodeActionsAPI <<Frame>> {
+ package episodeActionDataAccessLayer <<Frame>> {
+ class EpisodeActionDataAccessService <<@Repository>> {
+ <<create>> EpisodeActionDataAccessService (JpaTemplate jpaTemplate)
+ long addEpisodeActions(String username, List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+
+ interface EpisodeActionDao {
+ long addEpisodeActions(String username, List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+ }
+
+ package episodeActionService <<Frame>> {
+ class EpisodeActionService <<@Service>> {
+ <<create>> EpisodeActionService (EpisodeActionDao episodeActionDao)
+ LocalDateTime addEpisodeActions(String username, List<EpisodeActionPosts> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActions(String username)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcast(String username, String podcastURL)
+ List<EpisodeActionPost> getEpisodeActionsSince(String username, LocalDateTime since)
+ List<EpisodeActionPost> getEpisodeActionsOfPodcastSince(String username, String podcastURL, LocalDateTime since)
+ }
+ }
+
+ package episodeActionController <<Frame>> {
+ class EpisodeActionController <<@Controller>>{
+ <<create>> EpisodeActionController (EpisodeActionService episodeActionService)
+ ResponseEntity<EpisodeActionPostResponse> addEpisodeActions(String username, EpisodeActionPostRequest episodeActionPostRequest)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActions(String username, String deviceID, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsOfPodcast(String username, String podcastURL, String deviceID, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsSince(String username, String deviceID, long since, boolean aggregated)
+ ResponseEntity<EpisodeActionGetResponse> getEpisodeActionsOfPodcastSince(String username, String podcastURL, String deviceID, long since, boolean aggregated)
+ }
+
+ class EpisodeActionPostResponse {
+ <<create>> EpisodeActionPostResponse(List<Pair<String, String>> updateURLs)
+ long getTimestamp()
+ List<Pair<String, String>> getUpdatedURLs()
+ }
+
+ class EpisodeActionPost {
+ <<create>> EpisodeActionPost(String podcastURL, String episodeURL, Action action, LocalDateTime timestamp, int started, int position)
+ String getPodcastURL()
+ String getEpisodeURL()
+ int getGUID()
+ Action getAction()
+ LocalDateTime getTimestamp()
+ int getStarted()
+ int getPosition()
+ EpisodeAction getEpisodeAction()
+ }
+
+ class EpisodeActionPostRequest {
+ <<create>> EpisodeActionPostRequest(List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActionPosts()
+ }
+
+ class EpisodeActionGetResponse {
+ <<create>> EpisodeActionGetResponse(List<EpisodeActionPost> episodeActionPosts)
+ List<EpisodeActionPost> getEpisodeActionPosts()
+ long getTimestamp()
+ }
+ }
+}
+
+package authenticationAPI <<Frame>> {
+ package authenticationDataAccessLayer <<Frame>> {
+ ' interface AuthenticationDao {
+ ' String login(String username)
+ ' int logout(String username)
+ ' }
+
+ ' class AuthenticationDataAccessService <<@Respository>> {
+ ' <<create>> AuthenticationDataAccessService(JpaTemplate jpaTemplate)
+ ' String login(String username)
+ ' int logout(String username)
+ ' }
+
+ interface UserDetailsManager {
+ void createUser(UserDetails userDetails)
+ void changePassword(String oldPassword, String newPassword)
+ void deleteUser(String username)
+ void updateUser(UserDetails user)
+ boolean userExists(String username)
+ }
+ note left
+ Aus org.springframework.security.provisioning
+ - liefert Methoden zum Erstellen neuer User
+ und zum Aktualisieren bestehender.
+ end note
+
+ class JdbcUserDetailsManager <<@Repository>> {
+ <<create>> JdbcUserDetailsManager(DataSource dataSource)
+ void createUser(UserDetails user)
+ void changePassword(String oldPassword, String newPassword)
+ void deleteUser(String username)
+ void updateUser(UserDetails user)
+ boolean userExists(String username)
+ }
+ note right
+ User Management Service aus dem Paket
+ org.springframework.security.provisioning
+ der CRUD Operationen für User bereitstellt.
+ Hier sind nur die relevanten Methoden modelliert.
+ end note
+ }
+
+ package authenticationService <<Frame>> {
+ class AuthenticationService <<@Service>> {
+ --
+ <<create>> AuthenticationService(UserDetailsManager userDetailsManager)
+ List<String> verifyLogin(String username)
+ int logout(String username)
+ int forgotPassword(ForgotPasswordRequest forgotPasswordRequest)
+ .. via JdbcUserDetailsManager ..
+ int resetPassword(String username, RequestWithPassword requestWithPassword)
+ int registerUser(UserDetails user)
+ int changePassword(String username, ChangePasswordRequest changePasswordRequest)
+ int deleteUser(String username, RequestWithPassword requestWithPassword)
+ }
+
+ class JavaMailSenderImpl {}
+ note left
+ Aus org.springframework.mail.javamail.
+ Implementierung des JavaMailSender Interfaces,
+ welches das MailSender Interface durch Unterstützung
+ von MIME Nachrichten erweitert.
+ Das MailSender Interface definiert dabei eine
+ Strategie zum Versenden einfacher Mails.
+ Unterstützt sowohl JavaMail MimeMessages und
+ Spring SimpleMailMessages.
+ end note
+ }
+
+ package authenticationController <<Frame>> {
+ class AuthenticationController <<@Controller>> {
+ <<create>> AuthenticationController(AuthenticationService authenticationService)
+ ResponseEntity<List<String>> verifyLogin(String username)
+ ResponseEntity<Integer> logout(String username)
+ ResponseEntity<Integer> forgotPassword(ForgotPasswordRequest forgotPasswordRequest)
+ ResponseEntity<Integer> resetPassword(String username, RequestWithPassword requestWithPassword)
+ ResponseEntity<Integer> registerUser(UserDetails user)
+ ResponseEntity<Integer> changePassword(String username, ChangePasswordRequest changePasswordRequest)
+ ResponseEntity<Integer> deleteUser(String username, RequestWithPassword requestWithPassword)
+ }
+
+ class ChangePasswordRequest {
+ <<create>> ChangePasswordRequest(String oldPassword, String newPassword)
+ String getOldPassword()
+ String getNewPassword()
+ }
+
+ class ForgotPasswordRequest {
+ <<create>> ForgotPasswordRequest(String email)
+ String getEmail()
+ }
+
+ class RequestWithPassword {
+ <<create>> ResetPasswordRequest(String password)
+ String getPassword()
+ }
+ }
+}
+
+package model <<Frame>> {
+ class Subscription {
+ <<create>> Subscription(String url, String title)
+ int getID()
+ String getURL()
+ long getLastActionTimestamp()
+ String getTitle()
+ }
+
+ class SubscriptionAction {
+ <<create>> SubscriptionAction(int userID, int subscriptionID)
+ int getID()
+ int getUserID()
+ int getSubscriptionID()
+ long getTimestamp()
+ boolean getAdded()
+ }
+
+ class Episode {
+ <<create>> Episode(int subscriptionID, int id, String url, String title, String thumbnailURL, int total)
+ int getSubscriptionID()
+ int getID()
+ int getGUID()
+ String getURL()
+ String getTitle()
+ int getTotal()
+ }
+
+ enum Action {
+ Download
+ Play
+ Delete
+ New
+ Flattr
+ String getJsonProperty()
+ }
+
+ class EpisodeAction {
+ <<create>> EpisodeAction(Action action, LocalDateTime timestamp, int started, int position)
+ int getEpisodeID()
+ Action getAction()
+ long getTimestamp()
+ int getStarted()
+ int getPosition()
+ void setEpisodeID()
+ EpisodeActionPost getEpisodeActionPost(String podcastURL, String episodeURL)
+ }
+
+ interface UserDetails {
+ String getUsername()
+ String getPassword()
+ Collection<Authority> getAuthorities()
+ boolean isAccountExpired()
+ boolean isAccountLocked()
+ boolean isCredentialsNonExpired()
+ boolean isEnabled()
+ }
+ note left
+ Aus org.springframework.security.core.userdetails.
+ Wird für die Schnittstelle UserDetailsManager benötigt.
+ Stellt wichtige Informationen eines Users bereit.
+ Diese werden nur indirekt von Spring Security
+ benutzt, indem sie vorher in Authentication Objekten
+ gekapselt werden.
+ end note
+
+ class User {
+ --
+ <<create>> User(String username, String password)
+ int getID()
+ String getSessionToken()
+ boolean getEmailIsValidated()
+ .. interface methods ..
+ String getUsername()
+ String getPassword()
+ Collection<Authority> getAuthorities()
+ boolean isAccountExpired()
+ boolean isAccountLocked()
+ boolean isCredentialsNonExpired()
+ boolean isEnabled()
+ }
+
+ interface GrantedAuthority {
+ String getAuthority()
+ }
+ note right
+ Aus org.springframework.security.core.
+ Wird für die Schnittstelle UserDetails benötigt.
+ Repräsentiert eine Autorisierung, die einem
+ Authentication Objekt gewährt wird.
+ end note
+
+ class Authority {
+ <<create>> Authority()
+ String getAuthority()
+ }
+}
+
+package util <<Frame>> {
+ class RSSParser {
+ <<create>> RSSParser(String subscriptionURL)
+ String getSubscriptionTitle()
+ List<Episode> getEpisodes()
+ Episode getEpisodeForURL(String episodeURL)
+ }
+ note bottom
+ Verwendet intern Spring um
+ HTTP-Anfragen zu erstellen.
+ end note
+
+ class CleanCronJob {
+ <<create>> CleanCronJob(JdbcUserDetailsManager jdbcUserDetailsManager)
+ void cleanInvalidUsers()
+ }
+ note bottom
+ Hintergrundservice, der in periodischen Abständen
+ Nutzer, die ihre E-Mail-Adresse nicht nach 24 Stunden
+ bestätigt haben, wieder aus der Datenbank löscht.
+ (Auf die Assoziation zu JdbcUserDetailsManager wird
+ im Sinne der Übersichtlichkeit verzichtet.)
+ end note
+
+ class ResponseEntity<T> {
+ <<create>> ResponseEntity(T body, HttpStatusCode status)
+ T getBody()
+ HttpStatusCode getStatusCode()
+ }
+ note bottom
+ Aus org.springframework.http.
+ Erweitert die Klasse HttpEntity, welche
+ ein HTTP Anfrage- oder Antwort-Objekt
+ repräsentiert, durch einen HttpStatusCode.
+ Wird von den Controller-Methoden als
+ Rückgabewert verwendet.
+ end note
+}
+
+class SecurityConfigurationBasicAuth {
+ <<create>> SecurityConfigurationBasicAuth()
+ PasswordEncoder encoder()
+ UserDetailsManager userDetailsService()
+ SecuryFilterChain fiterChain(HTTPSecurity http) throws Excpetion
+}
+note top
+ Erstellt einen Servlet Filter (springSecurityFilterChain)
+ der für die gesamte Sicherheit zuständig ist (Schutz der URLs,
+ Validierung von Anmeldedaten, Weiterleitung zur Anmeldung, etc.).
+end note
+
+class PSEApplication {
+ <<create>> PSEApplication()
+ void main(String[] args)
+}
+
+database Datenbank
+Datenbank <-[hidden]d- subscriptionsAPI
+Datenbank <-[hidden]d- episodeActionsAPI
+Datenbank <-[hidden]d- authenticationAPI
+() SQL as SQLSub
+() SQL as SQLAuth
+() SQL as SQLEpisode
+
+Datenbank -- SQLSub
+Datenbank -- SQLAuth
+Datenbank -- SQLEpisode
+
+SubscriptionController ..o PSEApplication
+AuthenticationController ..o PSEApplication
+EpisodeActionController ..o PSEApplication
+SecurityConfigurationBasicAuth ..o PSEApplication
+
+PSEApplication --() HTTP
+
+SQLSub )-- SubscriptionDataAccessService: JPA
+' SQLAuth )-- AuthenticationDataAccessService: JPA
+SQLAuth )-- JdbcUserDetailsManager: JDBC
+SQLEpisode )-- EpisodeActionDataAccessService: JPA
+
+Subscription <. SubscriptionAction: ID
+' Subscription <.. SubscriptionDataAccessService: DB
+' SubscriptionAction <.. SubscriptionDataAccessService: DB
+SubscriptionService --o SubscriptionController
+SubscriptionDao <.. SubscriptionService: <<use>>
+Subscription --o SubscriptionTitles
+EpisodeActionPost -o SubscriptionTitles
+SubscriptionDao <|. SubscriptionDataAccessService: <<realize>>
+
+' User <.. AuthenticationDataAccessService: DB
+' User <.. JdbcUserDetailsManager: DB
+UserDetailsManager <.. AuthenticationService: <<use>>
+' AuthenticationDao <.. AuthenticationService: <<use>>
+AuthenticationService --o AuthenticationController
+' AuthenticationDao <|. AuthenticationDataAccessService: <<realize>>
+UserDetailsManager <|. JdbcUserDetailsManager: <<realize>>
+UserDetailsManager <.. SecurityConfigurationBasicAuth: <<use>>
+UserDetails <|.. User: <<realize>>
+User -> Authority
+GrantedAuthority <|.. Authority: <<realize>>
+JavaMailSenderImpl <. AuthenticationService: <<use>>
+
+Action <-- EpisodeAction
+EpisodeActionPost -o EpisodeActionGetResponse
+EpisodeActionPost -o EpisodeActionPostRequest
+EpisodeAction .> Episode: ID
+' EpisodeAction <.. EpisodeActionDataAccessService: DB
+' Episode <.. EpisodeActionDataAccessService: DB
+EpisodeActionDao <.. EpisodeActionService: <<use>>
+EpisodeActionService --o EpisodeActionController
+EpisodeActionDao <|. EpisodeActionDataAccessService: <<realize>>
+
+RSSParser <. SubscriptionDataAccessService: <<use>>
+RSSParser <. EpisodeActionDataAccessService: <<use>>
+' JdbcUserDetailsManager <-- CleanCronJob
+
+model .o Datenbank: ORM (User, SubscriptionAction, Subscription, EpisodeAction, Episode)
+' Datenbank o.. Subscription: ORM
+' Datenbank o.. SubscriptionAction: ORM
+' Datenbank o.. Episode: ORM
+' Datenbank o.. EpisodeAction: ORM
+' Datenbank o.. User: ORM
+
+@enduml