From 1436f602ca9ab302042793ecec5d07b4649ababe Mon Sep 17 00:00:00 2001
From: Martin Goik <goik@hdm-stuttgart.de>
Date: Wed, 7 Jan 2015 17:29:54 +0100
Subject: [PATCH] New SAX/JDBC Exercise

---
 Sda1/P/catalog2rdbms/.gitignore               |   5 +
 Sda1/P/catalog2rdbms/Schema/catalog.xsd       |  23 ++++
 Sda1/P/catalog2rdbms/Schema/schema.sql        |  27 ++++
 Sda1/P/catalog2rdbms/pom.xml                  | 104 +++++++++++++++
 Sda1/P/catalog2rdbms/products.xml             |  17 +++
 .../mi/sda1/catalog2sql/DataInsert.java       |  84 ++++++++++++
 .../mi/sda1/catalog2sql/Helper.java           |   9 ++
 .../mi/sda1/catalog2sql/Xml2Rdbms.java        |  90 +++++++++++++
 .../handler/CatalogContentHandler.java        | 126 ++++++++++++++++++
 .../src/main/resources/log4j2.xml             |  21 +++
 Sda1/sda1.xml                                 |  22 +++
 .../mi/sda2/jpa/cd/domain/Student.java        |  18 +++
 .../mi/sda2/jpa/university/Driver.java        |  39 +++++-
 .../main/resources/META-INF/persistence.xml   |   6 +-
 .../University/src/main/resources/log4j2.xml  |   2 +-
 15 files changed, 585 insertions(+), 8 deletions(-)
 create mode 100644 Sda1/P/catalog2rdbms/.gitignore
 create mode 100644 Sda1/P/catalog2rdbms/Schema/catalog.xsd
 create mode 100644 Sda1/P/catalog2rdbms/Schema/schema.sql
 create mode 100644 Sda1/P/catalog2rdbms/pom.xml
 create mode 100644 Sda1/P/catalog2rdbms/products.xml
 create mode 100644 Sda1/P/catalog2rdbms/src/main/java/de/hdm_stuttgart/mi/sda1/catalog2sql/DataInsert.java
 create mode 100644 Sda1/P/catalog2rdbms/src/main/java/de/hdm_stuttgart/mi/sda1/catalog2sql/Helper.java
 create mode 100644 Sda1/P/catalog2rdbms/src/main/java/de/hdm_stuttgart/mi/sda1/catalog2sql/Xml2Rdbms.java
 create mode 100644 Sda1/P/catalog2rdbms/src/main/java/de/hdm_stuttgart/mi/sda1/catalog2sql/handler/CatalogContentHandler.java
 create mode 100644 Sda1/P/catalog2rdbms/src/main/resources/log4j2.xml

diff --git a/Sda1/P/catalog2rdbms/.gitignore b/Sda1/P/catalog2rdbms/.gitignore
new file mode 100644
index 000000000..660be2a5f
--- /dev/null
+++ b/Sda1/P/catalog2rdbms/.gitignore
@@ -0,0 +1,5 @@
+.project
+.classpath
+/.settings/
+/target/
+A1.log
\ No newline at end of file
diff --git a/Sda1/P/catalog2rdbms/Schema/catalog.xsd b/Sda1/P/catalog2rdbms/Schema/catalog.xsd
new file mode 100644
index 000000000..959f9f663
--- /dev/null
+++ b/Sda1/P/catalog2rdbms/Schema/catalog.xsd
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
+ 
+    <xs:element name="catalog">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element ref="product" minOccurs="0" maxOccurs="unbounded"/>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+    
+    <xs:element name="product">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="name" type="xs:string"/>
+                <xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+                <xs:element name="age" type="xs:int" minOccurs="0" maxOccurs="1"/>
+            </xs:sequence>
+            <xs:attribute name="id" type="xs:ID" use="required"/>
+        </xs:complexType>
+    </xs:element>
+ 
+</xs:schema>
diff --git a/Sda1/P/catalog2rdbms/Schema/schema.sql b/Sda1/P/catalog2rdbms/Schema/schema.sql
new file mode 100644
index 000000000..c526fef87
--- /dev/null
+++ b/Sda1/P/catalog2rdbms/Schema/schema.sql
@@ -0,0 +1,27 @@
+DROP TABLE IF EXISTS Description;
+DROP TABLE IF EXISTS Product;
+
+CREATE TABLE Product (
+   id CHAR(20) NOT NULL PRIMARY KEY
+  ,name VARCHAR(255) NOT NULL
+  ,age SMALLINT
+);
+
+CREATE TABLE Description (
+   product CHAR(20) NOT NULL REFERENCES Product
+  ,orderIndex int NOT NULL   -- preserving the order of descriptions belonging to a given product
+  ,text VARCHAR(255) NOT NULL
+  ,UNIQUE(product, orderIndex)
+);
+
+-- example data corresponding to products.xml --
+
+-- Product lacking age property --
+INSERT INTO Product (id, name) VALUES ('mpt', 'Monkey Picked Tea');
+INSERT INTO Description VALUES('mpt', 0, 'Picked only by specially trained monkeys');
+INSERT INTO Description VALUES('mpt', 1, 'Rare wild Chinese tea');
+
+INSERT INTO Product VALUES ('instantTent', '4-Person Instant Tent', 15);
+INSERT INTO Description VALUES('instantTent', 0, 'Exclusive WeatherTec system.');
+INSERT INTO Description VALUES('instantTent', 1, '4-person, 1-room tent');
+INSERT INTO Description VALUES('instantTent', 2, 'Pre-attached tent poles');
diff --git a/Sda1/P/catalog2rdbms/pom.xml b/Sda1/P/catalog2rdbms/pom.xml
new file mode 100644
index 000000000..4b836f2a7
--- /dev/null
+++ b/Sda1/P/catalog2rdbms/pom.xml
@@ -0,0 +1,104 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<groupId>de.hdm-stuttgart.mi.sda1</groupId>
+	<artifactId>catalog2rdbms</artifactId>
+	<version>0.8</version>
+	<packaging>jar</packaging>
+
+	<name>catalog2rdbms</name>
+
+	<!--Fixme: Add a sensible project related domain here -->
+	<url>http://somedomain.org</url>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+	</properties>
+
+	<dependencies>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>4.11</version>
+			<scope>test</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.logging.log4j</groupId>
+			<artifactId>log4j-api</artifactId>
+			<version>2.1</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.logging.log4j</groupId>
+			<artifactId>log4j-core</artifactId>
+			<version>2.1</version>
+		</dependency>
+
+		<dependency>
+			<groupId>commons-io</groupId>
+			<artifactId>commons-io</artifactId>
+			<version>2.4</version>
+		</dependency>
+
+		<dependency>
+			<groupId>de.hdm-stuttgart.mi.sda1</groupId>
+			<artifactId>saxerrorhandler</artifactId>
+			<version>0.8</version>
+		</dependency>
+
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-java</artifactId>
+			<version>5.1.34</version>
+		</dependency>
+
+	</dependencies>
+
+	<build>
+		<plugins>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>3.1</version>
+				<configuration>
+					<source>1.8</source>
+					<target>1.8</target>
+				</configuration>
+			</plugin>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-javadoc-plugin</artifactId>
+				<version>2.10.1</version>
+				<configuration />
+			</plugin>
+
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-shade-plugin</artifactId>
+				<version>2.3</version>
+				<configuration>
+					<transformers>
+						<transformer
+							implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+							<manifestEntries>
+								<Main-Class>de.hdm_stuttgart.mi.sda1.catalog2sax.App</Main-Class>
+							</manifestEntries>
+						</transformer>
+					</transformers>
+				</configuration>
+				<executions>
+					<execution>
+						<phase>package</phase>
+						<goals>
+							<goal>shade</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+
+		</plugins>
+	</build>
+</project>
diff --git a/Sda1/P/catalog2rdbms/products.xml b/Sda1/P/catalog2rdbms/products.xml
new file mode 100644
index 000000000..191ea6b4f
--- /dev/null
+++ b/Sda1/P/catalog2rdbms/products.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:noNamespaceSchemaLocation="Schema/catalog.xsd">
+   <product id="mpt">
+       <name>Monkey Picked Tea</name>
+       <description>Rare wild Chinese tea</description>
+       <description>Picked only by specially trained monkeys</description>
+   </product>
+    <product id="instantTent">
+        <name>4-Person Instant Tent</name>
+        <description>4-person, 1-room tent</description>
+        <description>Pre-attached tent poles</description>
+        <description>Exclusive WeatherTec system.</description>
+        <age>15</age>
+    </product>
+</catalog>
\ No newline at end of file
diff --git a/Sda1/P/catalog2rdbms/src/main/java/de/hdm_stuttgart/mi/sda1/catalog2sql/DataInsert.java b/Sda1/P/catalog2rdbms/src/main/java/de/hdm_stuttgart/mi/sda1/catalog2sql/DataInsert.java
new file mode 100644
index 000000000..150f5286d
--- /dev/null
+++ b/Sda1/P/catalog2rdbms/src/main/java/de/hdm_stuttgart/mi/sda1/catalog2sql/DataInsert.java
@@ -0,0 +1,84 @@
+package de.hdm_stuttgart.mi.sda1.catalog2sql;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.List;
+
+/**
+ * Formatting product related INSERT statements
+ *
+ */
+public class DataInsert {
+	
+	final Statement stmt;
+
+	/**
+	 * @param conn Destination RDBMS
+	 * @throws SQLException 
+	 */
+	public DataInsert(final Connection conn) throws SQLException {
+		stmt = conn.createStatement();
+	}
+	
+	/**
+	 * Create an SQL INSERT statement corresponding to a &lt;product id='...' &gt; entry
+	 * lacking age specification.
+	 * @param productId  See {@link #insertproduct(String, String, int)}
+	 * @param productName See {@link #insertproduct(String, String, int)}
+	 * @throws SQLException 
+	 */
+	public void insertproduct(final String productId, final String productName) {
+      final String sqlInsertStmt = "INSERT INTO Product (id, name) VALUES ('" + productId + "', '" + productName +  "');";
+      try {
+         stmt.executeUpdate(sqlInsertStmt);
+      } catch (SQLException e) {
+         Helper.exitWithErrorMessage("Unable to insert product without age property", 1);
+
+      }
+	}
+	
+	/**
+	 * Insert dataset corresponding to a &lt;product id='...' &gt; entry
+	 * @param productId The product's unique id property
+	 * @param productName The product's end user readable name.
+	 * @param age The product's age
+	 * @throws SQLException 
+	 */
+	public void insertproduct(final String productId, final String productName, final int age)  {
+	   
+	   // A PreparedStatement is preferable but not yet introduced in lecture
+	   //
+		final String sqlInsertStmt = "INSERT INTO Product VALUES ('" + productId + "', '" + productName +  "', " + age + ");";
+      try {
+         stmt.executeUpdate(sqlInsertStmt);
+      } catch (SQLException e) {
+         Helper.exitWithErrorMessage("Unable to insert product including age property", 1);
+      }
+	}
+
+	
+	/**
+	 * Adding a description to a given product.
+	 * 
+	 * @param productId The description belongs to this product 
+	 * @param descriptions All descriptions belonging to productId
+	 * @throws SQLException 
+	 */
+	public void insertDescription(final String productId, final List<String> descriptions) {
+	   
+		for (int i = 0; i < descriptions.size(); i++) {
+		   final String sqlInsertStmt = "INSERT INTO Description VALUES('" + productId + "', " + i + ", '" +
+		                                 descriptions.get(i) + "');";
+		   try {
+            stmt.executeUpdate(sqlInsertStmt);
+         } catch (SQLException e) {
+           Helper.exitWithErrorMessage("Unable to insert product description", 1);
+         }
+		}
+	}
+	public void close() throws SQLException {
+	   stmt.close();
+	}
+	
+}
diff --git a/Sda1/P/catalog2rdbms/src/main/java/de/hdm_stuttgart/mi/sda1/catalog2sql/Helper.java b/Sda1/P/catalog2rdbms/src/main/java/de/hdm_stuttgart/mi/sda1/catalog2sql/Helper.java
new file mode 100644
index 000000000..06e88f12e
--- /dev/null
+++ b/Sda1/P/catalog2rdbms/src/main/java/de/hdm_stuttgart/mi/sda1/catalog2sql/Helper.java
@@ -0,0 +1,9 @@
+package de.hdm_stuttgart.mi.sda1.catalog2sql;
+
+public class Helper {
+   public static void exitWithErrorMessage(final String errMsg, int errorCode) {
+      System.err.println(errMsg);
+      System.exit(errorCode);
+   }
+
+}
diff --git a/Sda1/P/catalog2rdbms/src/main/java/de/hdm_stuttgart/mi/sda1/catalog2sql/Xml2Rdbms.java b/Sda1/P/catalog2rdbms/src/main/java/de/hdm_stuttgart/mi/sda1/catalog2sql/Xml2Rdbms.java
new file mode 100644
index 000000000..893868eff
--- /dev/null
+++ b/Sda1/P/catalog2rdbms/src/main/java/de/hdm_stuttgart/mi/sda1/catalog2sql/Xml2Rdbms.java
@@ -0,0 +1,90 @@
+package de.hdm_stuttgart.mi.sda1.catalog2sql;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+
+import de.hdm_stuttgart.mi.sda1.catalog2sql.handler.CatalogContentHandler;
+import de.hdm_stuttgart.mi.sda1.saxerrorhandler.handler.SaxErrorHandler;
+
+/**
+ * A simple SAX parser demo
+ * 
+ */
+public class Xml2Rdbms {
+   private static final Logger log = LogManager.getLogger(Xml2Rdbms.class);
+
+   /**
+    * @param args
+    *           Unused
+    * @throws SAXException
+    * @throws ParserConfigurationException
+    * @throws IOException
+    */
+   public static void main(String[] args) throws ParserConfigurationException,
+         SAXException, IOException {
+
+      log.info("Creating SAX parser");
+      final SAXParserFactory saxPf = SAXParserFactory.newInstance();
+      final SAXParser saxParser = saxPf.newSAXParser();
+      final XMLReader xmlReader = saxParser.getXMLReader();
+
+      
+      // Register Driver
+      final String sqlDriverClassName = "com.mysql.jdbc.Driver"; 
+      try {
+         Class.forName(sqlDriverClassName);
+      } catch (ClassNotFoundException e) {
+         Helper.exitWithErrorMessage("Unable to register driver class '" + sqlDriverClassName + "'", 1);
+      }
+
+
+      // Opening a JDBC connection
+      // 
+      Connection conn = null;
+      
+      final String jdbcConnectionUrl = "jdbc:mysql://localhost:3306/hdm";
+      final String userName = "hdmuser";
+      try {
+         conn = DriverManager.getConnection(jdbcConnectionUrl, userName, "XYZ");
+      } catch (SQLException e) {
+         Helper.exitWithErrorMessage("Unable to connect as user '" + userName + "' to '" +
+               jdbcConnectionUrl + "'", 1);
+      }
+      
+      DataInsert dataInsert = null;
+      try {
+         dataInsert = new DataInsert(conn);
+      } catch (SQLException e) {
+         Helper.exitWithErrorMessage("Unable to initialize data inserter", 1);
+      }
+
+      log.info("Registering content- and error handler instances");
+      xmlReader.setContentHandler(new CatalogContentHandler(dataInsert));
+      xmlReader.setErrorHandler(new SaxErrorHandler(System.err));
+
+      final String xmlDocumentInstanceFilename = "products.xml";
+      log.info("Start parsing file '" + xmlDocumentInstanceFilename + "'");
+      xmlReader.parse(xmlDocumentInstanceFilename);
+
+      // Closing
+      try {
+         dataInsert.close();  // Closing Statement
+         conn.close();        // Closing Connection
+      } catch (SQLException e) {
+         Helper.exitWithErrorMessage("Unable to close RDBMS access", 1);
+      }
+   }
+   
+}
diff --git a/Sda1/P/catalog2rdbms/src/main/java/de/hdm_stuttgart/mi/sda1/catalog2sql/handler/CatalogContentHandler.java b/Sda1/P/catalog2rdbms/src/main/java/de/hdm_stuttgart/mi/sda1/catalog2sql/handler/CatalogContentHandler.java
new file mode 100644
index 000000000..6e2510265
--- /dev/null
+++ b/Sda1/P/catalog2rdbms/src/main/java/de/hdm_stuttgart/mi/sda1/catalog2sql/handler/CatalogContentHandler.java
@@ -0,0 +1,126 @@
+package de.hdm_stuttgart.mi.sda1.catalog2sql.handler;
+
+import java.util.List;
+import java.util.Vector;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+
+import de.hdm_stuttgart.mi.sda1.catalog2sql.DataInsert;
+
+/**
+ * Turning XML data into SQL INSERT statements
+ *
+ */
+public class CatalogContentHandler implements ContentHandler {
+	private static final Logger log = LogManager.getLogger(CatalogContentHandler.class);
+	Locator locator = null;
+	
+	final DataInsert sqlFormatter;
+
+	private final List<String> currentDescriptions = new Vector<String>();
+
+	final StringBuffer currentElementContent = new StringBuffer();
+	
+	String productId, productName, productAgeString;
+	
+	/**
+	 * @param sqlFormatter SQL INSERT statement formatter
+	 */
+	public CatalogContentHandler(final DataInsert sqlFormatter) {
+		this.sqlFormatter = sqlFormatter;
+	}
+
+	@Override
+	public void setDocumentLocator(Locator locator) {
+		this.locator = locator;
+	}
+	// Convenience Method
+	String displayWithLocatio(final String saxMsg) {
+		if (null == locator) {
+			return saxMsg;
+		} else {
+			return "File position (" + locator.getLineNumber() + ", " + locator.getColumnNumber() + "): " + saxMsg;
+		}
+	}
+
+	@Override
+	public void startElement(String uri, String localName, String qName,
+			Attributes attributes) throws SAXException {
+		currentElementContent.setLength(0);
+		switch(qName) {
+		case "product":
+			productAgeString = null; // Value will be altered if &lt;age&gt; is present
+			productId = attributes.getValue("id");
+			log.info(displayWithLocatio("Product id=" + productId));
+			break;
+		}
+	}
+
+	@Override
+	public void endElement(final String uri, final String localName, final String qName)
+			throws SAXException {
+		switch(qName) {
+		case "product":
+			if (null == productAgeString) {
+				sqlFormatter.insertproduct(productId, productName);
+			} else {
+				try {
+					sqlFormatter.insertproduct(productId, productName, Integer.parseInt(productAgeString));
+				} catch (NumberFormatException ex) {
+					log.error("Property <age> is not of integer value:" + productAgeString);
+				}
+			}
+			flushDescriptionEntries();
+			break;
+		case "name":
+			productName = currentElementContent.toString();
+			break;
+
+		case "description":
+			// Do not interfere with the current INSERT INTO Product ... 
+			// statement. Instead postpone related INSERT INTO Description ...
+			// operations, see flushDescriptionEntries().
+			currentDescriptions.add(currentElementContent.toString());
+			break;
+		case "age":
+			productAgeString = currentElementContent.toString();
+			break;
+		}
+	}
+	private void flushDescriptionEntries() {
+		// Add <description> related INSERTs
+		sqlFormatter.insertDescription(productId, currentDescriptions);
+		
+		// Next <product> may be yet to come, so
+		// clear the current set of descriptions.
+		currentDescriptions.clear();
+	}
+
+	@Override
+	public void characters(final char[] ch, final int start, final int length)
+			throws SAXException {
+		currentElementContent.append(new String(ch, start,length));
+	}
+	
+	// We don't need these remaining callbacks 
+
+	@Override public void startDocument() throws SAXException {}
+	@Override public void endDocument() throws SAXException {}
+	@Override public void startPrefixMapping(String prefix, String uri)
+			throws SAXException {}
+	@Override public void endPrefixMapping(String prefix)
+			throws SAXException {}
+	@Override public void ignorableWhitespace(char[] ch, int start, int length)
+			throws SAXException {}
+
+	@Override public void processingInstruction(String target, String data)
+			throws SAXException {}
+
+	@Override public void skippedEntity(String name) throws SAXException {}
+
+}
\ No newline at end of file
diff --git a/Sda1/P/catalog2rdbms/src/main/resources/log4j2.xml b/Sda1/P/catalog2rdbms/src/main/resources/log4j2.xml
new file mode 100644
index 000000000..eda4f3b0d
--- /dev/null
+++ b/Sda1/P/catalog2rdbms/src/main/resources/log4j2.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration>
+    <Appenders>
+        <File name="A1" fileName="A1.log" append="false">
+            <PatternLayout pattern="%t %-5p %c{2} - %m%n"/>
+        </File>
+        <Console name="STDOUT" target="SYSTEM_OUT">
+            <PatternLayout pattern="%C{2} (%F:%L) - %m%n"/>
+        </Console>
+    </Appenders>
+    <Loggers>
+
+        <!-- You my want to define class or package level per-logger rules -->
+        <Logger name="de.hdm_stuttgart.mi.sda1.catalog2sax.App" level="debug">
+            <AppenderRef ref="A1"/>
+        </Logger>
+        <Root level="debug">
+            <AppenderRef ref="STDOUT"/>
+        </Root>
+    </Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/Sda1/sda1.xml b/Sda1/sda1.xml
index e7eb592c0..602c72365 100644
--- a/Sda1/sda1.xml
+++ b/Sda1/sda1.xml
@@ -9643,6 +9643,28 @@ public class SimpleInsert {
         </qandaset>
       </section>
 
+      <section xml:id="xmldata2rdbms">
+        <title>Moving data from XML to relational systems</title>
+
+        <qandaset defaultlabel="qanda" xml:id="qandaXmldata2relational">
+          <title>Avoiding intermediate <xref linkend="glo_SQL"/> file
+          export</title>
+
+          <qandadiv>
+            <qandaentry>
+              <question>
+                <para>In <xref linkend="quandaentry_SqlFromXml"/> you
+                implemented a <xref linkend="glo_SAX"/> application
+                transforming XML product catalog instances into a series of
+                SQL statements. Modify your solution by directly inserting
+                corresponding data by means of <xref linkend="glo_JDBC"/> into
+                a relational database.</para>
+              </question>
+            </qandaentry>
+          </qandadiv>
+        </qandaset>
+      </section>
+
       <section xml:id="sectSimpleInsertGui">
         <title>A first GUI sketch</title>
 
diff --git a/Sda2/P/Jpa/University/src/main/java/de/hdm_stuttgart/mi/sda2/jpa/cd/domain/Student.java b/Sda2/P/Jpa/University/src/main/java/de/hdm_stuttgart/mi/sda2/jpa/cd/domain/Student.java
index 330502011..12f95cc50 100644
--- a/Sda2/P/Jpa/University/src/main/java/de/hdm_stuttgart/mi/sda2/jpa/cd/domain/Student.java
+++ b/Sda2/P/Jpa/University/src/main/java/de/hdm_stuttgart/mi/sda2/jpa/cd/domain/Student.java
@@ -3,15 +3,19 @@ package de.hdm_stuttgart.mi.sda2.jpa.cd.domain;
 import static javax.persistence.CascadeType.PERSIST;
 import static javax.persistence.CascadeType.REMOVE;
 
+import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import javax.persistence.Column;
+import javax.persistence.ElementCollection;
 import javax.persistence.Entity;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.OneToMany;
+import javax.persistence.OrderColumn;
 import javax.persistence.Table;
 
 
@@ -26,6 +30,13 @@ public class Student {
    
    @Column(unique=true, nullable=false)
    int matriculation;
+   
+   @ElementCollection
+   final Set<String> emails = new HashSet<String>();
+   
+   @ElementCollection
+   @OrderColumn
+   final List<Address> addresses = new ArrayList<Address>();
 
    @OneToMany(mappedBy="student", cascade={PERSIST, REMOVE})
    Set<StudentLecture> lectures = new HashSet<StudentLecture>();
@@ -58,4 +69,11 @@ public class Student {
    public Long getId() {
       return id;
    }
+   public Set<String> getEmails() {
+      return emails;
+   }
+   public List<Address> getAddresses() {
+      return addresses;
+   }
+   
 }
diff --git a/Sda2/P/Jpa/University/src/main/java/de/hdm_stuttgart/mi/sda2/jpa/university/Driver.java b/Sda2/P/Jpa/University/src/main/java/de/hdm_stuttgart/mi/sda2/jpa/university/Driver.java
index 611cc34d1..4c6a17222 100644
--- a/Sda2/P/Jpa/University/src/main/java/de/hdm_stuttgart/mi/sda2/jpa/university/Driver.java
+++ b/Sda2/P/Jpa/University/src/main/java/de/hdm_stuttgart/mi/sda2/jpa/university/Driver.java
@@ -9,6 +9,7 @@ import javax.xml.bind.JAXBException;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
+import de.hdm_stuttgart.mi.sda2.jpa.cd.domain.Address;
 import de.hdm_stuttgart.mi.sda2.jpa.cd.domain.Lecture;
 import de.hdm_stuttgart.mi.sda2.jpa.cd.domain.Student;
 import de.hdm_stuttgart.mi.sda2.jpa.cd.domain.StudentLecture;
@@ -34,7 +35,20 @@ public class Driver {
 
       final EntityTransaction tx = manager.getTransaction();
 
-      final Student joe = new Student("Joe Blix", 12346);
+      final Student joe = new Student("Joe Blix", 12346),
+            eve = new Student("Eve Gardener", 54321);
+      
+      // Adding E-Mails
+      joe.getEmails().add("joe@test.com");
+      joe.getEmails().add("joe@blix.org");
+      
+      // Adding addresses
+      joe.getAddresses().add(new Address("Schulstrasse 4", "Bad Oyenhausen", "32547"));
+      joe.getAddresses().add(new Address("Am Märzenbaum 55", "Gummersbach", "66883"));
+      
+      eve.getAddresses().add(new Address("Grüner Weg 6", "Friedberg", "61169"));
+      eve.getAddresses().add(new Address("Grüner Weg 6", "Friedberg", "61169"));
+      
       final Lecture db = new Lecture("Database systems", 11312);
       final StudentLecture joeDb = new StudentLecture(joe, db, 5);
 
@@ -44,26 +58,39 @@ public class Driver {
          // enabled
          // manager.persist(db);
          manager.persist(joeDb);
+         manager.persist(eve);
       }
       tx.commit();
 
       tx.begin();
       {
          manager.refresh(joe);
-         System.out.println("Lectures of Joe:");
+         log.info("Lectures of Joe:");
          for (StudentLecture sl : joe.getLectures()) {
-            System.out.println(sl.getLecture().getTitle());
+            log.info(sl.getLecture().getTitle());
          }
       }
       tx.commit();
-
+      
       tx.begin();
       {
-         System.out.println("Deleting Joe from Database");
-         manager.remove(joe);
+         log.info("Reloading Joe:");
+         final Student joeRetrieved = manager.find(Student.class, joe.getId());
+         log.info(joeRetrieved.getFullName());
+         log.info("Retrieving Joe's adresses:" );
+         for (final Address a: joeRetrieved.getAddresses()) {
+            log.info(a);
+         }
       }
       tx.commit();
 
+//      tx.begin();
+//      {
+//         log.info("Deleting Joe from Database");
+//         manager.remove(joe);
+//      }
+//      tx.commit();
+
    }
 
 }
diff --git a/Sda2/P/Jpa/University/src/main/resources/META-INF/persistence.xml b/Sda2/P/Jpa/University/src/main/resources/META-INF/persistence.xml
index 6914d0be7..64646e14e 100644
--- a/Sda2/P/Jpa/University/src/main/resources/META-INF/persistence.xml
+++ b/Sda2/P/Jpa/University/src/main/resources/META-INF/persistence.xml
@@ -15,7 +15,11 @@
 			<!-- EclipseLink should create the database schema automatically -->
 			<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
 			<property name="eclipselink.ddl-generation.output-mode" value="database" />
-			<property name="eclipselink.logging.level" value="SEVERE"/>				
+			<property name="eclipselink.logging.level" value="SEVERE"/>	
+
+			<!-- Logging SQL operations -->
+			<property name="eclipselink.logging.level.sql" value="FINE"/>
+			<property name="eclipselink.logging.parameters" value="true"/>
 		</properties>
 
 	</persistence-unit>
diff --git a/Sda2/P/Jpa/University/src/main/resources/log4j2.xml b/Sda2/P/Jpa/University/src/main/resources/log4j2.xml
index 3d47b7de2..378492e37 100644
--- a/Sda2/P/Jpa/University/src/main/resources/log4j2.xml
+++ b/Sda2/P/Jpa/University/src/main/resources/log4j2.xml
@@ -5,7 +5,7 @@
             <PatternLayout pattern="%t %-5p %c{2} - %m%n"/>
         </File>
         <Console name="STDOUT" target="SYSTEM_OUT">
-            <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
+            <PatternLayout pattern="%-5p [%t] %C{2} (%F:%L) - %m%n"/>
         </Console>
     </Appenders>
     <Loggers>
-- 
GitLab