Swing MVC Verbindung von Model und Db

CHAOSFISCH

Bekanntes Mitglied
Servus,

Ich plane eine Java Desktop Anwendung basierend auf Swing zu erstellen. Dort will ich dann auch das MVC Model richtig anwenden. Ich hab dazu einiges schon gelesen und werde das MVC nach dem Beispiel von Java SE Application Design With MVC erstellen.

Die Informationen die im View angezeigt werden befinden sich dort stehts im Model. Das Model symbolisiert also ein Objekt, das die Daten "temporär" zwischenspeichert. Ein Model kann danach so aussehen (Darstellung stark verkürzt):
Java:
/** code drüber */
class XYZModel extends AbstractModel implements ABC
{
private String DEF;
private int GHI;
//...

public void getDEF();
}

Dadurch ergibt sich dann mir folgendes Problem: Wie lassen sich diese Model-Objekte sinnvoll abspeichern (die Daten in den Objekten)?
Muss für sowas JPA oder sowas wie Hibernate verwendet werden, um die Daten sinnvoll zu speichern und selbstverständlich auch zu laden und verändern?

Würde das bisher so stimmen?

Gruß
CHAOSFISCH
 
Schon mal das hier angeschaut:
http://www.java-forum.org/awt-swing-swt/128242-mvc-anfaengen.html

Die Model kannst du natürlich mit JPA abspeichern über Annotationen oder über ein orm.xml.
Musst halt die entsprechenden Regeln und Conventions einhalten.

Eigentlich sind JPA Klassen einfache Pojos

Ja, den Link hatte ich bereits bei der Forensuche gefunden 😛.
Für Models heißt das dann:
Einfügen von Annotations oder über orm.xml. Das speichern eines Models (also der Daten) erfolgt dann z.B. durch Aufruf eines EntityManagers, der dieses Model "verwaltet".
 
Ja, den Link hatte ich bereits bei der Forensuche gefunden 😛.
Für Models heißt das dann:
Einfügen von Annotations oder über orm.xml. Das speichern eines Models (also der Daten) erfolgt dann z.B. durch Aufruf eines EntityManagers, der dieses Model "verwaltet".

Ja ganze normales JPA halt. Wie gesagt musst dich halt an die Regeln und Convention halten.
 
So als kleinen Tip, wenn du dein Model mit EMF machst: Eclipse Modeling Framework (EMF) - Tutorial Kannst du dir mittels EMF Texo deine orm.xml generieren lassen: Texo - Eclipsepedia Martin Taal's Blog So als Anregung 😉
Danke werde ich mir dann anschauen.
Bin erst beim Designen des Views.
Eine Frage zu den Models:
Entities stelle Models dar. In der View müssen, z.B. in einer JTable mehrere Zeilen dargestellt werden. Jede Zeile = ein Datensatz. Daraus ergibt sich das jeder Datensatz ein Objekt der Klasse "DatensatzModell" (ein Entity) ist.
Wie macht man das jetzt richtig?
Erstellt man eine HauptKlasse die alle Entities-Objekte enthält und die Entities werden in einer List (oder ähnlichem) "gespeichert". Die HauptKlasse verwaltet dann quasi die Objekte in Form eines Zwischenspeichers. Objekte können über getter/setter-Methoden geladen werden z.B. mit lazy-loading.

Beispiel (gekürzt):

Entity-Kunde.
Java:
@Entity
class Kunde { 
 private int id;
//Setter/Getter Methoden
public getId();
punlic setId();

"HauptModel"

Java:
class ModelVerwalter{
private Set kunden;

public Set getKunden()
{
//Lade Kunden nach API des jeweiligen ORMs
}

Wenn ich das so mache, dann komm ich in das Problem das das View nicht weiß welches Objekt es jetzt ansprechen muss (bzw. vom Controller angesprochen werden muss) um Daten zu ändern.
Gibt es 3 Kunden-Objekte, jeder füllt z.B. eine Zeile in einer JTable.
Es erfolgt ein Aufruf eines Listeners, der auf den Controller (den Mediator) mappt. Der Controller kann herausfinden welche Zeile selected ist.
Wie erkennt er nun welches Objekt selected ist, er kennt ja nur die Zeile!?

Ich denke wahrscheinlich nur zu kompliziert, aber es stellt für mich ein richtiges Problem dar, Model-Objekte richtig zu verwalten.

Gruß
CHAOSFISCH
 
Aso,

ich muss wahrscheinlich eigene TableModels, Lists etc. für diese Komponenten erzeugen, richtig?
Dort kann ich die einmal geladenen Objekte "speichern".
 
Du hast doch jetzt ein ganz normaler Aufbau.
Ich versteh jetzt dein Problem nicht richtig?
😛

Ja ganz normaler Aufbau, einem MVC entsprechend.
Über den EntityManager können Entities-Objekte aus der Datenbank erstellt werden.
Die füge ich z.B. in eine JTable ein => das ist nur möglich mit einer Klasse die AbstractTableModel erweitert (oder mit Beans Binding). Ich hatte da lediglich einige Denkfehler.

Nur durch ein eigenes TableModel kann ein Objekt richtig in der Tabelle angezeigt werden (zuordnung der Objekt-Felder zu den Rows / Cols der Tabelle). Nur durch ein TableModel kann ich, bei Aufruf der Methode getSelectedRow() genau das ausgewählte Objekt wieder bekommen.

Ich hatte davor einen Aufbau das die Objekte außerhalb (ohne eignes TableModel) mit setValueAt() in der Tabelle dargestellt wurden. Das führt dann später zu Problemen, dass ich nicht wissen kann, welches Objekt genau ausgewählt ist in der Tabelle.

Selbiges gilt auch für AbstractListModel, etc.

Das stimmt dann so oder?
 
😛

Ja ganz normaler Aufbau, einem MVC entsprechend.
Über den EntityManager können Entities-Objekte aus der Datenbank erstellt werden.
Die füge ich z.B. in eine JTable ein => das ist nur möglich mit einer Klasse die AbstractTableModel erweitert (oder mit Beans Binding). Ich hatte da lediglich einige Denkfehler.

Das was du bis jetzt hast hat noch rein gar nix mit MVC zu tun. Zur MVC gehört noch mehr z.b. Notifications bei Änderungen.

MVC ist eine Architekturparadigma für die GUI, nicht für die ganze Applikation.
Wo lädst du denn deine Entities?

AbstractTableModel erweitert (oder mit Beans Binding). Ich hatte da lediglich einige Denkfehler.

Nur durch ein eigenes TableModel kann ein Objekt richtig in der Tabelle angezeigt werden (zuordnung der Objekt-Felder zu den Rows / Cols der Tabelle). Nur durch ein TableModel kann ich, bei Aufruf der Methode getSelectedRow() genau das ausgewählte Objekt wieder bekommen.

Ich hatte davor einen Aufbau das die Objekte außerhalb (ohne eignes TableModel) mit setValueAt() in der Tabelle dargestellt wurden. Das führt dann später zu Problemen, dass ich nicht wissen kann, welches Objekt genau ausgewählt ist in der Tabelle.

Selbiges gilt auch für AbstractListModel, etc.

Das stimmt dann so oder?

Ja kommt drauf wenn du Swing verwendest kann das schon passen.
Deine Probleme sind einfach dass du kein Plan von einer JTable hast oder? Solltest erst mal das Tutorial zur JTable durchmachen
 
Das was du bis jetzt hast hat noch rein gar nix mit MVC zu tun. Zur MVC gehört noch mehr z.b. Notifications bei Änderungen.

MVC ist eine Architekturparadigma für die GUI, nicht für die ganze Applikation.
Wo lädst du denn deine Entities?
Die Notifications und die Struktur sind vorhanden.
Wo ich die Entites lade: Bisher noch garnicht - an dem Punkt der Anwendung bin ich noch nicht angelangt. Ich habe zuerst sämtliche Views gerade erstellt.
Wo habe ich sie vor zu laden: Es gibt viele Unterschiedliche Varianten des MVC Patterns. Wenn bei mir ein Modell ein Entity darstellt, so kann dieses entweder nur von einem Modell geladen werden, dass kein Entity ist - also die Logik zum laden der Entites ist in einem weiteren Modell, oder sie werden im Controller geladen.


Ja kommt drauf wenn du Swing verwendest kann das schon passen.
Deine Probleme sind einfach dass du kein Plan von einer JTable hast oder? Solltest erst mal das Tutorial zur JTable durchmachen
Das Problem ist nicht die JTable an sich, sondern dass ich das erste mal mit Entities arbeite und diese auch irgendwie sinnvoll benutzen möchte.

In einer vorherigen Anwendung hatte ich alles durch direkte SQL Queries gelöst. Das bringt je komplexer die Datenstruktur wird jedoch viele Probleme, deswegen JPA.
 
Die Notifications und die Struktur sind vorhanden.
Wo ich die Entites lade: Bisher noch garnicht - an dem Punkt der Anwendung bin ich noch nicht angelangt. Ich habe zuerst sämtliche Views gerade erstellt.
Wo habe ich sie vor zu laden: Es gibt viele Unterschiedliche Varianten des MVC Patterns. Wenn bei mir ein Modell ein Entity darstellt, so kann dieses entweder nur von einem Modell geladen werden, dass kein Entity ist - also die Logik zum laden der Entites ist in einem weiteren Modell, oder sie werden im Controller geladen.

Wie gesagt dass hat NICHTS mehr mit MVC zu tun!!!!
Deine Model sollten wiederverwendbar sein, denkst du da ist es schlaub JPA einzupflanzen?
Normalerweise solltes du einen Service machen der auf den EM zugreift.

Das Problem ist nicht die JTable an sich, sondern dass ich das erste mal mit Entities arbeite und diese auch irgendwie sinnvoll benutzen möchte.

In einer vorherigen Anwendung hatte ich alles durch direkte SQL Queries gelöst. Das bringt je komplexer die Datenstruktur wird jedoch viele Probleme, deswegen JPA.

Du programmierst genau gleich es gibt keinen Unterschied. Ich versteh es nicht sorry mach mal ein KSKB was genau dein Problem ist.
Du musst auch aufpassen wenn du JPA verwendest, wenn du attach Objekte in der GUI veränderst, beim nächsten commit kommt alles in die DB. Also solltest du dich mit JPA beschäftigen und deine Architektur fertig ausdenken.
 
Zuletzt bearbeitet von einem Moderator:
Wie gesagt dass hat NICHTS mehr mit MVC zu tun!!!!
Deine Model sollten wiederverwendbar sein, denkst du da ist es schlaub JPA einzupflanzen?
Normalerweise solltes du einen Service machen der auf den EM zugreift.



Du programmierst genau gleich es gibt keinen Unterschied. Ich versteh es nicht sorry mach mal ein KSKB was genau dein Problem ist.
Du musst auch aufpassen wenn du JPA verwendest, wenn du attach Objekte in der GUI veränderst, beim nächsten commit kommt alles in die DB. Also solltest du dich mit JPA beschäftigen und deine Architektur fertig ausdenken.

So, ich brauchte jetzt ein wenig Zeit zum überdenken des Ganzen.
Im Grunde stimmt doch dann folgender Aufbau:
View-Controller->Services->DAO->DAO-Model
Der Service ist zuständig für die Verwaltung des EM und führt gewisse Sachen damit aus. Über ein DAO wird Unabhängigkeit und Wiederverwendbarkeit geschaffen. Das View muss nicht direkt über das Model bescheidwissen, dass muss nur der Controller. Dabei wird ein Interface implementiert, dass Properties und Methoden für ein Model definiert. Somit ist es dem Controller/View egal ob es ein HibernateKundenModel oder ein EclipselinkKundenModel bekommt, solange beide das Interface KundenModel implementieren.

Stimmt das jetzt so?
Wenn ja dann geb ich die auch noch nen KSKB nachher.
 
So, ich brauchte jetzt ein wenig Zeit zum überdenken des Ganzen.
Im Grunde stimmt doch dann folgender Aufbau:
View-Controller->Services->DAO->DAO-Model
Der Service ist zuständig für die Verwaltung des EM und führt gewisse Sachen damit aus. Über ein DAO wird Unabhängigkeit und Wiederverwendbarkeit geschaffen. Das View muss nicht direkt über das Model bescheidwissen, dass muss nur der Controller. Dabei wird ein Interface implementiert, dass Properties und Methoden für ein Model definiert. Somit ist es dem Controller/View egal ob es ein HibernateKundenModel oder ein EclipselinkKundenModel bekommt, solange beide das Interface KundenModel implementieren.

Stimmt das jetzt so?
Wenn ja dann geb ich die auch noch nen KSKB nachher.

Jop passt 😉, ich hab hier sogar ein KSKB hier im Forum welches genau diesen Aufbau darstellt.

Wie gesagt bei Controller musst du aufpassen, es gibt imho GUI-Controller (UI abhängig z.B. in Swing die Listener) und Controller welche UI unabhängig sind und deine Services aufruft.
Im eigentlichen MVC sind die Controller eigentlich die UI abhängigen also in Swing jeder Listener ist ein Controller...
 
Jop passt 😉, ich hab hier sogar ein KSKB hier im Forum welches genau diesen Aufbau darstellt.

Wie gesagt bei Controller musst du aufpassen, es gibt imho GUI-Controller (UI abhängig z.B. in Swing die Listener) und Controller welche UI unabhängig sind und deine Services aufruft.
Im eigentlichen MVC sind die Controller eigentlich die UI abhängigen also in Swing jeder Listener ist ein Controller...
Diesen Aufbau hab ich mir bereits angeschaut 😛. War aber garnicht so leicht zu finden.
Ich hoffe das ist jetzt nicht zu lang:

Interface QueueEntry
Java:
package coreplugin.db;

import java.util.Collection;

/**
 * Created by IntelliJ IDEA.
 * User: Dennis
 * Date: 03.01.12
 * Time: 17:31
 * To change this template use File | Settings | File Templates.
 */
public interface QueueEntry {

    int identity = 0;
    String title = null;
    String description = null;
    String playlistname = null;
    String category = null;
    String keywords = null;
    boolean privatefile = false;
    boolean unlisted = false;
    boolean playlist = false;
    boolean embed = false;
    boolean rate = false;
    boolean commentvote = false;
    byte comment = 0;
    byte videoresponse = 0;
    boolean mobile = false;
    boolean started = false;
    boolean failed = false;
    short sequence = 0;
    boolean archived = false;
    String file = null;
    String mimetype = null;
    String playlisturi = null;
    String uploadurl = null;
    Collection<AccountsEntity> account = null;

    int getIdentity();

    String getTitle();

    String getDescription();

    String getPlaylistname();

    String getCategory();

    String getKeywords();

    String getFile();

    String getMimetype();

    String getPlaylisturi();

    String getUploadurl();

    Collection<AccountsEntity> getAccount();

    short getSequence();

    byte getComment();

    byte getVideoresponse();

    boolean isPrivatefile();

    boolean isUnlisted();

    boolean isPlaylist();

    boolean isEmbed();

    boolean isRate();

    boolean isCommentvote();

    boolean isMobile();

    boolean isStarted();

    boolean isFailed();

    boolean isArchived();

    void setIdentity(int identity);

    void setTitle(String title);

    void setDescription(String description);

    void setPlaylist(boolean playlist);

    void setPlaylistname(String playlistname);

    void setCategory(String category);

    void setKeywords(String keywords);

    void setPrivatefile(boolean privatefile);

    void setUnlisted(boolean unlisted);

    void setEmbed(boolean embed);

    void setRate(boolean rate);

    void setComment(byte comment);

    void setCommentvote(boolean commentvote);

    void setVideoresponse(byte videoresponse);

    void setMobile(boolean mobile);

    void setStarted(boolean started);

    void setFailed(boolean failed);

    void setSequence(short sequence);

    void setArchived(boolean archived);

    void setFile(String file);

    void setMimetype(String mimetype);

    void setPlaylisturi(String playlisturi);

    void setUploadurl(String uploadurl);

    void setAccount(Collection<AccountsEntity> account);
}

QueueEntity
Java:
package coreplugin.db;

import javax.persistence.Entity;
import javax.persistence.GenerationType;
import java.util.Collection;

/**
 * Created by IntelliJ IDEA.
 * User: Dennis
 * Date: 01.01.12
 * Time: 16:49
 * To change this template use File | Settings | File Templates.
 */
@SuppressWarnings({"CallToStringEquals", "RedundantIfStatement", "DuplicateStringLiteralInspection"})
@javax.persistence.Table(name = "QUEUE", schema = "PUBLIC", catalog = "PUBLIC")
@Entity
public class QueueEntity implements QueueEntry {
    private int identity;

    @javax.persistence.Column(name = "IDENTITY")
    @javax.persistence.Id
    @javax.persistence.GeneratedValue(strategy = GenerationType.IDENTITY)
    @Override
    public int getIdentity() {
        return identity;
    }

    @Override
    public void setIdentity(int identity) {
        this.identity = identity;
    }

    private String title;

    @javax.persistence.Column(name = "TITLE")
    @javax.persistence.Basic
    @Override
    public String getTitle() {
        return title;
    }

    @Override
    public void setTitle(String title) {
        this.title = title;
    }

    private String description;

    @javax.persistence.Column(name = "DESCRIPTION")
    @javax.persistence.Basic
    @Override
    public String getDescription() {
        return description;
    }

    @Override
    public void setDescription(String description) {
        this.description = description;
    }

    private String playlistname;

    @javax.persistence.Column(name = "PLAYLISTNAME")
    @javax.persistence.Basic
    @Override
    public String getPlaylistname() {
        return playlistname;
    }

    @Override
    public void setPlaylistname(String playlistname) {
        this.playlistname = playlistname;
    }

    private String category;

    @javax.persistence.Column(name = "CATEGORY")
    @javax.persistence.Basic
    @Override
    public String getCategory() {
        return category;
    }

    @Override
    public void setCategory(String category) {
        this.category = category;
    }

    private String keywords;

    @javax.persistence.Column(name = "KEYWORDS")
    @javax.persistence.Basic
    @Override
    public String getKeywords() {
        return keywords;
    }

    @Override
    public void setKeywords(String keywords) {
        this.keywords = keywords;
    }

    private boolean privatefile;

    @javax.persistence.Column(name = "PRIVATEFILE")
    @javax.persistence.Basic
    @Override
    public boolean isPrivatefile() {
        return privatefile;
    }

    @Override
    public void setPrivatefile(boolean privatefile) {
        this.privatefile = privatefile;
    }

    private boolean unlisted;

    @javax.persistence.Column(name = "UNLISTED")
    @javax.persistence.Basic
    @Override
    public boolean isUnlisted() {
        return unlisted;
    }

    @Override
    public void setUnlisted(boolean unlisted) {
        this.unlisted = unlisted;
    }

    private boolean playlist;

    @javax.persistence.Column(name = "PLAYLIST")
    @javax.persistence.Basic
    @Override
    public boolean isPlaylist() {
        return playlist;
    }

    @Override
    public void setPlaylist(boolean playlist) {
        this.playlist = playlist;
    }

    private boolean embed;

    @javax.persistence.Column(name = "EMBED")
    @javax.persistence.Basic
    @Override
    public boolean isEmbed() {
        return embed;
    }

    @Override
    public void setEmbed(boolean embed) {
        this.embed = embed;
    }

    private boolean rate;

    @javax.persistence.Column(name = "RATE")
    @javax.persistence.Basic
    @Override
    public boolean isRate() {
        return rate;
    }

    @Override
    public void setRate(boolean rate) {
        this.rate = rate;
    }

    private boolean commentvote;

    @javax.persistence.Column(name = "COMMENTVOTE")
    @javax.persistence.Basic
    @Override
    public boolean isCommentvote() {
        return commentvote;
    }

    @Override
    public void setCommentvote(boolean commentvote) {
        this.commentvote = commentvote;
    }

    private byte comment;

    @javax.persistence.Column(name = "COMMENT")
    @javax.persistence.Basic
    @Override
    public byte getComment() {
        return comment;
    }

    @Override
    public void setComment(byte comment) {
        this.comment = comment;
    }

    private byte videoresponse;

    @javax.persistence.Column(name = "VIDEORESPONSE")
    @javax.persistence.Basic
    @Override
    public byte getVideoresponse() {
        return videoresponse;
    }

    @Override
    public void setVideoresponse(byte videoresponse) {
        this.videoresponse = videoresponse;
    }

    private boolean mobile;

    @javax.persistence.Column(name = "MOBILE")
    @javax.persistence.Basic
    @Override
    public boolean isMobile() {
        return mobile;
    }

    @Override
    public void setMobile(boolean mobile) {
        this.mobile = mobile;
    }

    private boolean started;

    @javax.persistence.Column(name = "STARTED")
    @javax.persistence.Basic
    @Override
    public boolean isStarted() {
        return started;
    }

    @Override
    public void setStarted(boolean started) {
        this.started = started;
    }

    private boolean failed;

    @javax.persistence.Column(name = "FAILED")
    @javax.persistence.Basic
    @Override
    public boolean isFailed() {
        return failed;
    }

    @Override
    public void setFailed(boolean failed) {
        this.failed = failed;
    }

    private short sequence;

    @javax.persistence.Column(name = "SEQUENCE")
    @javax.persistence.Basic
    @Override
    public short getSequence() {
        return sequence;
    }

    @Override
    public void setSequence(short sequence) {
        this.sequence = sequence;
    }

    private boolean archived;

    @javax.persistence.Column(name = "ARCHIVED")
    @javax.persistence.Basic
    @Override
    public boolean isArchived() {
        return archived;
    }

    @Override
    public void setArchived(boolean archived) {
        this.archived = archived;
    }

    private String file;

    @javax.persistence.Column(name = "FILE")
    @javax.persistence.Basic
    @Override
    public String getFile() {
        return file;
    }

    @Override
    public void setFile(String file) {
        this.file = file;
    }

    private String mimetype;

    @javax.persistence.Column(name = "MIMETYPE")
    @javax.persistence.Basic
    @Override
    public String getMimetype() {
        return mimetype;
    }

    @Override
    public void setMimetype(String mimetype) {
        this.mimetype = mimetype;
    }

    private String playlisturi;

    @javax.persistence.Column(name = "PLAYLISTURI")
    @javax.persistence.Basic
    @Override
    public String getPlaylisturi() {
        return playlisturi;
    }

    @Override
    public void setPlaylisturi(String playlisturi) {
        this.playlisturi = playlisturi;
    }

    private String uploadurl;

    @javax.persistence.Column(name = "UPLOADURL")
    @javax.persistence.Basic
    @Override
    public String getUploadurl() {
        return uploadurl;
    }

    @Override
    public void setUploadurl(String uploadurl) {
        this.uploadurl = uploadurl;
    }

    @SuppressWarnings("ConstantConditions")
    @Override
    public boolean equals(Object o) {
     //gekürzt
    }

    @SuppressWarnings("ConstantConditions")
    @Override
    public int hashCode() {
//gekürzt
    }

    private Collection<AccountsEntity> account;

    @javax.persistence.ManyToMany
    @Override
    public Collection<AccountsEntity> getAccount() {
        return account;
    }

    @Override
    public void setAccount(Collection<AccountsEntity> account) {
        this.account = account;
    }
}

Interface QueueDao:
Java:
package coreplugin.dao;

import coreplugin.db.QueueEntry;

import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: Dennis
 * Date: 03.01.12
 * Time: 18:50
 * To change this template use File | Settings | File Templates.
 */
interface QueueDao {
    Object createQueueEntry(QueueEntry queueEntry);
    Object deleteQueueEntry(QueueEntry queueEntry);
    Object updateQueueEntry(QueueEntry queueEntry);

    List getAllQueueEntry();
    Object findQueueEntry(int identifier);
    Object getFirstQueueEntry();
}
EclipselinkQueueDaoImpl
Java:
package coreplugin.dao;

import coreplugin.db.QueueEntity;
import coreplugin.db.QueueEntry;
import coreplugin.util.EclipseUtil;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: Dennis
 * Date: 03.01.12
 * Time: 18:53
 * To change this template use File | Settings | File Templates.
 */
@SuppressWarnings("HardCodedStringLiteral")
public class EclipselinkQueueDaoImpl implements QueueDao {

    private final EntityManager entityManager = EclipseUtil.getEntityManager();

    @Override
    public QueueEntry createQueueEntry(QueueEntry queueEntry) {
        entityManager.persist(queueEntry);
        return queueEntry;
    }

    @Override
    public QueueEntry deleteQueueEntry(QueueEntry queueEntry) {
        entityManager.remove(queueEntry);
        return queueEntry;
    }

    @Override
    public QueueEntry updateQueueEntry(QueueEntry queueEntry) {
        entityManager.merge(queueEntry);
        return queueEntry;
    }

    @Override
    public List getAllQueueEntry() {
        return entityManager.createQuery("Select q from QueueEntity q", QueueEntity.class).getResultList();
    }

    @Override
    public QueueEntry findQueueEntry(int identifier) {
        Query query = entityManager.createQuery("select q from QueueEntity q where q.identity in :identifier");
        query.setParameter("identifier", identifier);
        return (QueueEntry) query.getSingleResult();
    }

    @Override
    public QueueEntry getFirstQueueEntry() {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }
}

QueueModel
Java:
package coreplugin.db;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: Dennis
 * Date: 03.01.12
 * Time: 18:08
 * To change this template use File | Settings | File Templates.
 */
public class QueueModel {

    private final List<QueueEntry> queueEntryList = new ArrayList<QueueEntry>();
    protected final transient PropertyChangeSupport listeners = new PropertyChangeSupport(this);


    /**
     * Adds a property-change listener.
     *
     * @param l the listener
     */
    public void addPropertyChangeListener(PropertyChangeListener l) {
        if (l == null) {
            throw new IllegalArgumentException();
        }
        this.listeners.addPropertyChangeListener(l);
    }


    public void removePropertyChangeListener(PropertyChangeListener l) {
        this.listeners.removePropertyChangeListener(l);
    }

    /**
     * Notificates all listeners to a model-change
     *
     * @param prop     the property-id
     * @param old      the old-value
     * @param newValue the new value
     */
    protected void firePropertyChange(String prop, Object old, Object newValue) {
        if (this.listeners.hasListeners(prop)) {
            this.listeners.firePropertyChange(prop, old, newValue);
        }
    }

    public void addQueueEntry(QueueEntry queueEntry)
    {
        queueEntryList.add(queueEntry);
        firePropertyChange("queueEntryAdded", null, queueEntry);
    }

    public List<QueueEntry> getQueueList() {
        return new ArrayList<QueueEntry>(queueEntryList);
    }
}

QueueViewPanel
Java:
package coreplugin.view;

import coreplugin.controller.QueueController;
import coreplugin.dao.EclipselinkQueueDaoImpl;
import coreplugin.db.QueueEntry;
import coreplugin.db.QueueTableModel;
import org.chaosfisch.mvc.view.AbstractViewPanel;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.beans.PropertyChangeEvent;
import java.util.List;

public final class QueueViewPanel extends AbstractViewPanel {
    private final QueueController controller;
    private JPanel queuePanel;
    public JTable queueTable;
    private JButton startenButton;
    private JButton stoppenButton;
    private JButton arrowTop;
    private JButton arrowUp;
    private JButton arrowDown;
    private JButton arrowBottom;
    private JComboBox queueFinishedList;
    private JButton editButton;
    private JButton deleteButton;
    private JComboBox queueViewList;
    private JTextField titleTextField;
    private JTextField fileTextField;
    private JTextField starttimeTextField;
    private JTextField statusTextField;
    private JButton abortButton;
    private JTextField uploadedBytesTextField;
    private JTextField etaTextField;
    private JProgressBar progressbar;

    private final QueueTableModel queueTableModel;

    public QueueViewPanel(QueueController controller) {
        this.controller = controller;

        controller.getQueueList().addPropertyChangeListener(this);
        List<QueueEntry> list = controller.getQueueList().getQueueList();
        queueTableModel = new QueueTableModel(list);
        queueTable.setModel(queueTableModel);

        //Hier eine Factory noch einsetzen.
        EclipselinkQueueDaoImpl elipselinkQueueDao = new EclipselinkQueueDaoImpl();
        queueTableModel.addQueueEntryList(elipselinkQueueDao.getAllQueueEntry());
        initComponents();
        initListeners();
    }

    private void initComponents() {
        queueTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    }

    private void initListeners() {
        //Start, Stop, End Listeners
        startenButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                controller.startQueue();
            }
        });

        stoppenButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                controller.stopQueue();
            }
        });

        abortButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                controller.abortUpload();
            }
        });


        queueFinishedList.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                controller.changeQueueFinished(e.getItem());
            }
        });

        //ADD Arrow Listeners
        arrowTop.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                controller.moveTop(queueTable.getSelectedRow());
            }
        });
        arrowUp.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                controller.moveUp(queueTable.getSelectedRow());
            }
        });
        arrowDown.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                controller.moveDown(queueTable.getSelectedRow());
            }
        });
        arrowBottom.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                controller.moveBottom(queueTable.getSelectedRow());
            }
        });

        //Edit, Delete, View Buttons
        editButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int selectedRow = queueTable.getSelectedRow();
                if (queueTableModel.hasQueueEntryAt(selectedRow)) {
                    controller.editEntry(queueTableModel.getQueueEntryAt(selectedRow));
                }
            }
        });

        deleteButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int selectedRow = queueTable.getSelectedRow();
                if (queueTableModel.hasQueueEntryAt(selectedRow)) {
                    controller.deleteEntry(queueTableModel.getQueueEntryAt(selectedRow));
                    queueTableModel.removeQueueEntryAt(selectedRow);
                    queueTable.changeSelection(selectedRow-1, 0, false, false);
                }
            }
        });

        queueViewList.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                controller.changeQueueView(e.getItem());
            }
        });
    }

    public JPanel getQueuePanel() {
        return queuePanel;
    }

    @SuppressWarnings("CallToStringEquals")
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if (evt.getPropertyName().equals(QueueController.ETA_PROPERTY)) {
            etaTextField.setText(evt.getNewValue().toString());
        } else if (evt.getPropertyName().equals(QueueController.FILE_PROPERTY)) {
            fileTextField.setText(evt.getNewValue().toString());
        } else if (evt.getPropertyName().equals(QueueController.PROGRESS_PROPERTY)) {
            progressbar.setValue(Integer.parseInt(evt.getNewValue().toString()));
        } else if (evt.getPropertyName().equals(QueueController.STARTTIME_PROPERTY)) {
            starttimeTextField.setText(evt.getNewValue().toString());
        } else if (evt.getPropertyName().equals(QueueController.STATUS_PROPERTY)) {
            statusTextField.setText(evt.getNewValue().toString());
        } else if (evt.getPropertyName().equals(QueueController.TITLE_PROPERTY)) {
            titleTextField.setText(evt.getNewValue().toString());
        } else if (evt.getPropertyName().equals(QueueController.UPLOADED_BYTES_PROPERTY)) {
            uploadedBytesTextField.setText(evt.getNewValue().toString());
        }
    }
}

QueueController
Java:
package coreplugin.controller;

import coreplugin.db.QueueEntry;
import coreplugin.db.QueueModel;
import org.chaosfisch.mvc.controller.AbstractController;

public class QueueController extends AbstractController {

    public static final String STATUS_PROPERTY = "Status"; //NON-NLS
    public static final String TITLE_PROPERTY = "Title"; //NON-NLS
    public static final String FILE_PROPERTY = "File"; //NON-NLS
    public static final String STARTTIME_PROPERTY = "Starttime"; //NON-NLS
    public static final String UPLOADED_BYTES_PROPERTY = "Uploaded Bytes"; //NON-NLS
    public static final String ETA_PROPERTY = "ETA"; //NON-NLS
    public static final String PROGRESS_PROPERTY = "Progress"; //NON-NLS

    private static final QueueModel queueList = new QueueModel();


    public void startQueue() {
    }

    public void stopQueue() {
    }

    public void abortUpload() {
    }

    public void changeQueueFinished(Object item) {
    }

    public void moveTop(int selectedRow) {
    }

    public void moveUp(int selectedRow) {
    }

    public void moveDown(int selectedRow) {
    }

    public void moveBottom(int selectedRow) {
    }

    public void changeQueueView(Object item) {
    }

    public void deleteEntry(QueueEntry queueEntityAt) {
    }

    public void editEntry(QueueEntry queueEntityAt) {

    }

    public QueueModel getQueueList() {
        return queueList;
    }
}

So kurz zusammenfassend noch dazu:
Es muss noch die Service-Schicht ausgebaut werden. Es kommt eine Klasse QueueServiceImpl mit Interface QueueService hinzu. Dieser "Service" führt Operationen über das DAO aus, wodurch mit der Datenbank kommuniziert wird.
Einige PropertyChangeEvents wie queueEntryAdded müssen noch verarbeitet werden.

Nach diesem Aufbau passiert doch eigentlich folgendes:
User macht eine Eingabe über das View. Dieses mappt auf den Controller. Der Controller führt Aktionen aus und kann (muss aber nicht) einen Datenbankzugriff einfordern. Dies geschieht über 2 Sachen:
1. Dem Service-Layer: Hier findet der direkte Zugriff über ein DAO auf die Datenbank statt. Hier werden keine PropertyChangeEvents gefeuert
2. Einem Model: Ihm wird das selbe Objekt übergeben. Das Model feuert anschließend ein PropertyChangeEvent, sodass sich das View updaten kann.

Ich seh grad, ich hab da vermutlich noch ein Fehler in der Umsetzung. Wenn ich es richtig sehe, dann kann ich die Klasse QueueTableModel und QueueModel mergen. Der Fehler kam wohl durch die Übernahme "deiner" Struktur.

Jetzt halt nur nochmal die Frage, passt das so, oder sollte ich noch was ändern?

Gruß
CHAOSFISCH
 
So, hab jetzt mein QueueTableModel und mein QueueModel gemerged. Sollte das selbe darstellen.
Jetzt noch eine Frage:

Der Aufbau ist ja: View, Controller -> Service -> DAO
Warum benutzt man einen Service-Layer, in deinem KSKB macht der Service das selbe wie das DAO. Es gibt somit viel Coderedundanz. Gibt es also Gründe einen Service-Layer noch dazwischen zu setzen?

Edit: Achso, das man evtl sagt: Das DAO beinhaltet nur einfache Vorgänge wie: updaten, hinzufügen, entfernen, finden und alle zurückgeben.
Der Service hingegen kann mehrere DAO Funktionalitäten bündeln und viele weitere Aktionen durchführen!?

Gruß
CHAOSFISCH
 
Zuletzt bearbeitet:
Ich geb mal wieder mein Senf dazu 😉
1. Dein Interface von oben ist total unschön ein Interface sollte keine Variablen beinhalten, sondern nur Methoden vorgegeben nehm die raus und schreib diese in deine xxxxImpl rein.
2. Ich würde dir raten die JPA Annotationen dann an die Member Variable zu machen, da dass übersichtlicher ist.
3. Für CRUD Funktonalitäten brauchst du nicht unbedingt ein DAO, da der EntityManager typsicher ist und quasi dein DAO darstellt.
4. Du brauchst eine Service Schicht für das Transaktionshandling. In deinem Service Layer liegt deine Business Logik mit Fehlerbehandlung usw. Da musst du dir Gedanken machen was passiert bei Fehler xyz. Wie geht es weiter mit der Transaktion und vor allem muss dur dir Gedanken über die JPA Sachen machen bezüglich attach und dettach Objekten!!!
5. Würde ich keinen PropertyChange Support mehr verwenden. Der hat ein paar unschöne Nebeneffekte. z.B. kannst du einen GLEICHEN(!!!) Listener mehrmals deinem Model adden, aber beim remove wird er nur 1 mal entfernt.
Schau dir mal den EventBus an, finde persönlich sehr gelungen und einfach zu verstehen.


btw. Hast du eine Server/Client Anwendung??
 
Ich geb mal wieder mein Senf dazu 😉
1. Dein Interface von oben ist total unschön ein Interface sollte keine Variablen beinhalten, sondern nur Methoden vorgegeben nehm die raus und schreib diese in deine xxxxImpl rein.
2. Ich würde dir raten die JPA Annotationen dann an die Member Variable zu machen, da dass übersichtlicher ist.
Ah ok, werd ich machen.

4. Du brauchst eine Service Schicht für das Transaktionshandling. In deinem Service Layer liegt deine Business Logik mit Fehlerbehandlung usw. Da musst du dir Gedanken machen was passiert bei Fehler xyz. Wie geht es weiter mit der Transaktion und vor allem muss dur dir Gedanken über die JPA Sachen machen bezüglich attach und dettach Objekten!!!
So ungefähr hab ich mir das Gedacht vorhin. War mir aber nicht sicher.
5. Würde ich keinen PropertyChange Support mehr verwenden. Der hat ein paar unschöne Nebeneffekte. z.B. kannst du einen GLEICHEN(!!!) Listener mehrmals deinem Model adden, aber beim remove wird er nur 1 mal entfernt.
Schau dir mal den EventBus an, finde persönlich sehr gelungen und einfach zu verstehen.
Auf EventBus bin ich bereits gestoßen als ich nach Best Practices gesucht hatte. PropertyC. oder Oberserver. "Den Eventbus" entnehm ich doch aus dem Repositorie von Eventbus: Subversion &mdash; Java.net. Da brauch ich die ganz normale Eventbus.jar R 60?
btw. Hast du eine Server/Client Anwendung??
Hab eine Client Anwendung
 
Ah ok, werd ich machen.


So ungefähr hab ich mir das Gedacht vorhin. War mir aber nicht sicher.

Auf EventBus bin ich bereits gestoßen als ich nach Best Practices gesucht hatte. PropertyC. oder Oberserver. "Den Eventbus" entnehm ich doch aus dem Repositorie von Eventbus: Subversion &mdash; Java.net. Da brauch ich die ganz normale Eventbus.jar R 60?

Hab eine Client Anwendung

Standalone client Anwendung? Falls ja
Wie gesagt ich denke du brauchst dann nicht extra eine DAO-Schicht, diese stellt dein EntityManager dar.
Ich würde sogar sagen dass du deinen AbstractController genauso wenig brauchst, wenn du einen Service Layer einbaust. Der AbstractController manchmal auch ServiceLocator genannt war dafür gesagt remote Services aufzurfen, aber wenn du keine hast, könntest die auch rein theoretisch weglassen.

Ich hab den EventBus noch nie selber eingebaut, der war in meinem Projekten schon immer im repo vorhanden.

Aber sonst sieht dein Aufbau soweit okay aus.
Ich würde dir noch Google Guice als DI Framework ans Herz legen, da es für deinen Fall leicht gewichtiger als Spring ist. Ist eigentlich ziemlich einfach zu verstehen und dann ist deine Anwendung wirklich sauber aufgebaut.
 
Standalone client Anwendung? Falls ja
Wie gesagt ich denke du brauchst dann nicht extra eine DAO-Schicht, diese stellt dein EntityManager dar.
Ich würde sogar sagen dass du deinen AbstractController genauso wenig brauchst, wenn du einen Service Layer einbaust. Der AbstractController manchmal auch ServiceLocator genannt war dafür gesagt remote Services aufzurfen, aber wenn du keine hast, könntest die auch rein theoretisch weglassen.

Ich hab den EventBus noch nie selber eingebaut, der war in meinem Projekten schon immer im repo vorhanden.

Aber sonst sieht dein Aufbau soweit okay aus.
Ich würde dir noch Google Guice als DI Framework ans Herz legen, da es für deinen Fall leicht gewichtiger als Spring ist. Ist eigentlich ziemlich einfach zu verstehen und dann ist deine Anwendung wirklich sauber aufgebaut.
Jo standalone client Anwendung.
Der AbstractController war nur von vorher noch drinnen, aber komplett leer.
Ich werde mir das DI Framework dann noch anschauen. Sieht erstmal mächtig kompliziert aus.
Was ich soweit verstanden habe: DI macht die Anwendungsteile unabhängiger. Unit Tests werden dadurch einfacher.
Aus:
Java:
public class QueueServiceImpl implements QueueService {

    private final EntityManager entityManager = EclipseUtil.getEntityManager();
}
Muss dann sowas werden:
Java:
public class QueueServiceImpl implements QueueService{
private final EntityManager entityManager;
public QueueServiceImpl(EntitityManager em)
{
entityManager = em;
}

Wie das dann alles mit den Annotations funktioniert etc. muss ich noch genau durchlesen.
 
Jo standalone client Anwendung.
Der AbstractController war nur von vorher noch drinnen, aber komplett leer.
Ich werde mir das DI Framework dann noch anschauen. Sieht erstmal mächtig kompliziert aus.
Was ich soweit verstanden habe: DI macht die Anwendungsteile unabhängiger. Unit Tests werden dadurch einfacher.
Aus:

Wie das dann alles mit den Annotations funktioniert etc. muss ich noch genau durchlesen.

ja fehlt ja nur eine Annotation @Inject

Genau es wird alles loser gekoppelt und bei JUnit Test kannst du einfacher deine Sachen mocken. So kannst du MockService Schreiben die nicht auf die DB zugreifen usw.

Außerdem musst du dich nicht mehr um Singeltons kümmern, weil du keine mehr hast.
 

Danke, schau ich mir an sobald ich durch die Guice Wiki durch bin.
Ich hab nun auch EventBus statt PropertyChange drinnen.
Eine Frage hätte ich da aber noch:
Controller Methode, wird vom View aufgerufen:
Java:
public void startQueue() {
     EventBus.publish(Constants.UPLOAD_JOB, Constants.START_QUEUE);
}
In irgendeiner anderen Klasse befindet sich dann der Subscriber. Im Subscriber würde dann z.B. ein SwingWorker aufgerufen. Darf man das so, oder sollte man den Service im Controller direkt aufrufen?
 
In irgendeiner anderen Klasse befindet sich dann der Subscriber. Im Subscriber würde dann z.B. ein SwingWorker aufgerufen. Darf man das so, oder sollte man den Service im Controller direkt aufrufen?

Vesteh ich nicht... Wenn du etwas direkt aufrufen kannst, warum solltest du es nicht direkt aufrufen?
Der EventBus oder ein Notification ist dafür da auf etwas zu reagieren, wenn sich etwas ändert oder ausgelöst wird.
 

Neue Themen


Zurück
Oben