Beispiel Gruppenphase

Werbung
Beispiel Gruppenphase
Table of contents
1
Erklärung der eingesetzten Techniken...............................................................................2
1.1
Architektur des Beispieles.............................................................................................2
1.2
Spring Framework......................................................................................................... 3
1.3
JUnit.............................................................................................................................. 8
1.4
Log4J............................................................................................................................. 9
1.5
dom4j...........................................................................................................................10
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Beispiel Gruppenphase
1. Erklärung der eingesetzten Techniken
Hier werden die eingesetzten Techniken des SE Mittel vorgestellt und anhand von Beispielen
näher erörtert.
1.1. Architektur des Beispieles
Java Packages erlauben die Struktierung von Java Klassen. Das Beispiel ist in folgende
Packages aufgeteilt.
1.1.1. Package Beschreibung
Package
Beschreibung
at.ac.tuwien.ifs.qse.se1.basis
Das Packet enthält Startklassen um das Swing
UI und alle anderen Klassen in den
Subpackages zu starten. Es startet und
konfiguriert Log4j anhand der Log Properties
und öffnet die HauptGUI.
at.ac.tuwien.ifs.qse.se1.basis.dao
Das Data Access Object Package enthält alle
Methoden um auf die Datenbank (über die
Persistenz Klassen) zuzugreifen.
at.ac.tuwien.ifs.qse.se1.basis.export_import
Enthält die Klasse für den Import und Export zu
XML Dateien (verwendet dom4j) und Klassen für
den Export zu HTML.
at.ac.tuwien.ifs.qse.se1.basis.gui
Enthält die Klassen um das Swing User
Interface anzuzeigen. Dieses besteht aus dem
Hauptfenster (benutzt StudentTableModel und
ExportComboModel, den EditStudentFrame und
den MessageDialog)
at.ac.tuwien.ifs.qse.se1.basis.helper Dieses Packet enthält eine Klasse für
systemweite Methoden und eine für systemweite
Konstanten.
at.ac.tuwien.ifs.qse.se1.basis.model Dieses Packet enthält Datenobjekte die durch
Java Beans gekapselt werden.
at.ac.tuwien.ifs.qse.se1.basis.test
Dieses Packet enthält eine Klassen die alle Unit
Tests ausführt (verwendet JUnit).
at.ac.tuwien.ifs.qse.se1.basis.test.dao
Dieses Packet enthält die Unit Tests für das
DAO Packet.
Page 2
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Beispiel Gruppenphase
at.ac.tuwien.ifs.qse.se1.basis.test.export
Dieses Packet enthält die Unit Tests für das
export_import Packet.
1.1.2. Wichtige Dateien
beans.xml
In dieser XML Datei werden die Klassen und
Eigenschaften jedes Beans definiert.
1.2. Spring Framework
Spring Framework erleichtert die Arbeit wesentlich, Rod Johnson argumentiert:
• It addresses important areas that many other popular frameworks don't. Spring focuses
around providing a way to manage your business objects.
• Spring is both comprehensive and modular. Spring has a layered architecture, meaning
that you can choose to use just about any part of it in isolation, yet its architecture is
internally consistent. So you get maximum value from your learning curve. You might
choose to use Spring only to simplify use of JDBC, for example, or you might choose to
use Spring to manage all your business objects. And it's easy to introduce Spring
incrementally into existing projects.
• Spring is designed from the ground up to help you write code that's easy to test. Spring is
an ideal framework for test driven projects.
• Spring is an increasingly important integration technology, its role recognized by several
large vendors.
Im SE Beispiel wurde Spring Framework folgend eingesetzt:
1.2.1. beans.xml
In dieser XML Datei werden die Klassen und Eigenschaften jedes Beans definiert. In
folgenden Beispiel wird das StundentDAO Bean konfiguriert. Wie man sieht besteht
zwischen dem Bean und anderen Klassen (transactionManager, ...) Abhängigkeiten. Diese
werden mit dem "ref" Attribut deklariert, welches die Abhängikeiten zwischen den Klassen
zeigt. Wie man sieht können auch SQL Statements hier angeführt werden.
<!-- This Transaction Manager is needed for SQL Transactions: it uses a SQL
Datasource (see above) -->
<bean id="TransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="HsqldbDataSource"/>
</bean>
<!-****************************************************************************************
Page 3
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Beispiel Gruppenphase
-->
<!-- Configuration of Data Access Objects and injection of session and
transaction manager
-->
<!-****************************************************************************************
-->
<!-- Complete Bean Lifecycle Management here: including initialisation and
destroying -->
<bean
id="StudentDAO"
class="at.ac.tuwien.ifs.qse.se1.basis.dao.JdbcObjectStudentDAO"
singleton="true"
init-method="init"
destroy-method="destroy"
>
<!-- This is the datasource needed for JDBC Database Access -->
<property name="dataSource" ref="HsqldbDataSource"/>
<!-- This is the transaction manager needed for SQL Transactions
-->
<property name="transactionManager" ref="TransactionManager" />
<!-- The next properties are SQL Commands used in this DAO -->
<property name="sql_getAllStudents">
<value>select id, matnr, vorname, nachname, email from
studenten</value>
</property>
<property name="sql_getStudent">
<value>select id, matnr, vorname, nachname, email from
studenten where id=?</value>
</property>
<property name="sql_insertStudent">
<value>INSERT INTO studenten (matnr, vorname, nachname,
email) values (?, ?, ?, ?)</value>
</property>
<property name="sql_updateStudent">
<value>UPDATE studenten SET matnr=?, vorname=?, nachname=?,
email=? WHERE id=?</value>
</property>
<property name="sql_deleteStudent">
<value>DELETE FROM studenten WHERE id=?</value>
</property>
<property name="sql_getInsertId">
<value>CALL IDENTITY()</value>
</property>
</bean>
Nun definiert man die DAO, welche eine Bean Referenz zu den DataSource haben. Diese
werden mit dem "ref" Attribut deklariert, welches die Abhängikeiten zwischen den Klassen
zeigt. Danach folgenden die einzelen SQL Statements welche in den DAOs verwendet
werden.
<bean
Page 4
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Beispiel Gruppenphase
id="StudentDAO"
class="at.ac.tuwien.ifs.qse.se1.basis.dao.JdbcObjectStudentDAO"
singleton="true"
init-method="init"
destroy-method="destroy"
>
<!-- This is the datasource needed for JDBC Database Access -->
<property name="dataSource" ref="HsqldbDataSource"/>
<!-- This is the transaction manager needed for SQL Transactions
-->
<property name="transactionManager" ref="TransactionManager" />
<!-- The next properties are SQL Commands used in this DAO -->
<property name="sql_getAllStudents">
<value>select id, matnr, vorname, nachname, email from
studenten</value>
</property>
....
1.2.2. StudentDAO
Das StudentDAO Inteface legt die zu implementierenden Methoden fest.
public interface StudentDAO {
public Student getStudent (Long id);
public Long addStudent (Student student);
public Long updateStudent (Long id, Student student);
public Long deleteStudent (Long id);
public List<Student> getStudents(String order);}
Die JDdbcObjectStudentDAO Klasse implmentiert das vorher entworfene Interface.
Zu beachten ist der nun implementierte Transaction Manager "transactionManager" und
"dataSource".
In dem Beispiel wird als Inversion-of-Control (IoC) Technik Dependency Injection und nicht
Dependency Lookup verwendet. Bei Dependency Injection wird die Implementierungsklasse
über die JavaBean setter()-Methoden in die Komponenten injiziert. Weiters ist auch das
Handling der der init Methode zu beachten (siehe unten).
public class JdbcObjectStudentDAO implements StudentDAO {
...
// Logger
private static Log log =
LogFactory.getLog(JdbcObjectStudentDAO.class);
// SQL Datasource and Transaction Manager
private DataSource dataSource = null;
private PlatformTransactionManager transactionManager = null;
// SQL Query Strings
private String sql_getStudent = "";
// Query Objects
Page 5
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Beispiel Gruppenphase
private Query_GetStudent query_getStudent;
...
/************************************************************************************/
/************************************************************************************/
/*
C O N S T R U C T O R
*/
/************************************************************************************/
/************************************************************************************/
public JdbcObjectStudentDAO() {
super();
}
/**
* Initialise Method. Must be called after all bean values are set:
particularly the
* datasource and the transaction manager.
* This is actually performed by the Spring Framework, which sets
first of all, all
* Java Bean Properties and eventually calls this init method (see
bean definition
* in beans.xml configuration file)
*/
public void init() {
log.info("Initialise StudentDAO");
query_getStudent = new Query_GetStudent(dataSource);;
query_insertStudent = new Query_InsertStudent(dataSource);
query_getStudentId = new Query_GetStudentID(dataSource);
query_updateStudent = new Query_UpdateStudent(dataSource);
query_deleteStudent = new Query_DeleteStudent(dataSource);
query_getAllStudentsOrderMatnr = new
Query_GetAllStudentsOrderMatnr(dataSource);
query_getAllStudentsOrderNachname = new
Query_GetAllStudentsOrderNachname(dataSource);
}
/**
* Destroy Method.
* This method is called by the Spring Framework to end the
lifecycle of this bean,
* but only when the bean is created as singletong.
* Check the bean definition in beans.xml configuration file for
details.
*/
public void destroy() {
log.info("Destroy StudentDAO");
}
/************************************************************************************/
/************************************************************************************/
/*
BEAN SETTERS FOR DEPENDENCY INJECTION
*/
/************************************************************************************/
/************************************************************************************/
Page 6
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Beispiel Gruppenphase
/***
* Set SQL String to get all students
* @param sql_getAllStudents SQL Statement as String
*/
public void setSql_getAllStudents(String sql_getAllStudents) {
this.sql_getAllStudents = sql_getAllStudents;
}
/***
* Set SQL String to get one student with one SQL parameter
* @param sql_getStudent SQL Statement as String
*/
public void setSql_getStudent(String sql_getStudent) {
this.sql_getStudent = sql_getStudent;
}
/**
* Set SQL String to insert one student to database
* @param sql_insertStudent SQL Statement as String
*/
public void setSql_insertStudent(String sql_insertStudent) {
this.sql_insertStudent = sql_insertStudent;
}
/**
* Set SQL String to retrieve the ID of the last executed SQL
Statement
* @param sql_getInsertId SQL Statement as String
*/
public void setSql_getInsertId(String sql_getInsertId) {
this.sql_getInsertId = sql_getInsertId;
}
/**
* Set SQL String to update a student.
* @param sql_updateStudent SQL Statement as String
*/
public void setSql_updateStudent(String sql_updateStudent) {
this.sql_updateStudent = sql_updateStudent;
}
/**
* Set SQL String to delete a student.
* @param sql_deleteStudent SQL Statement as String
*/
public void setSql_deleteStudent(String sql_deleteStudent) {
this.sql_deleteStudent = sql_deleteStudent;
}
/**
* Set Datasource to connect to database
* @param dataSource SQL Datasource
*/
Page 7
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Beispiel Gruppenphase
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
/**
* Set a transaction manager for encapsulating insert and updates
in transaction
* @param transactionManager java Transaction Manager
*/
public void setTransactionManager (PlatformTransactionManager
transactionManager) {
this.transactionManager = transactionManager;
}
}
1.3. JUnit
Die Klasse AllTests (package ...basis.test) baut eine JUnit Test Suite auf, welche alle Test
Suite Klassen beinhaltet. In eine Suite werden neue TestSuite mit der Methode
addTestSuite(..) hinzugefügt. AllTest liefert eine TestSuite als return value. Sie kann bequem
über Eclipse gestartet werden.
public class AllTests {
// get logger for this root package
private static Log log =
LogFactory.getLog("at.ac.tuwien.ifs.qse.se1.basis");
/**
* Creates an new TestSuite containing all Tests in the
sub-packages.
* If you want your own TestClasses executed you have to add them
here to the
* TestSuit to have them executed in a testrun of jUnit.
*
* @return an initialized TestSuite
*/
public static Test suite() {
// configure log4j based on log.properties
Helper.configureLog4j();
log.info("Starting Unit-Tests");
TestSuite suite = new TestSuite("Test for
at.ac.tuwien.ifs.qse.se1.basis.test");
//$JUnit-BEGIN$
suite.addTestSuite(JdbcStudentTest.class);
suite.addTestSuite(XmlExportImportTest.class);
suite.addTestSuite(ExportImportTest.class);
suite.addTestSuite(HtmlExportTest.class);
//$JUnit-END$
return suite;
}
Page 8
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Beispiel Gruppenphase
}
Eine Test Suite besteht prinzipell aus folgenden Grundgerüst: Die setUp() Methode welche
vor jedem Testfall durchgeführt wird und die tearDown() Methode die nach dem Testfall
durchgeführt wird.
Nun wird für jede Methode zumindest ein Testfall geschrieben. In unseren Beispiel testet die
Methode testGetStudent die getStudent Methode. Nach dem Aufruf von getStundent(...) wird
überprüft ob der Rückgabewert korrekt ist.
public class JdbcStudentTest extends TestCase {
..
protected void setUp() throws Exception {
super.setUp();
...
}
protected void tearDown() throws Exception {
super.tearDown();
...
}
/**
* Test the method getStudent
*
* @see StudentDAO#getStudent(Long)
*
*/
public void testGetStudent() {
Student student = studentDAO.getStudent(new Long(0));
assertNotNull(student);
assertEquals("Alexander", student.getVorname());
assertEquals("Schatten", student.getNachname());
}
...
}
1.4. Log4J
Mit dem Packages Jakarta Commons Logging und Log4j von Apache ist es sehr einfach log
Statements auszugeben ohne dabei größere Geschwindigkeitseinbußen hinnehmen zu
müssen. Das konfigurieren mittels einer Konfigurationsdatei ermöglicht es, das
log-Verhalten zu manipulieren ohne den Sourcecode verändern zu müssen.
Page 9
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Beispiel Gruppenphase
Ich zeige hier am Beispiel der Basis Klasse aus SE_Medium die Anwendung dieser
Packages:
Mit dem Befehl
private static Log log =
LogFactory.getLog("at.ac.tuwien.ifs.qse.se1.basis");
erzeugen wir eine Variable namens log und holen uns von der LogFactory mit
.getLog(Klasse)eine Instanz für unsere Basisklasse.
Bevor wir den logger verwenden, muss er konfiguriert werden. Für die Konfiguration
existiert eine eigene Hilfsmethode namens Helper.configureLog4j(). Diese liest, nachdem er
geprüft hat ob die Datei überhaupt existiert, die Daten aus einem Log4j Properties File und
ruft dann die Methode
org.apache.log4j.PropertyConfigurator.configure(Properties_File);
auf.
Nach der erfolgreichen Konfiguration kann man mit dem einfachen Befehl
log.info(String);
einen String als info Message an den logger weitergeben, der ihn dann in der Konsole
ausgibt.
Weitere Message-Levels sind:
• fatal
• error
• warn
• debug
• trace
Für nähere Informationen folgen Sie bitte den links unter Referenz.
1.5. dom4j
Was ist dom4j eigentlich?
dom4j ist ein Open Source XML framework für Java, das es ermöglicht XML Dokumente zu
lesen, schreiben, erstellen und zu navigieren. Es ist dabei eine einfache, klein gehaltene API,
die häufigen Gebrauch von Standard Java APIs zB. Java 2 collections macht.
dom4j wird im SE Beispiel nur in der Klasse XMLExportImport verwendet:
Import:
Page 10
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Beispiel Gruppenphase
Ein XML File einzulesen ist recht einfach. Die Methode read(filename) ruft die Methode
readXML(filename) auf, erzeugt uns mit dem folgenden Code einen SAXReader und liest
damit die Datei filename in ein dom4j Documentein.
SAXReader xmlReader = new SAXReader();
Document doc = xmlReader.read(filename);
Anschließend werden mit
List|Student| studenten = new ArrayList|Student|();
eine neue ArrayList von Studenten erzeugt,
List studentenEl = doc.getRootElement().elements();
aus dem Document die vorhandenen Elemente des RootElementsin eine Liste studentenEl
gespeichert und mit
Iterator it = studentenEl.iterator();
ein Iterator erzeugt, über den in der folgenden Schleife über alle vorhandenen Elemente (in
unserem Fall ja Studenten) iteriert wird.
In der Schleife wird ein neuer Student angelegt, mit den Daten des Elements befüllt und zur
ArrayList studenten hinzugefügt
Nach dem das für alle Elemente gemacht wurde, wird die Schleife beendet und die nun volle
Liste von Studenten zurückgegeben.
Anmerkung: Der Import wird in SE_Medium (noch) nicht verwendet. Es sollte jedoch kein
Problem sein, mit dieser Vorlage eine Import Funktion in der eigenen Anwendung zu
realisieren
Export:
Der Export besteht aus zwei Teilen; zuerst wird eine XML Datei erzeugt und mit den Daten
befüllt, dann wird sie abgespeichert.
In der Methode generateXML wird am Anfang ein leeres Document mit
Document doc = documentFactory.createDocument();
erzeugt. Dem gleich noch ein Element student mit
doc.addElement("students");
angehängt wird.
Dann wird in einer Schleife die Studenten Liste durchgegangen und für jedes Element der
Liste (also für jeden Studenten) ein rootElement Student mit den Daten des Studenten als
Unterelemente und der id als Attribut dem Document hinzugefügt. Schon haben wir ein fertig
befülltes Document! Dieses wird jetzt in der Methode save(filename) als XML-Datei
abgespeichert.
Page 11
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Beispiel Gruppenphase
Und das geht so:
Erzeuge einen FileOutputStream,
FileOutputStream fos = new FileOutputStream(filename);
wähle das Format (in unserem Fall PrettyPrint) und stelle die Codierung ein,
OutputFormat outForm = OutputFormat.createPrettyPrint();
outForm.setEncoding(encoding);
erzeuge einen XMLWriter und gib ihm den Stream und das Format mit,
XMLWriter xwriter = new XMLWriter(fos, outForm);
und schreibe das ganze mit
xwriter.write(doc);
Schon haben wir eine schön formatierte XML Datei mit allen unseren Studenten
Page 12
Copyright © 2006 Institut fuer Softwaretechnik und interaktive Systeme All rights reserved.
Herunterladen