finished part 1 and 2 -> prepared part 3, please finish and todos
This commit is contained in:
parent
507430df6c
commit
9fc30c4e7c
|
@ -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}
|
|
@ -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}
|
|
@ -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.
|
Binary file not shown.
After Width: | Height: | Size: 5.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
813
pse.tex
813
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<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}
|
Loading…
Reference in New Issue