finished part 1 and 2 -> prepared part 3, please finish and todos

This commit is contained in:
Daniel Sommer 2019-03-03 00:21:08 +01:00
parent 507430df6c
commit 9fc30c4e7c
7 changed files with 980 additions and 811 deletions

622
parts/01_patterns.tex Normal file
View File

@ -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<Document> findByCommunity(Community community) {...}
@Override
public List<Document> 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<DocumentDTO> getDocumentsFromCommunity(Long communityID) {...}
@Override
public List<DocumentDTO> 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}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
...
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
\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}
<!-- Pfad: /src/main/webapp/community/documentManagement.xhtml -->
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core"
template="communityTemplate.xhtml">
<ui:define name="communityContent">
<h1>#{msg.document_manage_title}</h1>
<f:metadata>
<f:viewAction action="#{documentListController.loadDocumentsFromCommunity()}" />
</f:metadata>
<h:form id="doclistform">
<p:commandButton value="Refresh list" actionListener="#{documentListController.loadDocumentsFromCommunity()}" update="@form doclistform"></p:commandButton>
<p:dataTable id="doclisttable" value="#{documentListController.communityDocuments}" var="docs">
<p:column class="documenttimecolumn" headerText="#{msg.document_uploaded}">#{docs.createdTimestamp}</p:column>
<p:column class="documenttimecolumn" headerText="#{msg.label_userid}">#{docs.user.userId}</p:column>
<p:column headerText="#{msg.label_filename}">#{docs.filename}</p:column>
<p:column headerText="" class="documentbuttoncolumn">
<p:commandButton value="#{msg.button_download}" ajax="false"
onclick="PrimeFaces.monitorDownload(start, stop);">
<p:fileDownload value="#{documentController.downloadDocument(docs.id)}"/>
</p:commandButton>
</p:column>
<p:column headerText="" class="documentbuttoncolumn">
<p:commandButton id="btnDel" value="#{msg.button_delete}"
actionListener="#{documentController.removeDocument(docs.id)}"
update="@form doclistform">
</p:commandButton>
</p:column>
</p:dataTable>
</h:form>
<h:form id="formdocupload" enctype="multipart/form-data">
<p:fileUpload id="fileupload"
dragDropSupport="false"
update="@form doclistform"
fileUploadListener="#{documentController.uploadDocument}"
allowTypes="/(\.|\/)(pdf|jpe?g|docx)\$/" sizeLimit="5000000"
mode="advanced" label="Add document (.pdf .jpg .docx)">
</p:fileUpload>
</h:form>
<p:messages id="feedbackBox" severity="info,error" showDetail="true" showSummary="false">
<p:autoUpdate/>
</p:messages>
</ui:define>
</ui:composition>
\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<WebElement> list;
public DocumentsListPage(WebDriver driver) {
super(driver);
}
public List<WebElement> 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}

121
parts/02_exceptions.tex Normal file
View File

@ -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<DocumentDTO> getDocumentsFromCommunity(Long communityID) {
try {
List<Document> 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}

233
parts/03_config.tex Normal file
View File

@ -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}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
...
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<!-- Security roles -->
<security-role>
<description>administrators</description>
<role-name>ADMIN</role-name>
</security-role>
<security-role>
<description>portal administrators</description>
<role-name>PORTALADMIN</role-name>
</security-role>
<security-role>
<description>standard user</description>
<role-name>USER</role-name>
</security-role>
<!-- Security constraints -->
<security-constraint>
<web-resource-collection>
<web-resource-name>admin area</web-resource-name>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>ADMIN</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>community area</web-resource-name>
<url-pattern>/community/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>USER</role-name>
<role-name>PORTALADMIN</role-name>
<role-name>ADMIN</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>user administration area</web-resource-name>
<url-pattern>/userAdministration/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>USER</role-name>
<role-name>PORTALADMIN</role-name>
<role-name>ADMIN</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>user functionalities</web-resource-name>
<url-pattern>/user.xhtml</url-pattern>
<url-pattern>/userlist.xhtml</url-pattern>
<url-pattern>/notImplemented.xhtml</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>USER</role-name>
<role-name>PORTALADMIN</role-name>
<role-name>ADMIN</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>other functionalities</web-resource-name>
<url-pattern>/notImplemented.xhtml</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>USER</role-name>
<role-name>PORTALADMIN</role-name>
<role-name>ADMIN</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>pse</realm-name>
<form-login-config>
<form-login-page>/login.xhtml</form-login-page>
<form-error-page>/login.xhtml</form-error-page>
<!-- <form-error-page>/loginerror.xhtml</form-error-page> -->
</form-login-config>
</login-config>
</web-app>
\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.

BIN
pics/domain-layer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
pics/page-object.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
pse.pdf

Binary file not shown.

815
pse.tex
View File

@ -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<Document> findByCommunity(Community community) {...}
@Override
public List<Document> 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<DocumentDTO> getDocumentsFromCommunity(Long communityID) {...}
@Override
public List<DocumentDTO> 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}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
...
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
\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}
<!-- Pfad: /src/main/webapp/community/documentManagement.xhtml -->
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core"
template="communityTemplate.xhtml">
<ui:define name="communityContent">
<h1>#{msg.document_manage_title}</h1>
<f:metadata>
<f:viewAction action="#{documentListController.loadDocumentsFromCommunity()}" />
</f:metadata>
<h:form id="doclistform">
<p:commandButton value="Refresh list" actionListener="#{documentListController.loadDocumentsFromCommunity()}" update="@form doclistform"></p:commandButton>
<p:dataTable id="doclisttable" value="#{documentListController.communityDocuments}" var="docs">
<p:column class="documenttimecolumn" headerText="#{msg.document_uploaded}">#{docs.createdTimestamp}</p:column>
<p:column class="documenttimecolumn" headerText="#{msg.label_userid}">#{docs.user.userId}</p:column>
<p:column headerText="#{msg.label_filename}">#{docs.filename}</p:column>
<p:column headerText="" class="documentbuttoncolumn">
<p:commandButton value="#{msg.button_download}" ajax="false"
onclick="PrimeFaces.monitorDownload(start, stop);">
<p:fileDownload value="#{documentController.downloadDocument(docs.id)}"/>
</p:commandButton>
</p:column>
<p:column headerText="" class="documentbuttoncolumn">
<p:commandButton id="btnDel" value="#{msg.button_delete}"
actionListener="#{documentController.removeDocument(docs.id)}"
update="@form doclistform">
</p:commandButton>
</p:column>
</p:dataTable>
</h:form>
<h:form id="formdocupload" enctype="multipart/form-data">
<p:fileUpload id="fileupload"
dragDropSupport="false"
update="@form doclistform"
fileUploadListener="#{documentController.uploadDocument}"
allowTypes="/(\.|\/)(pdf|jpe?g|docx)\$/" sizeLimit="5000000"
mode="advanced" label="Add document (.pdf .jpg .docx)">
</p:fileUpload>
</h:form>
<p:messages id="feedbackBox" severity="info,error" showDetail="true" showSummary="false">
<p:autoUpdate/>
</p:messages>
</ui:define>
</ui:composition>
\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}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
...
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<!-- Security roles -->
<security-role>
<description>administrators</description>
<role-name>ADMIN</role-name>
</security-role>
<security-role>
<description>portal administrators</description>
<role-name>PORTALADMIN</role-name>
</security-role>
<security-role>
<description>standard user</description>
<role-name>USER</role-name>
</security-role>
<!-- Security constraints -->
<security-constraint>
<web-resource-collection>
<web-resource-name>admin area</web-resource-name>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>ADMIN</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>community area</web-resource-name>
<url-pattern>/community/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>USER</role-name>
<role-name>PORTALADMIN</role-name>
<role-name>ADMIN</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>user administration area</web-resource-name>
<url-pattern>/userAdministration/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>USER</role-name>
<role-name>PORTALADMIN</role-name>
<role-name>ADMIN</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>user functionalities</web-resource-name>
<url-pattern>/user.xhtml</url-pattern>
<url-pattern>/userlist.xhtml</url-pattern>
<url-pattern>/notImplemented.xhtml</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>USER</role-name>
<role-name>PORTALADMIN</role-name>
<role-name>ADMIN</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>other functionalities</web-resource-name>
<url-pattern>/notImplemented.xhtml</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>USER</role-name>
<role-name>PORTALADMIN</role-name>
<role-name>ADMIN</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>pse</realm-name>
<form-login-config>
<form-login-page>/login.xhtml</form-login-page>
<form-error-page>/login.xhtml</form-error-page>
<!-- <form-error-page>/loginerror.xhtml</form-error-page> -->
</form-login-config>
</login-config>
</web-app>
\end{minted}
\end{document}
\end{document}