5. Übung zu Software Engineering WS 2009/2010 Henning Heitkötter
Desktop-Anwendung AUFGABE 13 1
Schichtenarchitektur Strukturierung komplexer Anwendungen Anforderungen: Flexibilität, Robustheit, Wartbarkeit, Wiederverwendbarkeit, Skalierbarkeit Separation of concerns intern zusammenhängende Komponenten, lose mit anderen Komponenten gekoppelt Aufteilung der Komponenten in mehrere Schichten Ähnliches Abstraktionsniveau, enge Kopplung innerhalb einer Schicht Lose Anbindung an darunterliegende Schichten Strikte oder gelockerte Schichtenarchitektur Direkte Top-down und indirekte Bottom-up Interaktion 2
Umfragesystem 3
Übersicht GUI Liste der Umfragen Neue Umfrage anlegen Umfrage anzeigen / Abstimmen Logik Umfrageverwaltung Benutzerauthentifizierung Daten Datenklassen Datenbank 4
Klassendiagramm 5
Alternativen Qualifizierte Assoziation Partitionierung der Menge der referenzierten Objekte (vom Typ Antwort) anhand des qualifizierenden Attributs (hier: Objekt vom Typ Benutzer) Für eine Umfrage gilt: für jeden Benutzer gibt es maximal eine referenzierte Antwort auf diese Umfrage 6
Implementierung qualifizierter Assoziationen Assoziatives Array class Umfrage { Map<Benutzer, Antwort> antworten = ; Antwort getantwort(benutzer b) { antworten.get(b); Antwort Boolean Benutzer String 7
Klasse Umfrage public class Survey { protected String title; protected String text; protected final Date start; protected Date end; protected Map<String, Boolean> answermap; 8
Antwort hinzufügen public void addanswer(string user, boolean yes) { if (!isopen()) throw new IllegalStateException("Diese Umfrage ist beendet."); if (answermap.containskey(user)) throw new IllegalArgumentException("Der Nutzer hat schon abgestimmt."); answermap.put(user, yes); 9
Datenbank Speicherung der Daten in einer Datei Serialisierung und Deserialisierung einer Liste von Umfrageobjekten ObjectOutputStream schreibt komplette Objektgraphen in einen Ausgabestrom (z.b. eine Datei) ObjectInputStream zum Einlesen 10
Objekte in einer Datei speichern protected List<ISurvey> surveydb; public void storesurveydb() throws IOException { ObjectOutputStream out = null; try { out = new ObjectOutputStream(new FileOutputStream(FILENAME)); out.writeobject(surveydb); finally { if (out!= null) { out.close(); 11
protected List<ISurvey> loadsurveydb() throws IOException { File inputfile = new File(FILENAME); if (inputfile.exists()) { ObjectInputStream in = new ObjectInputStream(new FileInputStream(inputFile)); try { return (List<ISurvey>) in.readobject(); catch (ClassNotFoundException ex) { finally { in.close(); return new ArrayList<ISurvey>(); Umfragen aus der Datei laden 12
Übersicht GUI Liste der Umfragen Neue Umfrage anlegen Umfrage anzeigen / Abstimmen Logik Umfrageverwaltung Benutzerauthentifizierung Daten Datenklassen Datenbank 13
Umfrage erstellen public Survey createsurvey(string title, String text, Date end) { for (Survey s : getsurveylist()) if (s.gettitle().equals(title)) throw new IllegalArgumentException("Es existiert schon eine Umfrage mit diesem Titel."); Survey result = new Survey(title, text, end); getsurveylist().add(result); return result; 14
Antworten public void answersurvey(isurvey s, String user, String pwd, boolean yes) { if (!Authentication.isValidUser(user, pwd)) throw new IllegalArgumentException("Keine gültige Kombination aus E-Mail und Passwort."); s.addanswer(user, yes); 15
Übersicht GUI Liste der Umfragen Neue Umfrage anlegen Umfrage anzeigen / Abstimmen Logik Umfrageverwaltung Benutzerauthentifizierung Daten Datenklassen Datenbank 16
Hauptfenster public class MainWindow extends JFrame { private JButton createsurveybutton; private JList surveylist; public MainWindow() { initcomponents(); private void initcomponents() { settitle("umfragesystem"); 17
Button Neue Umfrage createsurveybutton = new JButton(); createsurveybutton.settext("neue Umfrage"); add(createsurveybutton); createsurveybutton.addactionlistener( new ActionListener() { public void actionperformed(actionevent evt) { JFrame createview = new SurveyCreationView(); createview.setlocationrelativeto(this); createview.setvisible(true); ); 18
public void actionperformed(actionevent evt) { Date end = (Date) endfield.getvalue(); Calendar endcal = new GregorianCalendar(); endcal.settime(end); setendofday(endcal); Neue Umfrage try { manager.createsurvey(titlefield. gettext(), textarea.gettext(), endcal.gettime()); dispose(); catch (IllegalArgumentException e) { JOptionPane.showMessageDialog(this, e.getmessage()); 19
Datenbindung der Umfragenliste Die angezeigte Liste der Umfragen soll mit der internen Liste der Umfragen synchronisiert werden. Initialisierung mit der internen Liste beim Start Darstellung einer Umfrage über ihren Titel Aktualisierung der Inhalte, wenn neue Umfragen hinzugefügt werden JList erhält Daten von ListModel getsize, getelementat Benachrichtigung über Listener addlistdatalistener 20
public class SurveyManagement implements ListModel { ListModel-Implementierung private List<ListDataListener> datalistenerlist = new ArrayList<ListDataListener>(); public int getsize() { return getsurveylist().size(); public Object getelementat(int index) { return getsurveylist().get(index); public void addlistdatalistener(listdatalistener l) { datalistenerlist.add(l); 21
Benachrichtigung public ISurvey createsurvey(string title, String text, Date end) { getsurveylist().add(result); surveylistelementadded(); protected void surveylistelementadded() { ListDataEvent lde = new ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, getsurveylist().size() 1, getsurveylist().size() - 1); for (ListDataListener ldd : datalistenerlist) ldd.intervaladded(lde); 22
public class SurveyInfoView extends JFrame { private final ISurvey survey; public ISurvey getsurvey() { return survey; Anzeige einer Umfrage public SurveyInfoView(ISurvey survey) { this.survey = survey; initcomponents(); private void initcomponents() { jlabel6.settext(string.valueof(getsurvey().getyescount())); answerpanel.setvisible(getsurvey().isopen()); 23
Enterprise JavaBeans AUFGABE 14 24
Java EE Plattform für verteilte, mehrschichtige Anwendungen Sammlung verschiedener APIs Web-Schicht: Servlets, Enterprise JavaBeans (EJB) Java Persistence API (JPA) Web Services Transaktionen Implementierung durch Java EE-Server EJB-Container, Web-Container 25
Entities Entity = Beschreibung persistenter Objekte Java-Klasse Parameterloser Konstruktor Zugriffsgeschützte Instanzvariablen (private, protected, -) Zugriff von außen nur über Methoden Annotationen @Entity Primärschlüssel: @Id Beziehungen zu anderen Entities: @OneToMany, @ManyToOne, Objektrelationales Mapping Entity Tabelle Instanz einer Entity Zeile der Tabelle 26
@Entity public class Lager implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String bezeichnung; private String strasse; private String hausnr; private String plz; private String ort; Entity Lager @OneToMany(mappedBy = "lager") private Collection<Lagerplatz> lagerplatzliste = new ArrayList<Lagerplatz>(); 27
Enterprise JavaBeans Server-Komponente, die Geschäftslogik realisiert Arten Session Bean (Stateful oder Stateless) Message-Driven Bean (Entity) Session Beans Verwaltet durch EJB-Container, der Systemdienste bereitstellt (Transaktionen, Sicherheit) Session Bean Enterprise Bean-Klasse implementiert Geschäftsmethoden Methoden deklariert in Remote oder Local Interface Lebenszyklus vom EJB-Container verwaltet 28
@Local public interface LagerVerwaltungLocal { Rahmen der Session Bean public void createlager(string bezeichnung, String strasse, String hausnr, String plz, String ort); public int berechnewarenwert(string bezeichnung); @Stateless public class LagerVerwaltungBean implements LagerVerwaltungLocal { @PersistenceContext private EntityManager em; 29
Lager erzeugen public void createlager(string bezeichnung, String strasse, String hausnr, String plz, String ort) { if (bezeichnung == null bezeichnung.isempty()) { throw new IllegalArgumentException("Keine gültige Bezeichnung."); Query q = em.createquery( "SELECT COUNT(*) FROM Lager l WHERE l.bezeichnung = :b"); q.setparameter("b", bezeichnung); if (((Long) q.getsingleresult()).equals(0l)) { else { Lager l = new Lager(); l.setbezeichnung(bezeichnung); l.setstrasse(strasse); l.sethausnr(hausnr); l.setplz(plz); l.setort(ort); em.persist(l); throw new IllegalArgumentException("Ein Lager mit dieser Bezeichnung existiert schon."); 30
public int berechnewarenwert(string bezeichnung) { Query q = em.createquery("select l FROM Lager l WHERE l.bezeichnung = :b"); q.setparameter("b", bezeichnung); Lager l; Bestand b; try { l = (Lager) q.getsingleresult(); catch (NoResultException e) { throw new IllegalArgumentException(..."); Warenwert berechnen int sum = 0; for (Lagerplatz lp : l.getlagerplatzliste()) { b = lp.getbestand(); if (b!= null) { sum += b.getmenge() * b.getartikel().getwert(); return sum; 31
Verwendung der Session Bean public class LagerAnlegen extends HttpServlet { @EJB private LagerVerwaltungLocal lagerverwaltungbean; protected void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { lagerverwaltungbean.createlager( ); 32
Entwurfsmuster, Testen 6. ÜBUNG 33
Aufgaben Aufgabe 15: Entwurfsmuster Aufgabe 16: Entwurfsmuster Aufgabe 17: Testen (Zusatzaufgabe) 34