diff --git a/parts/01_patterns.tex b/parts/01_patterns.tex new file mode 100644 index 0000000..50dfbc6 --- /dev/null +++ b/parts/01_patterns.tex @@ -0,0 +1,622 @@ + +\part{Pattern im Projekt} +\section{Layers Pattern} +\subsection{Erkläre die Funktionsweise + Skizze} +\begin{itemize} + \item Client schickt eine Anfrage an Layer N + \item Layer N reicht da er nicht vollständig alleine beantworten kann, Anfragen an darunterliegenden Layer weiter + \item Eine Anfrage kann bei Bedarf auch in mehrere Anfragen an darunterliegende Layer geteilt werden + \item dies wird immer weiter fortgesetzt bis Layer 1 erreicht ist + \item dabei gehen Abhängigkeiten nur von oben nach unten +\end{itemize} +\begin{figure}[!htp] + \centering + \includegraphics[width=0.8\textwidth]{pics/esa_layers.jpg} +\end{figure} +\subsubsection{3 Schichten Architektur:} +\begin{itemize} + \item Data Source Layer (data): Zugriff auf Daten, kümmert sich um Kommunikation mit anderen Systemen (z.B.: Datenbank) + \begin{itemize} + \item enthält Entities –> Java Repräsentation vom DB Entity + \begin{itemize} + \item im Projekt wurde eine AbstractEntity erstellt, welche die id managed + \end{itemize} + \item beinhaltet DAO und DAOImpl >> DocumentDAO, DocumentlibraryDAO + \begin{itemize} + \item damit man auf die Entities zugreifen kann. + \item um die DB zu abstrahieren. + \item enthält Methoden mit denen auf die DB zugegriffen wird + \item eine DAOException kontrolliert den Input + \begin{itemize} + \item der EntityManager Aufruf in DAOImpl befindet sich innerhalb eines Try Blocks + \item im catch wird der Cause in die DaoException gewrapped + \end{itemize} + % TODO: ?? + \end{itemize} + \end{itemize} + \item Domain Layer(service): enthält Business Logik (Berechnungen, Datenvalidierung, ...) + \begin{itemize} + \item beinhaltet + \begin{itemize} + \item \textbf{Service Layer Pattern} (aka Session Fassade - siehe~\ref{sec:slp}) + \item DTO >> DocumentDTO + \item Mapper >> DocumentMapper + \begin{minted}[breaklines=true]{java} +public static Document toEntity(DocumentDTO documentDTO, Document document){}; +public static DocumentDTO toDTO(Document document){}; + \end{minted} + \end{itemize} + \end{itemize} + \item Presentation Layer(web): serverseitig, kümmert sich um Benutzerinteraktion + \begin{itemize} + \item Controller (ViewHelper) >> DocumentController, DocumentListController + \item View (WebApp) + \end{itemize} +\end{itemize} +\begin{figure}[tph!] + \centering + \includegraphics[width=0.4\textwidth]{pics/layer-pattern} +\end{figure} +\section{Data Access Object (DAO) Pattern} +Befindet sich im Projekt in data und damit innerhalb des Data Layer. +\subsection{Erkläre die Funktion + Skizze} +\begin{itemize} + \item Client erstellt ein DAO Object und kann nach Entitäten suchen, einfügen, löschen, etc. + \item das DAO selbst soll keine spezifischen Elemente enthalten (Entity Manager, SQL Exception -> stattdessen DAOException) + \item dadurch entsteht eine Kapselung bei der die DAOImpl ohne den Client zu verändern ausgetauscht werden kann +\end{itemize} +\begin{figure}[!htp] + \centering + \includegraphics[width=0.8\textwidth]{pics/dao_pat1.jpg} +\end{figure} +\begin{minted}[breaklines=true]{java} +@ApplicationScoped +public class DocumentDAOImpl implements DocumentDAO, Serializable { + private static final long serialVersionUID = 1L; + private static final Logger logger = LoggerFactory.getLogger(DocumentDAOImpl.class); + @PersistenceContext + private EntityManager entityMangaer; + + @Override + public List findByCommunity(Community community) {...} + + @Override + public List findByUser(User user) {...} + + @Override + public void insert(Document document) {...} + + @Override + public void delete(Document document) {...} + + @Override + public Document findById(Long id) {...} +} +\end{minted} +\subsection{Nenne die Konsequenzen der Anwendung} +\begin{itemize} + \item Zugriff auf persistenten Speicher wird abstrahiert + \item Details des Speichers werden versteckt + \item ermöglicht einheitlichen Zugriff auf Daten + \item entkoppelt Implementierung von Persistierung (Datenbank,...) + \item ermöglicht Objektorientierte Ansicht des Speichers +\end{itemize} +\section{Service Layer Pattern (auch Session Fassade - in unserem Projekt im Domain Layer}\label{sec:slp} +\subsection{Erkläre die Funktion + Skizze}\label{subsubsec:service-layer-pattern} +\begin{itemize} + \item Der Service Layer (Ordner "`service"' im Projekt) delegiert auf die Business Logik (Zeile 68 community.setDocumentlibrary) und zum DAO (z.B. Zeile 66) + \item Bei wenig Logik wird zumindest Transaktions (Zeile 40), Error (ab Zeile 42) und Validierungshandling (ab Zeile 23) im Service erledigt +\end{itemize} +\begin{figure}[!htp] + \centering + \includegraphics[width=0.9\textwidth]{pics/sl_pat1.jpg} + \includegraphics[width=0.6\textwidth]{pics/domain-layer.png} +\end{figure} +\begin{minted}[xleftmargin=\parindent,linenos,breaklines=true]{java} + @Local(DocumentService.class) + @Remote(DocumentServiceRemote.class) + @Stateless + public class DocumentServiceImpl implements DocumentService, DocumentServiceRemote, Serializable { + private static final long serialVersionUID = -1L; + private static final Logger logger = LoggerFactory.getLogger(DocumentServiceImpl.class); + + @Inject + private DocumentDAO documentDAO; + @Inject + private DocumentlibraryDAO documentlibraryDAO; + @Inject + private CommunityDAO communityDAO; + @Inject + private UserDAO userDAO; + @Inject + private MessageDAO messageDAO; + @Override + public DocumentDTO addDocument(Long communityID, String userID, byte[] data, String filename) { + Document addedDocument; + User user; + + // Validierungshandling gefolgt von Error Handling + try { + if (communityID <= 0) throw new IllegalArgumentException("community must not be empty"); + if (userID == null) throw new IllegalArgumentException("user must not be empty"); + if (data == null) throw new IllegalArgumentException("uploaded file must not be empty"); + if (filename == null) throw new IllegalArgumentException("filename must not be empty"); + + Documentlibrary documentlibrary = documentlibraryDAO.findByCommunityId(communityID); + + //create a document library, if there isn't already one in the database + if (documentlibrary == null) { + documentlibrary = addDocumentlibrary(communityID); + } + + user = userDAO.getByUserId(userID); + + addedDocument = new Document(documentlibrary, user, filename, data); + documentDAO.insert(addedDocument); // Transaktionshandling + logger.info(String.format("Document %s saved in database", filename)); + // Error Handling + } catch (IllegalArgumentException iaex) { + String errorMsg = "Uploading file failed (illegal argument)"; + logger.error(errorMsg, iaex); + throw new ServiceException(errorMsg); + + } catch (Exception ex) { + String errorMsg = String.format("Uploading file %s failed.", filename); + logger.error(errorMsg, ex); + throw new ServiceException(errorMsg); + } + + String msgText = "Uploaded Document " + filename + " by user " + user.getUserId(); + addMessageToStream(communityID, user, msgText, addedDocument); + return DocumentMapper.toDTO(addedDocument); + } + + + private void addMessageToStream(Long communityID, User user, String text, Document document) {...} + + private Documentlibrary addDocumentlibrary(Long communityID) { + logger.info("Create missing documentlibrary"); + Community community; + Documentlibrary documentlibrary = new Documentlibrary(); + documentlibraryDAO.insert(documentlibrary); // Delegation zum DAO + community = communityDAO.findById(communityID); // Delegation zum DAO + community.setDocumentlibrary(documentlibrary); // Delegation zur Business Logik (Entity) + communityDAO.update(community); // Delegation zum DAO + return documentlibrary; + } + + @Override + public List getDocumentsFromCommunity(Long communityID) {...} + + @Override + public List getDocumentsFromUser(String userID) {...} + + @Override + public void removeDocument(Long documentID) {...} + + @Override + public DocumentDTO getDocumentById(Long documentID) {...} + } +\end{minted} + +\subsection{Nenne die Konsequenzen der Anwendung} +\begin{itemize} + \item Reduzierung der Abhängigkeiten zwischen Presentation und Domain Layer + \item Zentralisiertes Sicherheits und Transaktionshandling + \item verbirgt vor Client Komplexität der Business Logik + \item stellt Client ein grobkörniges Interface zur Verfügung + \item gut für Remote Aufrufe geeignet (weniger Aufrufe) + +\end{itemize} + +\section{Model-View-Controller (MVC) Pattern} +\subsection{Erkläre die Funktion + Skizze} +MVC unterteilt eine interaktive Applikation in drei Teile: Model, View und Controller. +\begin{itemize} + \item Controller und View befinden sich im Presentation Layer und haben gegenseitig Abhängigkeiten + \item Das Model darf keine Abhängigkeiten haben (Controller und View hängen vom Model ab) +\end{itemize} +\begin{figure}[!htp] + \centering + \includegraphics[width=0.8\textwidth]{pics/mvc_pat.jpg} +\end{figure} +\subsubsection{Model} +\begin{itemize} + \item Es befinden sich Teile im Domain und Data Source Layer. + \item Das Model enthält die Kernfunktionalität und Daten. (z.B.: Datenbankzugriff) + \item Im Projekt wird dies durch die Ordner \textit{service} und \textit{data} repräsentiert +\end{itemize} +\subsubsection{View} +\begin{itemize} + \item Im Projekt im Ordner \textit{webapp} zu finden. + \item Enthält im Projekt xhtml Dateien zur Darstellung und User Interaktion +\end{itemize} +\subsubsection{Controller} +\begin{itemize} + \item Im Projekt sind Controllerklassen im Ordner \textit{web} zu finden. + \item Sie enthalten die Logik und behandeln Benutzereingaben +\end{itemize} +\section{Front Controller} +\subsection{Erkläre die Funktion + Skizze} +\begin{itemize} + \item Client schickt Request an Front Controller + \item FC erfasst nur Infos die er für die weiter Delegation braucht + \item FC gibt Request an entsprechenden ConcreteCommand oder View weiter + \item es gibt zwei Implementierungsvarianten des Controller + \begin{multicols}{2} + \begin{itemize} + \item Servlet + \item ConcreteCommand + \end{itemize} + \end{multicols} + +\end{itemize} +\subsection{Servlet} +\begin{itemize} + \item Im Projekt wurde der Front Controller in Form eines Servlet realisiert, + \item die Einbindung erfolgt in der Konfigurationsdatei \textit{src/main/webapp/WEB-INF/web.xml}, + \item Servlet ist eine Java-API, welche auf einem Server betrieben wird, + \item die Verarbeitung von Requests und Responses wird ermöglicht, + \item JSF und JSP können darauf aufsetzen, in unserem Projekt wurde JSF verwendet +\end{itemize} +\begin{minted}[linenos,breaklines=true]{xml} + + +... + +Faces Servlet +javax.faces.webapp.FacesServlet +1 + + +Faces Servlet +*.xhtml + +\end{minted} +\subsubsection{Java Server Faces (JSF)} +\begin{itemize} + \item JSF basiert auf dem MVC-Pattern + \item JSF-View-Code ist im Projekt im Ordner \textit{src/main/webapp/*} zu finden + \item JSF-Logik befindet sich in den Java-Beans (im Projekt \textit{/src/main/java/at/fhj/swd/psoe/web/*}) + \item in unserem Projekt gibt es zu jeder xhtml-View eine eigene Controller-Klasse, welche dem ViewHelper-Pattern entspricht + \item in unserem Projekt kommt PrimeFaces zum Einsatz (eine konkrete Implementierungsart von JSF => Einbindung in pom.xml) + %TODO Toni fragen MVC-Aufteilung JSF +\end{itemize} +\begin{figure}[h!] + \centering + \includegraphics[width=0.5\textwidth]{pics/fc_pat.jpg} +\end{figure} +\begin{minted}[linenos,breaklines=true]{xml} + + + + + + +

#{msg.document_manage_title}

+ + + + + + + +#{docs.createdTimestamp} +#{docs.user.userId} +#{docs.filename} + + + + + + + + + + + + + + + + + + +
+
+\end{minted} + +\subsection{Nenne die Konsequenzen der Anwendung} +\begin{itemize} + \item es muss nur EIN (Front) Controller konfiguriert werden + \item da bei jedem Request ein neues Command Objekt erzeugt wird ist Thread-Safety nicht notwendig + \item da nur EIN Controller sind auch Erweiterungen durch z.B.: Decorator einfach (auch zur Laufzeit) +\end{itemize} +\section{View Helper (\textit{/src/main/java/at/fhj/swd/psoe/web/*})} +\subsection{Erkläre die Funktion + Skizze} +\begin{figure}[h!] + \centering + \includegraphics[width=0.8\textwidth]{pics/view-helper_pat1.jpg} +\end{figure} +\begin{itemize} + \item View (xhtml-Dateien im Ordner \textit{/src/main/webapp/*}) delegiert Aufgaben an Helper (z.B. DocumentController im Ordner web) + \item Helper adaptieren View zu Model (Klassen in den Ordnern \textit{src/main/java/at/fhj/swd/psoe/service/*} und \textit{src/main/java/at/fhj/swd/psoe/data/*}) + \item in View befindet sich HTML Code im ViewHelper Java Code zur Aufbereitung der Daten (+ wenig HTML) +\end{itemize} +\subsection{Nenne die Konsequenzen der Anwendung} +\begin{itemize} + \item kapselt Design-Code in View und View-Processing-Code Logik in Helper + \item steigert Wiederverwendbarkeit, Wartbarkeit und Strukturierungsqualität der Anwendung + \item vereinfacht Tests (Helperfunktionen ohne View) + \item bessere Trennung zwischen + \begin{itemize} + \item Presentation und Data Source Layer + \item Entwickler und Designer + \end{itemize} +\end{itemize} + + +\section{Dependency Injection (CDI-Framework -> eingebunden im \textit{./pom.xml})} +\subsection{Erkläre die Funktion + Skizze} +%TODO Zarwos is die Dependency-Injection in unserem Projekt guat und wo is se, verdammte Scheiße noch amol, wo konfigurierst denn den Dreck donn überhaupt??? +\begin{figure}[!htp] + \centering + \includegraphics[width=0.8\textwidth]{pics/dependency_inj_pat.jpg} +\end{figure} +\begin{itemize} + \item Grundidee sind loose gekoppelte Objekte + \item Objekte werden mittels externem Assembler verknüpft + \item Abhängigkeiten bestehen nur auf Interfaces + \item Assembler Objekt (Framework) erzeugt die Interface-Implementierungen (z.B.: durch Factory) + \item Es wird zwischen Constructor Injection und Setter Injection unterschiedlichen + \begin{minted}[linenos,breaklines=true]{java} + // Constructor Injection + puplic class Client { + private Interface iface; + public Client(Interface iface) { + this.iface = iface; + }} + + // Setter Injection + puplic class Client { + private Interface iface; + public setIface(Interface iface) + { + this.iface = iface; + }} + \end{minted} +\end{itemize} +\begin{itemize} + \item Im Spring Context: + \begin{itemize} + \item Dependency Injection mit XML-Datei + \item alle Beans sind dort gelistet und werden verknüpft + \item Context wird geladen damit alles verknüpft ist + \item erspart Factories + \end{itemize} +\end{itemize} +\subsection{Nenne die Konsequenzen der Anwendung} +\begin{itemize} + \item loose gekoppelte Objekte + \item Referenzen nur noch auf Interfaces + \item hohe Flexibilität (Strategy, Proxy,..) + \item bessere Erweiterbarkeit und Testbarkeit + \item bei Spring kann Dependency Injection mittels XML oder Annotation erfolgen + \begin{itemize} + \item Vorteil Annotation: Typ-Sicherheit (Tippfehler passieren schnell im XML) + \item Nachteil Annotation: nicht so flexibel wie XML + \end{itemize} +\end{itemize} +\section{Data Transfer Object (DTO) Pattern} +\subsection{Erkläre die Funktion (Skizze - ein Grund für DTO)} +\begin{figure}[!htp] + \centering + \includegraphics[width=0.9\textwidth]{pics/lok-vs-remote.jpg} +\end{figure} +\begin{itemize} + \item Transportiert Daten zwischen Prozessen um Remote Methodenaufrufe zu minimieren + \item besteht aus Fields, Getter und Setter + \item fasst Daten verschiedener Objekte zusammen die vom Remote Objekt benötigt werden + \item ev. Map, Record Set, ... -> um Anzahl der Aufrufe zu minimieren +\end{itemize} +\begin{minted}[linenos,breaklines=true]{java} +package at.fhj.swd.psoe.service.dto; + +import java.io.Serializable; +import java.util.Date; + +public class DocumentDTO implements Serializable { + private static final long serialVersionUID = 4016557982897997689L; + + private Long id; + private Long documentlibraryID; + private String filename; + private UserDTO user; + private byte[] data; + private Date createdTimestamp; + + public DocumentDTO() {} + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getDocumentlibraryID() { + return documentlibraryID; + } + + public void setDocumentlibraryID(Long documentlibraryID) { + this.documentlibraryID = documentlibraryID; + } + + public String getFilename() { + return filename; + } + + public void setFilename(String filename) { + this.filename = filename; + } + + public UserDTO getUser() { + return user; + } + + public void setUser(UserDTO user) { + this.user = user; + } + + public byte[] getData() { + return data; + } + + public void setData(byte[] data) { + this.data = data; + } + + public Date getCreatedTimestamp() { + return createdTimestamp; + } + + public void setCreatedTimestamp(Date createdTimestamp) { + this.createdTimestamp = createdTimestamp; + } + + @Override + public String toString() { + return "DocumentDTO{" + + "id=" + id + + ", documentlibraryID=" + documentlibraryID + + ", filename='" + filename + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof DocumentDTO)) return false; + + DocumentDTO that = (DocumentDTO) o; + + return id.equals(that.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } +} +\end{minted} +\subsection{Konsequenzen der Anwendung} +\begin{itemize} + \item kapselt und versteckt + \item nimmt Komplexität + \item steigert Effizienz da weniger Aufrufe über Remotegrenze +\end{itemize} +\section{Page-Object-Pattern} +\begin{itemize} + \item stellt Screens der Web-App als Reihe von Objekten dar + \item tatsächlich werden nicht alle Seiten sondern wesentliche Elemente in Objekte gekapselt + \item eine HTML Seite wird so mitunter mit mehreren Objekten dargestellt (z.B. Header und Footer Page Object) + \item Das Page Objekt Design eignet sich besonders gut um Selenium Tests umzusetzen + \item Mittels der Page Objekte kann HTML Code verändert werden (Verkapselung) + \item ermöglichen die Modellierung der Benutzeroberfläche für Tests + \item reduziert Code duplication + \item verbessert Testwartbarkeit und macht Tests robuster +\end{itemize} +\begin{figure}[!htp] + \centering + \includegraphics[width=0.8\textwidth]{pics/page-object.png} +\end{figure} +\subsection{Beispiel aus dem Projekt} +\subsubsection{Integration GUI Test mit Selenium} +\begin{minted}[linenos,breaklines=true]{java} +package at.fhj.swd.psoe.gui.pages; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import java.util.List; + +public class DocumentsListPage extends AbstractPage { + private List list; + + public DocumentsListPage(WebDriver driver) { + super(driver); + } + public List getList() { + list = this.getDriver().findElements(By.xpath("//*[@id=\"documents:comdoctable_data\"]")); + return list; + } + +} +\end{minted} +\subsubsection{Durch Selenium getestetes Page Objekt} +\begin{minted}[linenos,breaklines=true]{java} + package at.fhj.swd.psoe.gui; + + import at.fhj.swd.psoe.JdbcTestHelper; + import at.fhj.swd.psoe.gui.pages.*; + import org.junit.After; + import org.junit.Assert; + import org.junit.Before; + import org.junit.Test; + + import java.io.IOException; + import java.sql.SQLException; + import java.util.stream.Collectors; + + public class ShowDocumentsListITCase extends AbstractChromeTest { + final private String roleName = "ADMIN"; + private LoginPage loginPage; + private WelcomePage welcomePage; + private DocumentsListPage documentsListPage; + private String baseUrl = "http://localhost:8080/chr-krenn-fhj-ws2018-swd16-pse"; + private static final JdbcTestHelper JDBC_HELPER = new JdbcTestHelper(); + + @Before + @Override + public void setUp() { + super.setUp(); + JDBC_HELPER.executeSqlScript( + "src/test/resources/sql/DocumentServiceITCase-addDocument.sql"); + loginPage = new LoginPage(this.driver, baseUrl, 60); + welcomePage = loginPage.login("testdocument@swd.com", "admin"); + CommunitiesPage communitiesPage = welcomePage.openCommunitiesPage(); + CommunityPage communityPage = communitiesPage.openCommunityPage(); + documentsListPage = communityPage.openDocumentListPage(); + } + + @Test + public void testTwoDocumentsListed() { + String content = documentsListPage.getList().stream().map(x -> x.getText()).collect(Collectors.joining()); + Assert.assertTrue(content.contains("documentuser123")); + Assert.assertTrue(content.contains("DocumentITCase1")); + Assert.assertTrue(content.contains("DocumentITCase2")); + } + + @After + @Override + public void tearDown() { + super.tearDown(); + JDBC_HELPER.executeSqlScript( + "src/test/resources/sql/DocumentServiceITCase-deleteDocument.sql"); + } + } +\end{minted} \ No newline at end of file diff --git a/parts/02_exceptions.tex b/parts/02_exceptions.tex new file mode 100644 index 0000000..c18742e --- /dev/null +++ b/parts/02_exceptions.tex @@ -0,0 +1,121 @@ +\part{Exception Handling} +\section{Checked und Runtime Exceptions in Java} +\subsection{Checked Exceptions (z.B. SQL-Exception)} +\begin{itemize} + \item leiten von Exception Klasse ab und müssen behandelt werden (trows - catch) + \item Verwendung für Probleme die durch User behoben werden können (alternative Aktion) +\end{itemize} +\subsection{Unchecked Exceptions (z.B. NullPointerException)} +\begin{itemize} + \item leiten von RuntimeException ab + \item Verwendung für technische Probleme (User kann nichts machen außer neu starten) + \begin{itemize} + \item beschädigte Datenbank - die Exception geht durch alle Layer + \begin{itemize} + \item erst mit Implementierungsspezifischer Exception + \item später mit Runtime \textbf{ohne Stacktrace} bis zum User (-> Destructive wrapping mit Log and Throw im ServiceLayer) + \item im Projekt: ServiceException, DaoException, AuthenticationException und SerializerException + \end{itemize} + \end{itemize} +\end{itemize} +\begin{minted}[linenos,breaklines=true]{java} + package at.fhj.swd.psoe.service; + + public class ServiceException extends RuntimeException { + private static final long serialVersionUID = -1109707847007116930L; + + public ServiceException(String message) {super(message);}} + \end{minted} +\begin{minted}[linenos,breaklines=true]{java} + package at.fhj.swd.psoe.data; + + public class DaoException extends RuntimeException { + private static final long serialVersionUID = -2712863481296295032L; + + public DaoException(String message, Throwable cause) { + super(message, cause); + } + public DaoException(Throwable cause) {super(cause);}} + \end{minted} +\begin{figure}[!htp] + \centering + \includegraphics[width=0.3\textwidth]{pics/except_class_dia.jpg} +\end{figure} +\section{Best Practice Beispiele beim Einsatz von Exceptions} +\begin{itemize} + \item Exceptions nicht für Programmflusskontrolle verwenden (schlechte Performance) + \item offene Ressourcen schließen (try-with-resources bzw. close im finally) + \item selbst erstellte Exceptions auch mit nützlichen Infos ausstatten + \item Implementierungsspezifische Exceptions nicht bis zum User durchwerfen (stattdessen catch + trow RuntimeException) + \item dokumentieren mit @trows im DOC, testen mit JUnit +\end{itemize} +\section{Exception Handling Anti Pattern} +\begin{itemize} + \item Log and Trow (nie beides: entweder, oder) + \item Trowing Exception bzw. catch Exception (spezifischere anstatt Basisklasse verwenden) + \item Destructive Wrapping (wenn bei catch + trow = wrapping nicht die Original Exception weitergegeben wird) + \item Log and return Null (provoziert an einer anderen Stelle eine NullPointerException) + \item Catch and Ignore + \item Unsupported Operation return Null (besser UnsupportedOperationException) +\end{itemize} +\section{Destructive Wrapping im Service Layer} +\begin{itemize} + \item im Codebeispiel wird in Zeile 12 eine IllegalArgumentException (Runtime) gefangen in Zeile 18 die Exception allgemein + \item beide werden in Zeile 14 bzw. 18 inklusive Stacktrace geloggt + \item ausnahmsweise muss hier zusätzlich auch eine neue ServiceException geschmissen werden, jedoch \textbf{ohne Stacktrace} (siehe Zeile 15 und 19) +\end{itemize} +\begin{minted}[linenos,breaklines=true]{java} + package at.fhj.swd.psoe.service.impl; + ... + @Override + public List getDocumentsFromCommunity(Long communityID) { + try { + List documents; + if (communityID <= 0) throw new IllegalArgumentException("community must not be empty"); + Community community = communityDAO.findById(communityID); + if (community == null) throw new IllegalStateException("community " + communityID + " not found"); + documents = documentDAO.findByCommunity(community); + return documents.stream().map(DocumentMapper::toDTO).collect(Collectors.toList()); + } catch (IllegalArgumentException iaex) { + String errorMsg = "Could not load docs from community (illegal argument)"; + logger.error(errorMsg, iaex); + throw new ServiceException(errorMsg); + } catch (Exception ex) { + String errorMsg = "Could not load docs for community."; + logger.error(errorMsg + " id " + communityID, ex); + throw new ServiceException(errorMsg); + } + } + ... + \end{minted} +\section{Exception Testing} +\begin{minted}[linenos,breaklines=true]{java} + package at.fhj.swd.psoe.service; + + import java.util.ArrayList; + ... + + @RunWith(MockitoJUnitRunner.Silent.class) + public class DocumentServiceTest { + @Mock + private DocumentDAO documentDAO; + ... + + @Test(expected = ServiceException.class) +public void getDocumentsFromCommunity_WithId0_ShouldFail() { + documentService.getDocumentsFromCommunity(0L); + } + + @Test(expected = ServiceException.class) + public void getDocumentsFromCommunity_NoDocuments_ShouldFail() { + Community community = Mockito.mock(Community.class); + Mockito.when(community.getId()).thenReturn(COMMUNITYID); + Documentlibrary doclib = Mockito.mock(Documentlibrary.class); + Mockito.when(community.getDocumentlibrary()).thenReturn(doclib); + Mockito.when(doclib.getCommunity()).thenReturn(community); + Mockito.when(communityDAO.findById(community.getId())).thenReturn(null); + + documentService.getDocumentsFromCommunity(COMMUNITYID); + } + ... +\end{minted} diff --git a/parts/03_config.tex b/parts/03_config.tex new file mode 100644 index 0000000..1a81c18 --- /dev/null +++ b/parts/03_config.tex @@ -0,0 +1,233 @@ +\part{Allgemeines \& Config} +\section{Logging} +\subsubsection{Vorteile Logging mittels Framework (z.B.: log4j)} +\begin{itemize} + \item Nutzt ein einheitliches Format / Konventionen + \item logging kann optional an und ausgeschalten werden + \item durch verschiedene Log-level können Logs gefiltert erstellt werden + \item Layout für Ausgabe kann zentral definiert/geändert werden +\end{itemize} +\section{Annotationen} +\begin{itemize} + \item @MappedSuperclass + \begin{itemize} + \item ist im Hybernate Framework + \item eine Klasse durch die gemeinsame Felder definiert werden. + \item definiert eine abstrakte Superklasse + \end{itemize} + \item @Produces + \begin{itemize} + \item kommt während deployment, markiert Factory Method damit man nicht direkt auf die Klasse zugreifen muss + \end{itemize} + \item @Typed + \begin{itemize} + \item zeigt die Vererbung Wieso bei uns allein stehend? + \end{itemize} + \item @Named + \begin{itemize} + \item Zeigt bei Mehrdeutigkeit das richtige Objekt mit dem Namen + \end{itemize} + \item @Resource + \begin{itemize} + \item fast wie Dependency Injection + \end{itemize} + \item @Stateless + \begin{itemize} + \item speichert den Client Status nicht + \end{itemize} + \item @Entity + \begin{itemize} + \item Data Access Layer + \end{itemize} + \item @Table + \begin{itemize} + \item Tabellenname im SQL + \end{itemize} + \item @Column + \begin{itemize} + \item SQL-Spalten nullable=false + \end{itemize} + \item @OneToMany + \item @JoinColums + \begin{itemize} + \item welche Spalten zusammen gehören FK + \end{itemize} + \item @OneToMany + \begin{itemize} + \item auf anderen Seite + \end{itemize} + \item @ApplicationScoped + \begin{itemize} + \item lebt die ganze Applikation lang, wird einmal gemacht. + \end{itemize} + \item @PersistenceContext + \begin{itemize} + \item persistance.xml auslesen für Treiber und andere JPA Geschichten + Data Source. Entity Manager + \end{itemize} + \item @Id + \begin{itemize} + \item das ist die id + \end{itemize} + \item @GeneratedValue + \begin{itemize} + \item Wert kommt aus der DB + \end{itemize} + \item @Local + \begin{itemize} + \item Klasse für lokale Aufrufe. + \end{itemize} + \item @Remote + \begin{itemize} + \item interprozessaufrufe. RMI + \end{itemize} + \item @ApplicationException + \begin{itemize} + \item Rollback wenn so eine Exception kommt, Nachricht zum Client. + \end{itemize} +\end{itemize} + +\section{Konfigurationsdateien} +\subsection{standalone-psoe.xml} +\subsection{persistance.xml} +\begin{figure}[!htp] + \centering + \includegraphics[width=0.7\textwidth]{pics/ConfigFiles.png} +\end{figure} +\subsection{web.xml} +\begin{itemize} + \item konfiguriert den Java Webserver (Wildfly - JBOSS) + \item befindet sich im Ordner \textbf{src/main/webapp/WEB-INF/web.xml} +\end{itemize} +\begin{minted}[linenos,breaklines=true]{xml} + + +... + +Faces Servlet +javax.faces.webapp.FacesServlet +1 + + +Faces Servlet +*.xhtml + + + + +administrators +ADMIN + + +portal administrators +PORTALADMIN + + +standard user +USER + + + + + +admin area +/admin/* + + +ADMIN + + + + + +community area +/community/* + + +USER +PORTALADMIN +ADMIN + + + + + +user administration area +/userAdministration/* + + +USER +PORTALADMIN +ADMIN + + + + + + +user functionalities +/user.xhtml +/userlist.xhtml +/notImplemented.xhtml + + +USER +PORTALADMIN +ADMIN + + + + + +other functionalities +/notImplemented.xhtml + + +USER +PORTALADMIN +ADMIN + + + + +FORM +pse + +/login.xhtml +/login.xhtml + + + + +\end{minted} +\subsection{pom.xml} +\begin{itemize} + \item Resource plugin – klar für Ressourcen + \item Wildfly – server +\begin{multicols}{2} + \begin{enumerate} + \item Compile + \item Surefire (unitTests) + \item Packaging - war file erstellen + \item Wildfly - fressen und deployen + \item Failsafe IT-test + \item MVN site + \item Gui test + \end{enumerate} +\end{multicols} + \item Primeafce = jsf Framework + \item Jacoco = test Coverage + \item Slf4j = logger + \item Jaxb – xml + \item Cdi = context dependancy injection +\end{itemize} +\section{Frageart Prüfung} +Welche Fehler können bei Exception-Handling vorkommen in unserem Projekt?? – wie funktioniert es grundsätzlich in unserem Code + +DocumentDAO – DocumentService – DocumentController – so sollte Exception-Handling implementiert warden + +DAO wirft Exception – im ServiceLayer wird dies gefangen und der Stack-Trace wird im weggeloggt und eine benutzerfreundliche Fehlermeldung wird ausgegeben (Destructive Wrapping). + +Alle Patterns, die vorkommen – praktische Beispiele aus dem Code + +Was sind JavaBeans? Wie funktioniert das Konzept? Wie wird es genau implementiert? +NamedBean, TypedBean etc. \ No newline at end of file diff --git a/pics/domain-layer.png b/pics/domain-layer.png new file mode 100644 index 0000000..ba8fea4 Binary files /dev/null and b/pics/domain-layer.png differ diff --git a/pics/page-object.png b/pics/page-object.png new file mode 100644 index 0000000..206987b Binary files /dev/null and b/pics/page-object.png differ diff --git a/pse.pdf b/pse.pdf index 7c87d1d..330172e 100644 Binary files a/pse.pdf and b/pse.pdf differ diff --git a/pse.tex b/pse.tex index 440a89d..0cfd907 100644 --- a/pse.tex +++ b/pse.tex @@ -20,815 +20,8 @@ \pagebreak \tableofcontents \pagebreak +\include{parts/01_patterns} +\include{parts/02_exceptions} +\include{parts/03_config} -\part{Pattern im Projekt} -\section{Layers Pattern} -\subsection{Erkläre die Funktionsweise + Skizze} -\begin{itemize} - \item Client schickt eine Anfrage an Layer N - \item Layer N reicht da er nicht vollständig alleine beantworten kann, Anfragen an darunterliegenden Layer weiter - \item Eine Anfrage kann bei Bedarf auch in mehrere Anfragen an darunterliegende Layer geteilt werden - \item dies wird immer weiter fortgesetzt bis Layer 1 erreicht ist - \item dabei gehen Abhängigkeiten nur von oben nach unten -\end{itemize} -\begin{figure}[!htp] - \centering - \includegraphics[width=0.8\textwidth]{pics/esa_layers.jpg} -\end{figure} -\subsubsection{3 Schichten Architektur:} -\begin{itemize} - \item Data Source Layer (data): Zugriff auf Daten, kümmert sich um Kommunikation mit anderen Systemen (z.B.: Datenbank) - \begin{itemize} - \item beinhaltet DAO und DAOImpl >> DocumentDAO, DocumentlibraryDAO - \end{itemize} - \item Domain Layer(service): enthält Business Logik (Berechnungen, Datenvalidierung, ...) - \begin{itemize} - \item beinhaltet - \begin{itemize} - \item \textbf{Service Layer Pattern} (aka Session Fassade - siehe~\ref{sec:slp}) - \item DTO >> DocumentDTO - \item Mapper >> DocumentMapper - \begin{minted}[breaklines=true]{java} -public static Document toEntity(DocumentDTO documentDTO, Document document){}; -public static DocumentDTO toDTO(Document document){}; - \end{minted} - \end{itemize} - \end{itemize} - \item Presentation Layer(web): serverseitig, kümmert sich um Benutzerinteraktion - \begin{itemize} - \item Controller (ViewHelper) >> DocumentController, DocumentListController - \item View (WebApp) - \end{itemize} -\end{itemize} -\begin{figure}[tph!] - \centering - \includegraphics[width=0.4\textwidth]{pics/layer-pattern} -\end{figure} -\section{Data Access Object (DAO) Pattern} -Befindet sich im Projekt in data und damit innerhalb des Data Layer. -\subsection{Erkläre die Funktion + Skizze} -\begin{itemize} - \item Client erstellt ein DAO Object und kann nach Entitäten suchen, einfügen, löschen, etc. - \item das DAO selbst soll keine spezifischen Elemente enthalten (Entity Manager, SQL Exception -> stattdessen DAOException) - \item dadurch entsteht eine Kapselung bei der die DAOImpl ohne den Client zu verändern ausgetauscht werden kann -\end{itemize} -\begin{figure}[!htp] - \centering - \includegraphics[width=0.8\textwidth]{pics/dao_pat1.jpg} -\end{figure} -\begin{minted}[breaklines=true]{java} -@ApplicationScoped -public class DocumentDAOImpl implements DocumentDAO, Serializable { - private static final long serialVersionUID = 1L; - private static final Logger logger = LoggerFactory.getLogger(DocumentDAOImpl.class); - @PersistenceContext - private EntityManager entityMangaer; - - @Override - public List findByCommunity(Community community) {...} - - @Override - public List findByUser(User user) {...} - - @Override - public void insert(Document document) {...} - - @Override - public void delete(Document document) {...} - - @Override - public Document findById(Long id) {...} -} -\end{minted} -\subsection{Nenne die Konsequenzen der Anwendung} -\begin{itemize} - \item Zugriff auf persistenten Speicher wird abstrahiert - \item Details des Speichers werden versteckt - \item ermöglicht einheitlichen Zugriff auf Daten - \item entkoppelt Implementierung von Persistierung (Datenbank,...) - \item ermöglicht Objektorientierte Ansicht des Speichers -\end{itemize} -\section{Service Layer Pattern (auch Session Fassade - in unserem Projekt im Domain Layer}\label{sec:slp} -\subsection{Erkläre die Funktion + Skizze}\label{subsubsec:service-layer-pattern} -\begin{itemize} - \item Der Service Layer (Ordner "`service"' im Projekt) delegiert auf die Business Logik (Zeile 68 community.setDocumentlibrary) und zum DAO (z.B. Zeile 66) - \item Bei wenig Logik wird zumindest Transaktions (Zeile 40), Error (ab Zeile 42) und Validierungshandling (ab Zeile 23) im Service erledigt -\end{itemize} -\begin{figure}[!htp] - \centering - \includegraphics[width=0.9\textwidth]{pics/sl_pat1.jpg} - \includegraphics[width=0.7\textwidth]{pics/service.png} -\end{figure} -\begin{minted}[xleftmargin=\parindent,linenos,breaklines=true]{java} - @Local(DocumentService.class) - @Remote(DocumentServiceRemote.class) - @Stateless - public class DocumentServiceImpl implements DocumentService, DocumentServiceRemote, Serializable { - private static final long serialVersionUID = -1L; - private static final Logger logger = LoggerFactory.getLogger(DocumentServiceImpl.class); - - @Inject - private DocumentDAO documentDAO; - @Inject - private DocumentlibraryDAO documentlibraryDAO; - @Inject - private CommunityDAO communityDAO; - @Inject - private UserDAO userDAO; - @Inject - private MessageDAO messageDAO; - @Override - public DocumentDTO addDocument(Long communityID, String userID, byte[] data, String filename) { - Document addedDocument; - User user; - - // Validierungshandling gefolgt von Error Handling - try { - if (communityID <= 0) throw new IllegalArgumentException("community must not be empty"); - if (userID == null) throw new IllegalArgumentException("user must not be empty"); - if (data == null) throw new IllegalArgumentException("uploaded file must not be empty"); - if (filename == null) throw new IllegalArgumentException("filename must not be empty"); - - Documentlibrary documentlibrary = documentlibraryDAO.findByCommunityId(communityID); - - //create a document library, if there isn't already one in the database - if (documentlibrary == null) { - documentlibrary = addDocumentlibrary(communityID); - } - - user = userDAO.getByUserId(userID); - - addedDocument = new Document(documentlibrary, user, filename, data); - documentDAO.insert(addedDocument); // Transaktionshandling - logger.info(String.format("Document %s saved in database", filename)); - // Error Handling - } catch (IllegalArgumentException iaex) { - String errorMsg = "Uploading file failed (illegal argument)"; - logger.error(errorMsg, iaex); - throw new ServiceException(errorMsg); - - } catch (Exception ex) { - String errorMsg = String.format("Uploading file %s failed.", filename); - logger.error(errorMsg, ex); - throw new ServiceException(errorMsg); - } - - String msgText = "Uploaded Document " + filename + " by user " + user.getUserId(); - addMessageToStream(communityID, user, msgText, addedDocument); - return DocumentMapper.toDTO(addedDocument); - } - - - private void addMessageToStream(Long communityID, User user, String text, Document document) {...} - - private Documentlibrary addDocumentlibrary(Long communityID) { - logger.info("Create missing documentlibrary"); - Community community; - Documentlibrary documentlibrary = new Documentlibrary(); - documentlibraryDAO.insert(documentlibrary); // Delegation zum DAO - community = communityDAO.findById(communityID); // Delegation zum DAO - community.setDocumentlibrary(documentlibrary); // Delegation zur Business Logik (Entity) - communityDAO.update(community); // Delegation zum DAO - return documentlibrary; - } - - @Override - public List getDocumentsFromCommunity(Long communityID) {...} - - @Override - public List getDocumentsFromUser(String userID) {...} - - @Override - public void removeDocument(Long documentID) {...} - - @Override - public DocumentDTO getDocumentById(Long documentID) {...} - } -\end{minted} - -\subsection{Nenne die Konsequenzen der Anwendung} -\begin{itemize} - \item Reduzierung der Abhängigkeiten zwischen Presentation und Domain Layer - \item Zentralisiertes Sicherheits und Transaktionshandling - \item verbirgt vor Client Komplexität der Business Logik - \item stellt Client ein grobkörniges Interface zur Verfügung - \item gut für Remote Aufrufe geeignet (weniger Aufrufe) - -\end{itemize} - -\section{Model-View-Controller (MVC) Pattern} -\subsection{Erkläre die Funktion + Skizze} -MVC unterteilt eine interaktive Applikation in drei Teile: Model, View und Controller. -\begin{itemize} - \item Controller und View befinden sich im Presentation Layer und haben gegenseitig Abhängigkeiten - \item Das Model darf keine Abhängigkeiten haben (Controller und View hängen vom Model ab) -\end{itemize} -\begin{figure}[!htp] - \centering - \includegraphics[width=0.8\textwidth]{pics/mvc_pat.jpg} -\end{figure} -\subsubsection{Model} -\begin{itemize} - \item Es befinden sich Teile im Domain und Data Source Layer. - \item Das Model enthält die Kernfunktionalität und Daten. (z.B.: Datenbankzugriff) - \item Im Projekt wird dies durch die Ordner \textit{service} und \textit{data} repräsentiert -\end{itemize} -\subsubsection{View} -\begin{itemize} - \item Im Projekt im Ordner \textit{webapp} zu finden. - \item Enthält im Projekt xhtml Dateien zur Darstellung und User Interaktion -\end{itemize} -\subsubsection{Controller} -\begin{itemize} - \item Im Projekt sind Controllerklassen im Ordner \textit{web} zu finden. - \item Sie enthalten die Logik und behandeln Benutzereingaben -\end{itemize} -\section{Front Controller} -\subsection{Erkläre die Funktion + Skizze} -\begin{itemize} - \item Client schickt Request an Front Controller - \item FC erfasst nur Infos die er für die weiter Delegation braucht - \item FC gibt Request an entsprechenden ConcreteCommand oder View weiter - \item es gibt zwei Implementierungsvarianten des Controller - \begin{multicols}{2} - \begin{itemize} - \item Servlet - \item ConcreteCommand - \end{itemize} - \end{multicols} - - \end{itemize} -\subsection{Servlet} -\begin{itemize} -\item Im Projekt wurde der Front Controller in Form eines Servlet realisiert, -\item die Einbindung erfolgt in der Konfigurationsdatei \textit{src/main/webapp/WEB-INF/web.xml}, -\item Servlet ist eine Java-API, welche auf einem Server betrieben wird, -\item die Verarbeitung von Requests und Responses wird ermöglicht, -\item JSF und JSP können darauf aufsetzen, in unserem Projekt wurde JSF verwendet -\end{itemize} -\begin{minted}[linenos,breaklines=true]{xml} - - -... - -Faces Servlet -javax.faces.webapp.FacesServlet -1 - - -Faces Servlet -*.xhtml - -\end{minted} -\subsubsection{Java Server Faces (JSF)} -\begin{itemize} - \item JSF basiert auf dem MVC-Pattern - \item JSF-View-Code ist im Projekt im Ordner \textit{src/main/webapp/*} zu finden - \item JSF-Logik befindet sich in den Java-Beans (im Projekt \textit{/src/main/java/at/fhj/swd/psoe/web/*}) - \item in unserem Projekt gibt es zu jeder xhtml-View eine eigene Controller-Klasse, welche dem ViewHelper-Pattern entspricht - \item in unserem Projekt kommt PrimeFaces zum Einsatz (eine konkrete Implementierungsart von JSF => Einbindung in pom.xml) -%TODO Toni fragen MVC-Aufteilung JSF -\end{itemize} -\begin{figure}[h!] - \centering - \includegraphics[width=0.5\textwidth]{pics/fc_pat.jpg} -\end{figure} -\begin{minted}[linenos,breaklines=true]{xml} - - - - - - -

#{msg.document_manage_title}

- - - - - - - -#{docs.createdTimestamp} -#{docs.user.userId} -#{docs.filename} - - - - - - - - - - - - - - - - - - -
-
-\end{minted} - -\subsection{Nenne die Konsequenzen der Anwendung} -\begin{itemize} - \item es muss nur EIN (Front) Controller konfiguriert werden - \item da bei jedem Request ein neues Command Objekt erzeugt wird ist Thread-Safety nicht notwendig - \item da nur EIN Controller sind auch Erweiterungen durch z.B.: Decorator einfach (auch zur Laufzeit) -\end{itemize} -\section{View Helper (\textit{/src/main/java/at/fhj/swd/psoe/web/*})} -\subsection{Erkläre die Funktion + Skizze} -\begin{figure}[h!] - \centering - \includegraphics[width=0.8\textwidth]{pics/view-helper_pat1.jpg} -\end{figure} -\begin{itemize} - \item View (xhtml-Dateien im Ordner \textit{/src/main/webapp/*}) delegiert Aufgaben an Helper (z.B. DocumentController im Ordner web) - \item Helper adaptieren View zu Model (Klassen in den Ordnern \textit{src/main/java/at/fhj/swd/psoe/service/*} und \textit{src/main/java/at/fhj/swd/psoe/data/*}) - \item in View befindet sich HTML Code im ViewHelper Java Code zur Aufbereitung der Daten (+ wenig HTML) -\end{itemize} -\subsection{Nenne die Konsequenzen der Anwendung} -\begin{itemize} - \item kapselt Design-Code in View und View-Processing-Code Logik in Helper - \item steigert Wiederverwendbarkeit, Wartbarkeit und Strukturierungsqualität der Anwendung - \item vereinfacht Tests (Helperfunktionen ohne View) - \item bessere Trennung zwischen - \begin{itemize} - \item Presentation und Data Source Layer - \item Entwickler und Designer - \end{itemize} -\end{itemize} - - -\section{Dependency Injection (CDI-Framework in pom.xml im Projekt)} -\subsection{Erkläre die Funktion + Skizze} -%TODO Zarwos is die Dependency-Injection in unserem Projekt guat und wo is se, verdammte Scheiße noch amol, wo konfigurierst denn den Dreck donn überhaupt??? -\begin{figure}[!htp] - \centering - \includegraphics[width=0.8\textwidth]{pics/dependency_inj_pat.jpg} -\end{figure} -\begin{itemize} - \item Grundidee sind loose gekoppelte Objekte - \item Objekte werden mittels externem Assembler verknüpft - \item Abhängigkeiten bestehen nur auf Interfaces - \item Assembler Objekt (Framework) erzeugt die Interface-Implementierungen (z.B.: durch Factory) - \item Es wird zwischen Constructor Injection und Setter Injection unterschiedlichen - \begin{minted}[linenos,breaklines=true]{java} - // Constructor Injection - puplic class Client - { - private Interface iface; - public Client(Interface iface) - { - this.iface = iface; - }} - - // Setter Injection - puplic class Client - { - private Interface iface; - public setIface(Interface iface) - { - this.iface = iface; - }} - \end{minted} -\end{itemize} -\begin{itemize} - \item Im Spring Context: - \begin{itemize} - \item Dependency Injection mit XML-Datei - \item alle Beans sind dort gelistet und werden verknüpft - \item Context wird geladen damit alles verknüpft ist - \item erspart Factories - \end{itemize} -\end{itemize} -\subsection{Nenne die Konsequenzen der Anwendung} -\begin{itemize} - \item loose gekoppelte Objekte - \item Referenzen nur noch auf Interfaces - \item hohe Flexibilität (Strategy, Proxy,..) - \item bessere Erweiterbarkeit und Testbarkeit - \item bei Spring kann Dependency Injection mittels XML oder Annotation erfolgen - \begin{itemize} - \item Vorteil Annotation: Typ-Sicherheit (Tippfehler passieren schnell im XML) - \item Nachteil Annotation: nicht so flexibel wie XML - \end{itemize} -\end{itemize} -\section{Data Transfer Object (DTO) Pattern} -\subsection{Erkläre die Funktion (Skizze - ein Grund für DTO)} -\begin{figure}[!htp] - \centering - \includegraphics[width=0.9\textwidth]{pics/lok-vs-remote.jpg} -\end{figure} -\begin{itemize} - \item Transportiert Daten zwischen Prozessen um Remote Methodenaufrufe zu minimieren - \item besteht aus Fields, Getter und Setter - \item fasst Daten verschiedener Objekte zusammen die vom Remote Objekt benötigt werden - \item ev. Map, Record Set, ... -\end{itemize} -\subsection{Verwendung im Projekt in \textit{src/main/java/at/fhj/swd/psoe/service/dto/*}} -\begin{minted}[linenos,breaklines=true]{java} -package at.fhj.swd.psoe.service.dto; - -import java.io.Serializable; -import java.util.Date; - -public class DocumentDTO implements Serializable { - - private static final long serialVersionUID = 4016557982897997689L; - - private Long id; - private Long documentlibraryID; - private String filename; - private UserDTO user; - private byte[] data; - private Date createdTimestamp; - - public DocumentDTO() {} - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Long getDocumentlibraryID() { - return documentlibraryID; - } - - public void setDocumentlibraryID(Long documentlibraryID) { - this.documentlibraryID = documentlibraryID; - } - - public String getFilename() { - return filename; - } - - public void setFilename(String filename) { - this.filename = filename; - } - - public UserDTO getUser() { - return user; - } - - public void setUser(UserDTO user) { - this.user = user; - } - - public byte[] getData() { - return data; - } - - public void setData(byte[] data) { - this.data = data; - } - - public Date getCreatedTimestamp() { - return createdTimestamp; - } - - public void setCreatedTimestamp(Date createdTimestamp) { - this.createdTimestamp = createdTimestamp; - } - - @Override - public String toString() { - return "DocumentDTO{" + - "id=" + id + - ", documentlibraryID=" + documentlibraryID + - ", filename='" + filename + '\'' + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof DocumentDTO)) return false; - - DocumentDTO that = (DocumentDTO) o; - - return id.equals(that.id); - } - - @Override - public int hashCode() { - return id.hashCode(); - } -} -\end{minted} -\subsection{Nenne die Konsequenzen der Anwendung} -\begin{itemize} - \item kapselt und versteckt - \item nimmt Komplexität - \item steigert Effizienz da weniger Aufrufe über Remotegrenze -\end{itemize} - - - - - - - - - - -\section{Page-Object-Pattern} -PageObjectPattern - -HTML – wrappen mit JavaCode, um es zu manipulieren - -GUI-Test-Klasse und Page-Object - -Über die Page-Object-Klasse manipuliere ich das HTML-Dokument - -Bei HTML-Änderung muss ich nur Page-Objekt ändern und ansonsten nichts angreifen (Verkapselung) -\section{Remote} -\section{Beschreibe die Unterschiede zwischen lokalem und Remote Interface Design} -\begin{itemize} - \item Aufrufe innerhalb des Prozesses sind schneller als über Prozessgrenzen - \item lokale Interfaces sind möglichst fein-granular während Remote Interfaces grob-granular sein müssen (weniger Aufrufe - Effizienz) - \item viele kleine Aufrufe mit wenigen Daten sind "teuer" (Latenz durch Verbindungsherstellung) -\end{itemize} -\section{Beschreibe drei Situationen wo Multiple Prozesse in Applikationen verwendet werden müssen} -\begin{itemize} - \item Trennung zwischen Clients und Servern in Business Software - \item Trennung zwischen server-basierter Applikationssoftware und Datenbank (SQL ist als Remote Interface designed, daher sind hier schnelle Abfragen möglich) - \item Trennung wegen unterschiedlichen Anbietern oder Programmiersprachen -\end{itemize} - -\section{Beschreibe das folgende Diagramm. Was können wir daraus für das Design von Remote Interfaces folgern?} -\begin{itemize} - \item speziell bei "teuren" Remote Calls ist es empfehlenswert weniger Calls mit großen Datenmengen anstatt vielen Calls mit wenigen Daten zu machen - \item dieser Gedanke befürwortet auch den Einsatz von DTO um Calls und Daten zu bündeln -\end{itemize} -\begin{figure}[!htp] - \centering - \includegraphics[width=0.9\textwidth]{pics/lok-vs-remote.jpg} -\end{figure} -\section{Exception Handling} -\section{Beschreibe den Unterschied zwischen Checked und Runtime Exceptions in Java (inkl. Klassendiagramm)} -\begin{itemize} - \item Checked Exceptions (z.B. SQL-Exception) leiten von Exception Klasse ab und müssen behandelt werden (trows - catch) - \begin{itemize} - \item Verwendung für Probleme die durch User behoben werden können (alternative Aktion) - \end{itemize} - \item Unchecked Exceptions (z.B. NullPointerException) leiten von RuntimeException ab - \begin{itemize} - \item Verwendung für technische Probleme (User kann nichts machen außer neu starten) - \end{itemize} -\end{itemize} -\begin{figure}[!htp] - \centering - \includegraphics[width=0.3\textwidth]{pics/except_class_dia.jpg} -\end{figure} -\section{Beschreibe einen Use Case für eine Checked Exceptions in Java} -\begin{itemize} - \item eine Netzwerkübertragung schlägt fehl - es ist vorgesehen, dass der Applikations-User dies neu anstoßen kann -\end{itemize} -\section{Beschreibe einen Use Case für eine Runtime Exceptions in Java} -\begin{itemize} - \item Die Datenbank ist beschädigt - die Exception geht durch alle Layer erst mit - Implementierungsspezifischer Exception später mit Runtime ohne Stacktrace (Sicherheit) bis zum User. -\end{itemize} -\section{Beschreibe 5 Best Practice Beispiele beim Einsatz von Exceptions} -\begin{itemize} - \item Exceptions nicht für Programmflusskontrolle verwenden (schlechte Performance) - \item offene Ressourcen schließen (try-with-resources bzw. close im finally) - \item selbst erstellte Exceptions auch mit nützlichen Infos ausstatten - \item Implementierungsspezifische Exceptions nicht bis zum User durchwerfen (stattdessen catch + trow RuntimeException) - \item dokumentieren mit @trows im DOC, testen mit JUnit -\end{itemize} - -\section{Beschreibe 5 Exception Handling Anti Pattern} -\begin{itemize} - \item Log and Trow (nie beides: entweder, oder) - \item Trowing Exception bzw. catch Exception (spezifischere anstatt Basisklasse verwenden) - \item Destructive Wrapping (wenn bei catch + trow = wrapping nicht die Original Exception weitergegeben wird) - \item Log and return Null (provoziert an einer anderen Stelle eine NullPointerException) - \item Catch and Ignore - \item Unsupported Operation return Null (besser UnsupportedOperationException) -\end{itemize} -\section{Logging} -\section{Nenne die Nachteile von debugging mit printf() sowie die Vorteile die Logging Frameworks wie log4j bieten} -\subsection{Nachteile printf()} -\begin{itemize} - \item Produktiv-Code wird überfüllt -> erschwert Lesbarkeit - \item Consolenausgabe wird bei vielen prints auch schnell unübersichtlich - \item im Falle eines vorzeitigen Absturzes können Ausgabedaten verloren gehen - \item Performance bei vielen Logprints -\end{itemize} -\subsection{Vorteile Logging mittels Framework (z.B.: log4j)} -\begin{itemize} - \item Nutzt ein einheitliches Format / Konventionen - \item logging kann optional an und ausgeschalten werden - \item durch verschiedene Log-level können Logs gefiltert erstellt werden - \item Layout für Ausgabe kann zentral definiert/geändert werden -\end{itemize} -\part{Project Structure} -\section{Annotationen} -\subsection{@MappedSuperclass} -\begin{itemize} - \item ist im Hybernate Framework eine Klasse durch die gemeinsame Felder definiert werden. - \item definiert eine abstrakte Superklasse -\end{itemize} - -@Produces – kommt während deployment, markiert Factory Method damit man nicht direkt auf die Klasse zugreifen muss -@Typed – zeigt die Vererbung Wieso bei uns allein stehend? -@Named – Zeigt bei Mehrdeutigkeit das richtige Objekt mit dem Namen -@Resource – fast wie Dependency Injection -@Stateless – speichert den Client Status nicht -@Entity – Data Access Layer -@Table – Tabellenname im SQL -@Column – SQL-Spalten nullable=false -@OneToMany Beziehung -@JoinColums – welche Spalten zusammen gehören FK -@OneToMany FK auf anderen Seite -@ApplicationScoped – lebt die ganze Applikation lang, wird einmal gemacht. -@PersistenceContext – persistance.xml auslesen für Treiber und andere JPA Geschichten + Data Source. Entity Manager Injection. -@Id – das ist die id -@GeneratedValue – Wert kommt aus der DB -@Local – Klasse für lokale Aufrufe. -@Remote – interprozessaufrufe. RMI -@ApplicationException – Rollback wenn so eine Exception kommt, Nachricht zum Client. -\section{Patterns in Practice} -Data Access Layer -Entity – Java Repräsentation vom DB Entity -DAO damit man auf die Entities zugreifen kann. DB abstrahieren. Methoden mit denen man auf die DB zugreifen kann. -DAOImpl – Implementierung -DAOImpl – DAOException fehlt. Schlecht weil Input wird nicht kontrolliert. EntityManager in try catch, sonst kann es kleschen. Zusätzlich in DaoException wrappen. -AbstractEntity – hier wird die id gemanaged -Service Layer -DTO – Aufrufgeschw. Verringern, nicht jedes Objekt einzeln aufrufen, sondern mit einmal alle notwendigen Objekte. -Mapper – von DTO in Entity und Entity ins DTO. - -FrontController web.xml -ViewHelper *ServiceImpl -\section{Konfigurationsdateien (pom.xml), (persistence.xml) und noch a bissl mehr Scheiß} -Resource plugin – klar für Ressourcen -Wildfly – server -Primeafce = jsf Framework -Jacoco = test Coverage -Slf4j = logger -Jaxb – xml -Cdi = context dependancy injection -\section{Reihenfolge - Wildfly - Abfolge - einzelne Schritte} -Reihenfolge: -\begin{multicols}{2} - \begin{enumerate} - \item Compile - \item Surefire (unitTests) - \item Packaging - war file erstellen - \item Wildfly - fressen und deployen - \item Failsafe IT-test - \item MVN site - \item Gui test - \end{enumerate} -\end{multicols} - -\section{Frageart Prüfung} -Welche Fehler können bei Exception-Handling vorkommen in unserem Projekt?? – wie funktioniert es grundsätzlich in unserem Code - -DocumentDAO – DocumentService – DocumentController – so sollte Exception-Handling implementiert warden - -DAO wirft Exception – im ServiceLayer wird dies gefangen und der Stack-Trace wird im weggeloggt und eine benutzerfreundliche Fehlermeldung wird ausgegeben (Destructive Wrapping). - -Alle Patterns, die vorkommen – praktische Beispiele aus dem Code - -Was sind JavaBeans? Wie funktioniert das Konzept? Wie wird es genau implementiert? -NamedBean, TypedBean etc. - -DTO - - -\section{Die CONFIG-Files} -\begin{figure}[!htp] - \centering - \includegraphics[width=0.7\textwidth]{pics/ConfigFiles.png} -\end{figure} -\subsection{web.xml} -\begin{itemize} - \item konfiguriert den Java Webserver (Wildfly - JBOSS) - \item befindet sich im Ordner \textbf{src/main/webapp/WEB-INF/web.xml} -\end{itemize} - -\begin{minted}[linenos,breaklines=true]{xml} - - -... - -Faces Servlet -javax.faces.webapp.FacesServlet -1 - - -Faces Servlet -*.xhtml - - - - -administrators -ADMIN - - -portal administrators -PORTALADMIN - - -standard user -USER - - - - - -admin area -/admin/* - - -ADMIN - - - - - -community area -/community/* - - -USER -PORTALADMIN -ADMIN - - - - - -user administration area -/userAdministration/* - - -USER -PORTALADMIN -ADMIN - - - - - - -user functionalities -/user.xhtml -/userlist.xhtml -/notImplemented.xhtml - - -USER -PORTALADMIN -ADMIN - - - - - -other functionalities -/notImplemented.xhtml - - -USER -PORTALADMIN -ADMIN - - - - -FORM -pse - -/login.xhtml -/login.xhtml - - - - -\end{minted} -\end{document} \ No newline at end of file +\end{document}