Commit 52fa32802f529a8930db5df8c422fef3848b87e9

Authored by Thomas Ziemer
0 parents

Initial commit

.gitignore 0 → 100644
  1 +++ a/.gitignore
  1 +.classpath
  2 +.project
  3 +.settings/
  4 +target/
... ...
README.md 0 → 100644
  1 +++ a/README.md
  1 +Ein Beispielprojekt für die Lehrveranstaltungen "Software Engineering 2" (SE2) und "Softwarequalität und Test" (SwQT).
... ...
pom.xml 0 → 100644
  1 +++ a/pom.xml
  1 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  3 + <modelVersion>4.0.0</modelVersion>
  4 + <groupId>net.ziemers</groupId>
  5 + <artifactId>swxercise</artifactId>
  6 + <packaging>war</packaging>
  7 + <version>0.0.1-SNAPSHOT</version>
  8 + <name>swXercise Maven Webapp</name>
  9 + <url>http://maven.apache.org</url>
  10 + <properties>
  11 + <mvn-compiler-plugin-version>3.3</mvn-compiler-plugin-version>
  12 + <jee-version>7.0</jee-version>
  13 + <java-version>1.8</java-version>
  14 + <jaxrs-version>2.0</jaxrs-version>
  15 + <mysql-version>5.1.41</mysql-version>
  16 + <hibernate-version>5.2.1.Final</hibernate-version>
  17 + <junit-version>4.12</junit-version>
  18 + <mockito-version>2.7.22</mockito-version>
  19 + <dbunit-version>2.5.1</dbunit-version>
  20 + <slf4j-version>1.8.0-alpha0</slf4j-version>
  21 + </properties>
  22 + <dependencies>
  23 + <dependency>
  24 + <groupId>javax</groupId>
  25 + <artifactId>javaee-api</artifactId>
  26 + <version>${jee-version}</version>
  27 + </dependency>
  28 + <dependency>
  29 + <groupId>javax.ws.rs</groupId>
  30 + <artifactId>javax.ws.rs-api</artifactId>
  31 + <version>${jaxrs-version}</version>
  32 + </dependency>
  33 + <dependency>
  34 + <groupId>junit</groupId>
  35 + <artifactId>junit</artifactId>
  36 + <version>${junit-version}</version>
  37 + <scope>test</scope>
  38 + </dependency>
  39 + <dependency>
  40 + <groupId>org.slf4j</groupId>
  41 + <artifactId>slf4j-api</artifactId>
  42 + <version>${slf4j-version}</version>
  43 + <scope>provided</scope>
  44 + </dependency>
  45 + <dependency>
  46 + <groupId>org.mockito</groupId>
  47 + <artifactId>mockito-core</artifactId>
  48 + <version>${mockito-version}</version>
  49 + </dependency>
  50 + <dependency>
  51 + <groupId>org.dbunit</groupId>
  52 + <artifactId>dbunit</artifactId>
  53 + <version>${dbunit-version}</version>
  54 + </dependency>
  55 + <dependency>
  56 + <groupId>org.hibernate</groupId>
  57 + <artifactId>hibernate-core</artifactId>
  58 + <version>${hibernate-version}</version>
  59 + </dependency>
  60 + <dependency>
  61 + <groupId>mysql</groupId>
  62 + <artifactId>mysql-connector-java</artifactId>
  63 + <version>${mysql-version}</version>
  64 + </dependency>
  65 + </dependencies>
  66 + <build>
  67 + <finalName>swXercise</finalName>
  68 +
  69 + <plugins>
  70 + <plugin>
  71 + <artifactId>maven-compiler-plugin</artifactId>
  72 + <version>${mvn-compiler-plugin-version}</version>
  73 + <configuration>
  74 + <source>${java-version}</source>
  75 + <target>${java-version}</target>
  76 + </configuration>
  77 + </plugin>
  78 + </plugins>
  79 + </build>
  80 +</project>
... ...
src/main/java/net/ziemers/swxercise/db/utils/JpaTestUtils.java 0 → 100644
  1 +++ a/src/main/java/net/ziemers/swxercise/db/utils/JpaTestUtils.java
  1 +package net.ziemers.swxercise.db.utils;
  2 +
  3 +import java.io.File;
  4 +import java.io.FileInputStream;
  5 +import java.io.IOException;
  6 +import java.io.InputStream;
  7 +import java.util.Arrays;
  8 +import java.util.List;
  9 +import java.util.Properties;
  10 +import java.util.stream.Collectors;
  11 +
  12 +import javax.enterprise.inject.Produces;
  13 +import javax.persistence.EntityManager;
  14 +import javax.persistence.EntityManagerFactory;
  15 +import javax.persistence.EntityTransaction;
  16 +import javax.persistence.Persistence;
  17 +import javax.persistence.Query;
  18 +
  19 +import org.dbunit.DatabaseUnitException;
  20 +import org.dbunit.database.DatabaseConfig;
  21 +import org.dbunit.database.DatabaseConnection;
  22 +import org.dbunit.database.IMetadataHandler;
  23 +import org.dbunit.dataset.IDataSet;
  24 +import org.dbunit.dataset.datatype.IDataTypeFactory;
  25 +import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
  26 +import org.dbunit.ext.mysql.MySqlDataTypeFactory;
  27 +import org.dbunit.ext.mysql.MySqlMetadataHandler;
  28 +import org.dbunit.operation.DatabaseOperation;
  29 +import org.hibernate.internal.SessionImpl;
  30 +import org.junit.After;
  31 +import org.slf4j.Logger;
  32 +import org.slf4j.LoggerFactory;
  33 +
  34 +public class JpaTestUtils {
  35 +
  36 + private static final Logger logger = LoggerFactory.getLogger(JpaTestUtils.class.getName());
  37 +
  38 + private static final String PERSISTENCE_UNIT_TEST = "swxercise_test";
  39 +
  40 + private static final String NET_ZIEMERS_SWXERCISE_PKG = "net/ziemers/swxercise/";
  41 +
  42 + private static EntityManagerFactory emf = null;
  43 +
  44 + private static EntityManager em = null;
  45 +
  46 + private EntityTransaction tx;
  47 +
  48 + /**
  49 + * Produziert eine EntityManagerFactory und einen EntityManager und speichert sie als static (Singleton),
  50 + * damit sie nicht immer neu erstellt werden für jeden Test.
  51 + *
  52 + * @return EntityManager der erzeugt wurde
  53 + */
  54 + @Produces
  55 + public EntityManager getEm() {
  56 + if (emf == null) {
  57 + synchronized (EntityManagerFactory.class) {
  58 + if (emf == null) {
  59 + emf = createEntityManagerFactory();
  60 + }
  61 + }
  62 + }
  63 + if (emf != null && em == null) {
  64 + synchronized (EntityManager.class) {
  65 + if (emf != null && em == null) {
  66 + em = emf.createEntityManager();
  67 + }
  68 + }
  69 + }
  70 + return em;
  71 + }
  72 +
  73 + protected void clearEm() {
  74 + em = null;
  75 + }
  76 +
  77 + /**
  78 + * Private Methode, die eine EntityManagerFactory erzeugen kann. Verwendet eine im Home-Verzeichnis des
  79 + * aktuellen Benutzers abgelegte Datei persistence.properties, um die Defaults aus der persistence.xml
  80 + * zu überschreiben.
  81 + *
  82 + * @return neu erstellte {@link EntityManagerFactory}
  83 + */
  84 + private static EntityManagerFactory createEntityManagerFactory() {
  85 +
  86 + String homePath = System.getProperty("user.home");
  87 + String swxercisePersistenceXmlPath = homePath + File.separator + ".swXercise" + File.separator + "persistence.properties";
  88 + File swxercisePersistenceXmlFile = new File(swxercisePersistenceXmlPath);
  89 + EntityManagerFactory emf = null;
  90 + FileInputStream fis = null;
  91 +
  92 + try {
  93 + fis = new FileInputStream(swxercisePersistenceXmlFile);
  94 + Properties overrideProperties = new Properties();
  95 + overrideProperties.load(fis);
  96 + emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_TEST, overrideProperties);
  97 + } catch (Exception e) {
  98 + logger.info("Persistence properties will not be overriden because of following error:", e);
  99 + } finally {
  100 + if (fis != null) {
  101 + try {
  102 + fis.close();
  103 + } catch (IOException e) {
  104 + logger.error(e.getMessage(), e);
  105 + }
  106 + }
  107 + }
  108 +
  109 + if (emf == null) {
  110 + emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_TEST);
  111 + }
  112 +
  113 + return emf;
  114 + }
  115 +
  116 + public void txBegin() {
  117 + tx = getEm().getTransaction();
  118 + tx.begin();
  119 + }
  120 +
  121 + public void txCommit() {
  122 + tx.commit();
  123 + }
  124 +
  125 + public void txRollback() {
  126 + tx.rollback();
  127 + }
  128 +
  129 + /**
  130 + * Hilfsmethode, um ein als XML vorliegendes Dataset zu laden.
  131 + *
  132 + * @param resourceName Dateiname, welches als Ressource gesucht wird
  133 + * @return das geladene Dataset
  134 + * @throws Exception wenn beim Behandeln der Dateien eine Exception aufgetreten ist
  135 + */
  136 + private static IDataSet readDataset(String resourceName) throws Exception {
  137 + IDataSet dataSet = null;
  138 + InputStream dtdStream = null;
  139 + InputStream resourceAsStream = null;
  140 + try {
  141 + FlatXmlDataSetBuilder flatXmlDataSetBuilder = new FlatXmlDataSetBuilder();
  142 + dtdStream = JpaTestUtils.class.getClassLoader().getResourceAsStream(NET_ZIEMERS_SWXERCISE_PKG + "empty/entity_versioning.dtd");
  143 + // flatXmlDataSetBuilder.setMetaDataSetFromDtd(dtdStream);
  144 + flatXmlDataSetBuilder.setColumnSensing(true);
  145 +
  146 + resourceAsStream = JpaTestUtils.class.getClassLoader().getResourceAsStream(NET_ZIEMERS_SWXERCISE_PKG + resourceName);
  147 + dataSet = flatXmlDataSetBuilder.build(resourceAsStream);
  148 + } catch (Exception e) {
  149 + throw e;
  150 + } finally {
  151 + if (dtdStream != null) {
  152 + dtdStream.close();
  153 + }
  154 + if (resourceAsStream != null) {
  155 + resourceAsStream.close();
  156 + }
  157 + }
  158 +
  159 + return dataSet;
  160 + }
  161 +
  162 + /**
  163 + * Initialisiert die Datenbank aus einer XML-Beschreibung heraus.
  164 + *
  165 + * @param resourceName der Name der XML-Datei
  166 + * @throws Exception wenn dabei etwas schiefläuft
  167 + */
  168 + protected void initDbWith(String resourceName) throws Exception {
  169 + IDataSet dataset = readDataset(resourceName);
  170 + try {
  171 + SessionImpl delegate = (SessionImpl) this.getEm().getDelegate();
  172 + DatabaseConnection connection = new DatabaseConnection(delegate.connection());
  173 + IMetadataHandler mysqlHandler = new MySqlMetadataHandler();
  174 + IDataTypeFactory mySqlDataTypeFactory = new MySqlDataTypeFactory();
  175 + connection.getConfig().setProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER, mysqlHandler);
  176 + connection.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, mySqlDataTypeFactory);
  177 + DatabaseOperation.INSERT.execute(connection, dataset);
  178 + } catch (DatabaseUnitException qe) {
  179 + logger.warn("Database entries already inserted. If your tests fail, check your sql inserts for constraint violations!");
  180 + logger.warn(qe.getMessage());
  181 + logger.warn(qe.getMessage(), qe);
  182 + throw qe;
  183 + }
  184 + }
  185 +
  186 + /**
  187 + * Räumt die Datenbank mit DBUnit auf, um für jeden Test eine leere, saubere Datenbank zu haben.
  188 + *
  189 + * @throws Exception Wirft eventuelle SQL- und I/O-Exceptions
  190 + */
  191 + public void cleanDb() throws Exception {
  192 + String schema = getCurrentSchema();
  193 + List<String> tables = getTableNamesToBeEmptied();
  194 + getEm().getTransaction().begin();
  195 + getEm().createNativeQuery("SET foreign_key_checks=0;").executeUpdate();
  196 + for (String table : tables) {
  197 + getEm().createNativeQuery(getTruncateStatement(schema, table)).executeUpdate();
  198 + }
  199 + getEm().createNativeQuery("SET foreign_key_checks=1;").executeUpdate();
  200 + getEm().getTransaction().commit();
  201 + getEm().clear();
  202 + }
  203 +
  204 + private String getCurrentSchema() {
  205 + String query = "SELECT DATABASE()";
  206 + List<Object> result = executeReadQuery(query);
  207 + if (result.isEmpty()) {
  208 + return null;
  209 + }
  210 + Object object = result.get(0);
  211 + if (object instanceof String) {
  212 + return (String) object;
  213 + }
  214 + return null;
  215 + }
  216 +
  217 + public List<String> getTableNamesToBeEmptied() throws Exception {
  218 + return showTablesNotEmpty(getCurrentSchema());
  219 + }
  220 +
  221 + private List<String> showTablesNotEmpty(String schema) throws Exception {
  222 + StringBuilder query = new StringBuilder();
  223 + query.append("SELECT table_name ");
  224 + query.append("FROM information_schema.tables ");
  225 + // query.append("WHERE table_rows > 0 ");
  226 + // query.append(String.format("AND table_schema = '%s'", schema));
  227 + query.append(String.format("WHERE table_schema = '%s'", schema));
  228 + getSkippingTables().stream().forEach(table -> query.append(String.format("AND table_name != '%s'", table)));
  229 + List<Object> result = executeReadQuery(query.toString());
  230 + return result.stream().filter(o -> o instanceof String).map(o -> (String) o).collect(Collectors.toList());
  231 + }
  232 +
  233 + /**
  234 + * Verschiedene Tabellen sollen ignoriert werden.
  235 + *
  236 + * @return eine Liste der zu ignorierenden Tabellen
  237 + */
  238 + public List<String> getSkippingTables() {
  239 + return Arrays.asList(
  240 + "status",
  241 + "schema_version"); // FlywayDB Metatable
  242 + }
  243 +
  244 + private List<Object> executeReadQuery(String queryString) {
  245 + getEm().getTransaction().begin();
  246 + Query query = getEm().createNativeQuery(queryString);
  247 + @SuppressWarnings("unchecked")
  248 + List<Object> result = query.getResultList();
  249 + getEm().getTransaction().rollback();
  250 + return result;
  251 + }
  252 +
  253 + public String getTruncateStatement(String schema, String table) {
  254 + return String.format("DELETE FROM %s.%s;", schema, table);
  255 + }
  256 +
  257 + /**
  258 + * Rollt eine jetzt noch aktive Transaktion zurück.
  259 + */
  260 + @After
  261 + public void tearDown() {
  262 + EntityTransaction transaction = getEm().getTransaction();
  263 + if (transaction.isActive()) {
  264 + transaction.rollback();
  265 + }
  266 + }
  267 +
  268 +}
... ...
src/main/java/net/ziemers/swxercise/lg/SwXerciseService.java 0 → 100644
  1 +++ a/src/main/java/net/ziemers/swxercise/lg/SwXerciseService.java
  1 +package net.ziemers.swxercise.lg;
  2 +
  3 +import javax.ejb.Stateless;
  4 +
  5 +@Stateless
  6 +public class SwXerciseService {
  7 +}
... ...
src/main/java/net/ziemers/swxercise/ui/RestApplication.java 0 → 100644
  1 +++ a/src/main/java/net/ziemers/swxercise/ui/RestApplication.java
  1 +package net.ziemers.swxercise.ui;
  2 +
  3 +import javax.ws.rs.ApplicationPath;
  4 +import javax.ws.rs.core.Application;
  5 +
  6 +@ApplicationPath(RestApplication.webContextPath)
  7 +public class RestApplication extends Application {
  8 +
  9 + static final String webContextPath = "/rest";
  10 +
  11 +}
... ...
src/main/java/net/ziemers/swxercise/ui/RestController.java 0 → 100644
  1 +++ a/src/main/java/net/ziemers/swxercise/ui/RestController.java
  1 +package net.ziemers.swxercise.ui;
  2 +
  3 +import javax.annotation.PostConstruct;
  4 +import javax.enterprise.context.ApplicationScoped;
  5 +import javax.ws.rs.GET;
  6 +import javax.ws.rs.Path;
  7 +import javax.ws.rs.PathParam;
  8 +import javax.ws.rs.Produces;
  9 +import javax.ws.rs.core.MediaType;
  10 +
  11 +import org.slf4j.Logger;
  12 +import org.slf4j.LoggerFactory;
  13 +
  14 +@ApplicationScoped
  15 +@Path(RestController.webContextPath)
  16 +public class RestController {
  17 +
  18 + static final String webContextPath = "/misc";
  19 +
  20 + private Logger logger;
  21 +
  22 + @PostConstruct
  23 + public void init() {
  24 + logger = LoggerFactory.getLogger(RestController.class);
  25 + }
  26 +
  27 + /**
  28 + * Schickt eine Hello-Nachricht zum Aufrufer zurück.
  29 + *
  30 + * @param name
  31 + * der Name, der in der Hallo-Nachricht angegeben wird
  32 + * @return eine Hallo-Nachricht
  33 + */
  34 + @GET
  35 + @Path("/hello/{name}")
  36 + @Produces(MediaType.TEXT_PLAIN)
  37 + public String helloPath(@PathParam("name") String name) {
  38 + logger.info("Hello {}", name);
  39 + return String.format("Hello %s", name);
  40 + }
  41 +
  42 +}
... ...
src/main/webapp/WEB-INF/jboss-web.xml 0 → 100644
  1 +++ a/src/main/webapp/WEB-INF/jboss-web.xml
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<jboss-web xmlns="http://www.jboss.com/xml/ns/javaee"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="
  5 + http://www.jboss.com/xml/ns/javaee
  6 + http://www.jboss.org/j2ee/schema/jboss-web_5_1.xsd">
  7 + <context-root>swxercise</context-root>
  8 +</jboss-web>
... ...
src/main/webapp/WEB-INF/web.xml 0 → 100644
  1 +++ a/src/main/webapp/WEB-INF/web.xml
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3 + xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  4 + xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
  5 + version="3.1" />
0 6 \ No newline at end of file
... ...
src/test/java/net/ziemers/swxercise/lg/SwXerciseServiceTest.java 0 → 100644
  1 +++ a/src/test/java/net/ziemers/swxercise/lg/SwXerciseServiceTest.java
  1 +package net.ziemers.swxercise.lg;
  2 +
  3 +import net.ziemers.swxercise.db.utils.JpaTestUtils;
  4 +import org.junit.Test;
  5 +import org.junit.runner.RunWith;
  6 +import org.mockito.InjectMocks;
  7 +import org.mockito.junit.MockitoJUnitRunner;
  8 +
  9 +@RunWith(MockitoJUnitRunner.class)
  10 +public class SwXerciseServiceTest extends JpaTestUtils {
  11 +
  12 + @InjectMocks
  13 + private SwXerciseService underTest;
  14 +
  15 + @Test
  16 + public void test() {
  17 +
  18 + }
  19 +
  20 +}
... ...
src/test/java/net/ziemers/swxercise/ui/RestControllerTest.java 0 → 100644
  1 +++ a/src/test/java/net/ziemers/swxercise/ui/RestControllerTest.java
  1 +package net.ziemers.swxercise.ui;
  2 +
  3 +import net.ziemers.swxercise.ui.RestController;
  4 +import org.junit.Test;
  5 +import org.junit.runner.RunWith;
  6 +import org.mockito.InjectMocks;
  7 +import org.mockito.junit.MockitoJUnitRunner;
  8 +
  9 +@RunWith(MockitoJUnitRunner.class)
  10 +public class RestControllerTest {
  11 +
  12 + @InjectMocks
  13 + private RestController underTest;
  14 +
  15 + @Test
  16 + public void test() {
  17 +
  18 + }
  19 +
  20 +}
... ...