From 063c8a45c19751e086c17d84ff50a265a0d6a705 Mon Sep 17 00:00:00 2001 From: Thomas Rausch Date: Sun, 11 Mar 2018 02:57:27 +0100 Subject: [PATCH] Add template for assignment 1 --- ass1-doc/pom.xml | 36 ++ .../java/dst/ass1/doc/IDocumentQuery.java | 15 + .../dst/ass1/doc/IDocumentRepository.java | 11 + .../dst/ass1/doc/IDocumentServiceFactory.java | 11 + .../ass1/doc/impl/DocumentServiceFactory.java | 22 + .../java/dst/ass1/doc/DocumentTestData.java | 47 ++ .../test/java/dst/ass1/doc/EmbeddedMongo.java | 58 ++ .../java/dst/ass1/doc/IDocumentTestData.java | 18 + .../test/java/dst/ass1/doc/MockMaterial.java | 91 ++++ .../test/java/dst/ass1/doc/MongoService.java | 128 +++++ .../java/dst/ass1/doc/tests/Ass1_4_1Test.java | 84 +++ .../dst/ass1/doc/tests/Ass1_4_2aTest.java | 51 ++ .../dst/ass1/doc/tests/Ass1_4_2bTest.java | 39 ++ .../dst/ass1/doc/tests/Ass1_4_3_01Test.java | 34 ++ .../dst/ass1/doc/tests/Ass1_4_3_02Test.java | 48 ++ .../java/dst/ass1/doc/tests/Ass1_4_Suite.java | 16 + ass1-doc/src/test/resources/documents.json | 182 +++++++ ass1-doc/src/test/resources/logback.xml | 17 + ass1-jpa/pom.xml | 31 ++ .../java/dst/ass1/jpa/dao/GenericDAO.java | 9 + .../java/dst/ass1/jpa/dao/ICourseDAO.java | 14 + .../dst/ass1/jpa/dao/ICoursePlatformDAO.java | 6 + .../java/dst/ass1/jpa/dao/IDAOFactory.java | 24 + .../java/dst/ass1/jpa/dao/IEnrollmentDAO.java | 6 + .../java/dst/ass1/jpa/dao/ILecturerDAO.java | 13 + .../java/dst/ass1/jpa/dao/ILessonDAO.java | 6 + .../java/dst/ass1/jpa/dao/IMaterialDAO.java | 6 + .../dst/ass1/jpa/dao/IMaterialServerDAO.java | 12 + .../java/dst/ass1/jpa/dao/IMembershipDAO.java | 6 + .../java/dst/ass1/jpa/dao/IMetadataDAO.java | 6 + .../dst/ass1/jpa/dao/IParticipantDAO.java | 14 + .../dst/ass1/jpa/dao/impl/DAOFactory.java | 90 ++++ .../ass1/jpa/interceptor/SQLInterceptor.java | 33 ++ .../ass1/jpa/listener/DefaultListener.java | 44 ++ .../java/dst/ass1/jpa/model/CourseStatus.java | 5 + .../java/dst/ass1/jpa/model/IAddress.java | 17 + .../main/java/dst/ass1/jpa/model/ICourse.java | 65 +++ .../dst/ass1/jpa/model/ICoursePlatform.java | 25 + .../java/dst/ass1/jpa/model/IEnrollment.java | 18 + .../dst/ass1/jpa/model/IEnrollmentKey.java | 13 + .../java/dst/ass1/jpa/model/ILecturer.java | 19 + .../main/java/dst/ass1/jpa/model/ILesson.java | 52 ++ .../java/dst/ass1/jpa/model/IMaterial.java | 38 ++ .../dst/ass1/jpa/model/IMaterialServer.java | 30 ++ .../java/dst/ass1/jpa/model/IMembership.java | 24 + .../java/dst/ass1/jpa/model/IMetadata.java | 17 + .../dst/ass1/jpa/model/IModelFactory.java | 30 ++ .../java/dst/ass1/jpa/model/IParticipant.java | 35 ++ .../main/java/dst/ass1/jpa/model/IPerson.java | 17 + .../dst/ass1/jpa/model/impl/ModelFactory.java | 99 ++++ .../java/dst/ass1/jpa/util/Constants.java | 106 ++++ .../src/main/resources/META-INF/Material.xml | 9 + ass1-jpa/src/main/resources/META-INF/orm.xml | 9 + .../main/resources/META-INF/persistence.xml | 24 + ...aseInsensitiveStringCollectionMatcher.java | 52 ++ .../java/dst/ass1/jpa/DatabaseGateway.java | 293 +++++++++++ .../src/test/java/dst/ass1/jpa/ITestData.java | 21 + .../test/java/dst/ass1/jpa/ORMService.java | 173 ++++++ .../ExampleTestWithCustomTestData.java | 68 +++ .../examples/ExampleTestWithDependencies.java | 68 +++ .../dst/ass1/jpa/examples/package-info.java | 5 + .../dst/ass1/jpa/tests/Ass1_1_1_00Test.java | 127 +++++ .../dst/ass1/jpa/tests/Ass1_1_1_01Test.java | 178 +++++++ .../dst/ass1/jpa/tests/Ass1_1_1_02Test.java | 31 ++ .../dst/ass1/jpa/tests/Ass1_1_1_03Test.java | 30 ++ .../dst/ass1/jpa/tests/Ass1_1_1_04Test.java | 30 ++ .../dst/ass1/jpa/tests/Ass1_1_1_05Test.java | 57 ++ .../dst/ass1/jpa/tests/Ass1_1_1_06Test.java | 60 +++ .../dst/ass1/jpa/tests/Ass1_1_1_07Test.java | 86 +++ .../dst/ass1/jpa/tests/Ass1_1_1_08Test.java | 51 ++ .../dst/ass1/jpa/tests/Ass1_1_1_09Test.java | 68 +++ .../dst/ass1/jpa/tests/Ass1_1_1_10Test.java | 98 ++++ .../dst/ass1/jpa/tests/Ass1_1_2_01Test.java | 48 ++ .../dst/ass1/jpa/tests/Ass1_1_2_02Test.java | 54 ++ .../dst/ass1/jpa/tests/Ass1_2_1aTest.java | 55 ++ .../dst/ass1/jpa/tests/Ass1_2_1bTest.java | 46 ++ .../dst/ass1/jpa/tests/Ass1_2_1cTest.java | 62 +++ .../java/dst/ass1/jpa/tests/Ass1_2_2Test.java | 95 ++++ .../dst/ass1/jpa/tests/Ass1_2_3a_01Test.java | 50 ++ .../dst/ass1/jpa/tests/Ass1_2_3a_02Test.java | 69 +++ .../dst/ass1/jpa/tests/Ass1_2_3b_01Test.java | 84 +++ .../dst/ass1/jpa/tests/Ass1_2_3b_02Test.java | 69 +++ .../java/dst/ass1/jpa/tests/Ass1_3_1Test.java | 82 +++ .../java/dst/ass1/jpa/tests/Ass1_3_2Test.java | 72 +++ .../java/dst/ass1/jpa/tests/Ass1_3_3Test.java | 35 ++ .../java/dst/ass1/jpa/tests/Ass1_Suite.java | 16 + .../dst/ass1/jpa/tests/Ass1_TestBase.java | 51 ++ .../java/dst/ass1/jpa/tests/TestData.java | 498 ++++++++++++++++++ .../jpa/tests/UniqueConstraintTester.java | 58 ++ ass1-jpa/src/test/resources/logback.xml | 16 + ass1-kv/pom.xml | 27 + .../java/dst/ass1/kv/ISessionManager.java | 69 +++ .../dst/ass1/kv/ISessionManagerFactory.java | 15 + .../kv/SessionCreationFailedException.java | 25 + .../dst/ass1/kv/SessionNotFoundException.java | 24 + .../ass1/kv/impl/SessionManagerFactory.java | 17 + .../test/java/dst/ass1/kv/RedisCleaner.java | 61 +++ .../java/dst/ass1/kv/tests/Ass1_5_1Test.java | 113 ++++ .../java/dst/ass1/kv/tests/Ass1_5_2Test.java | 51 ++ .../java/dst/ass1/kv/tests/Ass1_5_Suite.java | 13 + ass1-kv/src/test/resources/logback.xml | 14 + ass1-kv/src/test/resources/redis.properties | 4 + pom.xml | 272 ++++++++++ vm/Vagrantfile | 11 + 104 files changed, 5552 insertions(+) create mode 100644 ass1-doc/pom.xml create mode 100644 ass1-doc/src/main/java/dst/ass1/doc/IDocumentQuery.java create mode 100644 ass1-doc/src/main/java/dst/ass1/doc/IDocumentRepository.java create mode 100644 ass1-doc/src/main/java/dst/ass1/doc/IDocumentServiceFactory.java create mode 100644 ass1-doc/src/main/java/dst/ass1/doc/impl/DocumentServiceFactory.java create mode 100644 ass1-doc/src/test/java/dst/ass1/doc/DocumentTestData.java create mode 100644 ass1-doc/src/test/java/dst/ass1/doc/EmbeddedMongo.java create mode 100644 ass1-doc/src/test/java/dst/ass1/doc/IDocumentTestData.java create mode 100644 ass1-doc/src/test/java/dst/ass1/doc/MockMaterial.java create mode 100644 ass1-doc/src/test/java/dst/ass1/doc/MongoService.java create mode 100644 ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_1Test.java create mode 100644 ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_2aTest.java create mode 100644 ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_2bTest.java create mode 100644 ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_3_01Test.java create mode 100644 ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_3_02Test.java create mode 100644 ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_Suite.java create mode 100644 ass1-doc/src/test/resources/documents.json create mode 100644 ass1-doc/src/test/resources/logback.xml create mode 100644 ass1-jpa/pom.xml create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/dao/GenericDAO.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/dao/ICourseDAO.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/dao/ICoursePlatformDAO.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/dao/IDAOFactory.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/dao/IEnrollmentDAO.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/dao/ILecturerDAO.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/dao/ILessonDAO.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/dao/IMaterialDAO.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/dao/IMaterialServerDAO.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/dao/IMembershipDAO.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/dao/IMetadataDAO.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/dao/IParticipantDAO.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/dao/impl/DAOFactory.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/interceptor/SQLInterceptor.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/listener/DefaultListener.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/model/CourseStatus.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/model/IAddress.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/model/ICourse.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/model/ICoursePlatform.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/model/IEnrollment.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/model/IEnrollmentKey.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/model/ILecturer.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/model/ILesson.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/model/IMaterial.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/model/IMaterialServer.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/model/IMembership.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/model/IMetadata.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/model/IModelFactory.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/model/IParticipant.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/model/IPerson.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/model/impl/ModelFactory.java create mode 100644 ass1-jpa/src/main/java/dst/ass1/jpa/util/Constants.java create mode 100644 ass1-jpa/src/main/resources/META-INF/Material.xml create mode 100644 ass1-jpa/src/main/resources/META-INF/orm.xml create mode 100644 ass1-jpa/src/main/resources/META-INF/persistence.xml create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/CaseInsensitiveStringCollectionMatcher.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/DatabaseGateway.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/ITestData.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/ORMService.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/examples/ExampleTestWithCustomTestData.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/examples/ExampleTestWithDependencies.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/examples/package-info.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_00Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_01Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_02Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_03Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_04Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_05Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_06Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_07Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_08Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_09Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_10Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_2_01Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_2_02Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_1aTest.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_1bTest.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_1cTest.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_2Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_3a_01Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_3a_02Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_3b_01Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_3b_02Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_3_1Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_3_2Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_3_3Test.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_Suite.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_TestBase.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/TestData.java create mode 100644 ass1-jpa/src/test/java/dst/ass1/jpa/tests/UniqueConstraintTester.java create mode 100644 ass1-jpa/src/test/resources/logback.xml create mode 100644 ass1-kv/pom.xml create mode 100644 ass1-kv/src/main/java/dst/ass1/kv/ISessionManager.java create mode 100644 ass1-kv/src/main/java/dst/ass1/kv/ISessionManagerFactory.java create mode 100644 ass1-kv/src/main/java/dst/ass1/kv/SessionCreationFailedException.java create mode 100644 ass1-kv/src/main/java/dst/ass1/kv/SessionNotFoundException.java create mode 100644 ass1-kv/src/main/java/dst/ass1/kv/impl/SessionManagerFactory.java create mode 100644 ass1-kv/src/test/java/dst/ass1/kv/RedisCleaner.java create mode 100644 ass1-kv/src/test/java/dst/ass1/kv/tests/Ass1_5_1Test.java create mode 100644 ass1-kv/src/test/java/dst/ass1/kv/tests/Ass1_5_2Test.java create mode 100644 ass1-kv/src/test/java/dst/ass1/kv/tests/Ass1_5_Suite.java create mode 100644 ass1-kv/src/test/resources/logback.xml create mode 100644 ass1-kv/src/test/resources/redis.properties create mode 100644 pom.xml create mode 100644 vm/Vagrantfile diff --git a/ass1-doc/pom.xml b/ass1-doc/pom.xml new file mode 100644 index 0000000..cf0dc1e --- /dev/null +++ b/ass1-doc/pom.xml @@ -0,0 +1,36 @@ + + + + 4.0.0 + + + at.ac.tuwien.infosys.dst + dst + 2018.1 + .. + + + ass1-doc + + jar + + DST :: Assignment 1 :: Document DB + + + + at.ac.tuwien.infosys.dst + ass1-jpa + ${project.version} + + + + org.mongodb + mongodb-driver + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + + + diff --git a/ass1-doc/src/main/java/dst/ass1/doc/IDocumentQuery.java b/ass1-doc/src/main/java/dst/ass1/doc/IDocumentQuery.java new file mode 100644 index 0000000..5c2f57b --- /dev/null +++ b/ass1-doc/src/main/java/dst/ass1/doc/IDocumentQuery.java @@ -0,0 +1,15 @@ +package dst.ass1.doc; + +import java.util.List; + +import org.bson.Document; + +public interface IDocumentQuery { + + Document findByMaterialId(Long materialId); + + List findIdsByType(String typeSubstring); + + List getDocumentStatistics(); + +} diff --git a/ass1-doc/src/main/java/dst/ass1/doc/IDocumentRepository.java b/ass1-doc/src/main/java/dst/ass1/doc/IDocumentRepository.java new file mode 100644 index 0000000..243d1ea --- /dev/null +++ b/ass1-doc/src/main/java/dst/ass1/doc/IDocumentRepository.java @@ -0,0 +1,11 @@ +package dst.ass1.doc; + +import java.util.Map; + +import dst.ass1.jpa.model.IMaterial; + +public interface IDocumentRepository { + + void insert(IMaterial material, Map materialProperties); + +} diff --git a/ass1-doc/src/main/java/dst/ass1/doc/IDocumentServiceFactory.java b/ass1-doc/src/main/java/dst/ass1/doc/IDocumentServiceFactory.java new file mode 100644 index 0000000..1ab0da1 --- /dev/null +++ b/ass1-doc/src/main/java/dst/ass1/doc/IDocumentServiceFactory.java @@ -0,0 +1,11 @@ +package dst.ass1.doc; + +import com.mongodb.client.MongoDatabase; + +public interface IDocumentServiceFactory { + + IDocumentQuery createDocumentQuery(MongoDatabase db); + + IDocumentRepository createDocumentRepository(); + +} diff --git a/ass1-doc/src/main/java/dst/ass1/doc/impl/DocumentServiceFactory.java b/ass1-doc/src/main/java/dst/ass1/doc/impl/DocumentServiceFactory.java new file mode 100644 index 0000000..28f3ba6 --- /dev/null +++ b/ass1-doc/src/main/java/dst/ass1/doc/impl/DocumentServiceFactory.java @@ -0,0 +1,22 @@ +package dst.ass1.doc.impl; + +import com.mongodb.client.MongoDatabase; + +import dst.ass1.doc.IDocumentQuery; +import dst.ass1.doc.IDocumentRepository; +import dst.ass1.doc.IDocumentServiceFactory; + +public class DocumentServiceFactory implements IDocumentServiceFactory { + + @Override + public IDocumentQuery createDocumentQuery(MongoDatabase db) { + // TODO + return null; + } + + @Override + public IDocumentRepository createDocumentRepository() { + // TODO + return null; + } +} diff --git a/ass1-doc/src/test/java/dst/ass1/doc/DocumentTestData.java b/ass1-doc/src/test/java/dst/ass1/doc/DocumentTestData.java new file mode 100644 index 0000000..0f2e5cd --- /dev/null +++ b/ass1-doc/src/test/java/dst/ass1/doc/DocumentTestData.java @@ -0,0 +1,47 @@ +package dst.ass1.doc; + +import java.io.IOException; +import java.net.URL; +import java.util.List; +import java.util.Objects; +import java.util.Scanner; + +import org.bson.Document; + +import com.mongodb.client.MongoDatabase; + +import dst.ass1.jpa.util.Constants; + +public class DocumentTestData implements IDocumentTestData { + + private String documentResource; + + public DocumentTestData() { + this("documents.json"); + } + + public DocumentTestData(String documentResource) { + this.documentResource = documentResource; + } + + @SuppressWarnings("unchecked") + @Override + public void insertTestData(MongoDatabase db) throws IOException { + URL resource = Objects.requireNonNull(getDocumentsResource()); + + String testDataJson = readFully(resource); + List documents = Document.parse(testDataJson).get("documents", List.class); + db.getCollection(Constants.COLL_MATERIAL_DATA).insertMany(documents); + } + + private URL getDocumentsResource() { + return getClass().getClassLoader().getResource(documentResource); + } + + private String readFully(URL resource) throws IOException { + try (Scanner scanner = new Scanner(resource.openStream())) { + return scanner.useDelimiter("\\Z").next(); + } + } + +} diff --git a/ass1-doc/src/test/java/dst/ass1/doc/EmbeddedMongo.java b/ass1-doc/src/test/java/dst/ass1/doc/EmbeddedMongo.java new file mode 100644 index 0000000..4f484b6 --- /dev/null +++ b/ass1-doc/src/test/java/dst/ass1/doc/EmbeddedMongo.java @@ -0,0 +1,58 @@ +package dst.ass1.doc; + +import java.io.IOException; +import java.net.BindException; +import java.net.ServerSocket; + +import org.junit.rules.ExternalResource; + +import de.flapdoodle.embed.mongo.config.IMongodConfig; +import de.flapdoodle.embed.mongo.config.MongodConfigBuilder; +import de.flapdoodle.embed.mongo.config.Net; +import de.flapdoodle.embed.mongo.distribution.IFeatureAwareVersion; +import de.flapdoodle.embed.mongo.distribution.Version; +import de.flapdoodle.embed.mongo.tests.MongodForTestsFactory; + +/** + * JUnit rule that creates an in-memory instance of MongoDB using the flapdoodle Embedded MongoDB. + */ +public class EmbeddedMongo extends ExternalResource { + + private MongodForTestsFactory mongod; + + @Override + protected void before() throws Throwable { + requirePort(); + mongod = new MongodFactory(); // starts process in constructor + } + + @Override + protected void after() { + if (mongod != null) { + mongod.shutdown(); + } + } + + private void requirePort() throws IOException, IllegalStateException { + try (ServerSocket ignore = new ServerSocket(27017)) { + // ignore + } catch (BindException e) { + throw new IllegalStateException("Could not bind port 27017 which is necessary to run the MongoDB tests", e); + } + } + + public static class MongodFactory extends MongodForTestsFactory { + + public MongodFactory() throws IOException { + super(Version.Main.V3_5); + } + + @Override + protected IMongodConfig newMongodConfig(IFeatureAwareVersion version) throws IOException { + return new MongodConfigBuilder() + .net(new Net(27017, false)) + .version(version) + .build(); + } + } +} diff --git a/ass1-doc/src/test/java/dst/ass1/doc/IDocumentTestData.java b/ass1-doc/src/test/java/dst/ass1/doc/IDocumentTestData.java new file mode 100644 index 0000000..f2a57a3 --- /dev/null +++ b/ass1-doc/src/test/java/dst/ass1/doc/IDocumentTestData.java @@ -0,0 +1,18 @@ +package dst.ass1.doc; + +import com.mongodb.client.MongoDatabase; + +// DO NOT MODIFY THIS CLASS. + +/** + * The IDocumentTestData interface works like the ITestData as introduced in ass1-jpa only for the {@link MongoService}. + */ +public interface IDocumentTestData { + /** + * Inserts the data into the given MongoDatabase instance. + * + * @param db the mongo database instance + * @throws Exception if the insertion failed for some reason + */ + void insertTestData(MongoDatabase db) throws Exception; +} diff --git a/ass1-doc/src/test/java/dst/ass1/doc/MockMaterial.java b/ass1-doc/src/test/java/dst/ass1/doc/MockMaterial.java new file mode 100644 index 0000000..be4c33e --- /dev/null +++ b/ass1-doc/src/test/java/dst/ass1/doc/MockMaterial.java @@ -0,0 +1,91 @@ +package dst.ass1.doc; + +import java.util.Collection; +import java.util.Date; + +import dst.ass1.jpa.model.ILesson; +import dst.ass1.jpa.model.IMaterial; +import dst.ass1.jpa.model.IMaterialServer; + +/** + * Mock implementation of the IMaterial entity. Avoid dependencies to the implementation of ass1-jpa. + */ +public class MockMaterial implements IMaterial { + + private Long id; + private String type; + + public MockMaterial(Long id, String type) { + this.id = id; + this.type = type; + } + + @Override + public Long getId() { + return id; + } + + @Override + public void setId(Long id) { + this.id = id; + } + + @Override + public String getType() { + return type; + } + + @Override + public void setType(String type) { + this.type = type; + } + + @Override + public String getUrn() { + return null; + } + + @Override + public void setUrn(String urn) { + } + + @Override + public Date getUploaded() { + return null; + } + + @Override + public void setUploaded(Date uploaded) { + } + + @Override + public Date getLastUpdate() { + return null; + } + + @Override + public void setLastUpdate(Date lastUpdate) { + } + + @Override + public ILesson getLesson() { + return null; + } + + @Override + public void setLesson(ILesson lesson) { + } + + @Override + public Collection getMaterialServers() { + return null; + } + + @Override + public void setMaterialServers(Collection materialServers) { + } + + @Override + public void addMaterialServer(IMaterialServer materialServer) { + } +} diff --git a/ass1-doc/src/test/java/dst/ass1/doc/MongoService.java b/ass1-doc/src/test/java/dst/ass1/doc/MongoService.java new file mode 100644 index 0000000..6640571 --- /dev/null +++ b/ass1-doc/src/test/java/dst/ass1/doc/MongoService.java @@ -0,0 +1,128 @@ +package dst.ass1.doc; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import org.bson.Document; +import org.junit.rules.ExternalResource; + +import com.mongodb.MongoClient; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; + +import dst.ass1.doc.impl.DocumentServiceFactory; +import dst.ass1.jpa.util.Constants; + +// DO NOT MODIFY THIS CLASS. + +/** + * The MongoService class is used as a JUnit rule, that fulfills the same tasks as the ORMService in ass1-jpa, and works + * very similarly. + */ +public class MongoService extends ExternalResource { + + private IDocumentTestData testData; + private boolean insertTestData; + private boolean clearTestData; + + private MongoClient mongoClient; + private MongoDatabase mongoDatabase; + + private IDocumentServiceFactory documentServiceFactory; + private IDocumentRepository documentRepository; + private IDocumentQuery documentQuery; + + public MongoService() { + this(null, false, true); + } + + public MongoService(IDocumentTestData testData) { + this(testData, true, true); + } + + public MongoService(IDocumentTestData testData, boolean insertTestData, boolean clearTestData) { + this.testData = testData; + this.insertTestData = insertTestData; + this.clearTestData = clearTestData; + } + + public MongoClient getMongoClient() { + return mongoClient; + } + + public MongoDatabase getMongoDatabase() { + return mongoDatabase; + } + + public IDocumentServiceFactory getDocumentServiceFactory() { + return documentServiceFactory; + } + + public IDocumentRepository getDocumentRepository() { + return documentRepository; + } + + public IDocumentQuery getDocumentQuery() { + return documentQuery; + } + + @Override + protected void before() throws Throwable { + setUpMongo(); + + if (insertTestData && testData != null) { + insertData(testData); + } + } + + @Override + protected void after() { + try { + if (clearTestData) { + clearData(); + } + } finally { + tearDownMongo(); + } + } + + private void setUpMongo() { + mongoClient = new MongoClient("127.0.0.1"); + mongoDatabase = mongoClient.getDatabase(Constants.MONGO_DB_NAME); + + documentServiceFactory = new DocumentServiceFactory(); + documentRepository = documentServiceFactory.createDocumentRepository(); + + if (documentRepository == null) { + throw new IllegalStateException("DocumentRepository returned from factory is null"); + } + + documentQuery = documentServiceFactory.createDocumentQuery(mongoDatabase); + } + + private void tearDownMongo() { + mongoClient.close(); + } + + private void insertData(IDocumentTestData testData) throws Exception { + testData.insertTestData(getMongoDatabase()); + } + + private void clearData() { + getMongoDatabase().drop(); + } + + public static Stream stream(MongoCollection collection) { + return StreamSupport.stream(collection.find().spliterator(), false); + } + + public static Map idMap(MongoCollection collection, Function idFunction) { + return stream(collection).collect(Collectors.toMap(idFunction, Function.identity())); + } + +} diff --git a/ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_1Test.java b/ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_1Test.java new file mode 100644 index 0000000..a2342dc --- /dev/null +++ b/ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_1Test.java @@ -0,0 +1,84 @@ +package dst.ass1.doc.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.bson.Document; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; + +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; + +import dst.ass1.doc.EmbeddedMongo; +import dst.ass1.doc.IDocumentRepository; +import dst.ass1.doc.MockMaterial; +import dst.ass1.doc.MongoService; +import dst.ass1.jpa.util.Constants; + +public class Ass1_4_1Test { + + @ClassRule + public static EmbeddedMongo embeddedMongo = new EmbeddedMongo(); + + @Rule + public MongoService mongo = new MongoService(); + + private MockMaterial m1; + private MockMaterial m2; + + private Map m1Properties; + private Map m2Properties; + + @Before + public void setUp() throws Exception { + m1 = new MockMaterial(1L, "testType"); + m2 = new MockMaterial(2L, "testType2"); + + m1Properties = new HashMap<>(); + m1Properties.put("1337", "7331"); + m1Properties.put("Foo", "Bar"); + m1Properties.put("Complex", Arrays.asList(1, 2, 3, 5, 8)); + + m2Properties = new HashMap<>(); + m2Properties.put("123456", "654321"); + m2Properties.put("F00", "B@r"); + m2Properties.put("Complex2", Arrays.asList(4, 6, 7, 9)); + } + + @Test + public void insert_insertsDocumentsCorrectly() throws Exception { + IDocumentRepository documentRepository = mongo.getDocumentRepository(); + MongoDatabase mongoDatabase = mongo.getMongoDatabase(); + + documentRepository.insert(m1, m1Properties); + documentRepository.insert(m2, m2Properties); + + MongoCollection collection = mongoDatabase.getCollection(Constants.COLL_MATERIAL_DATA); + Map map = MongoService.idMap(collection, d -> d.getLong(Constants.I_MATERIAL)); + + assertNotNull(map); + assertEquals(2, map.size()); + + Document document1 = map.get(1L); + assertEquals(1L, document1.get(Constants.I_MATERIAL)); + assertEquals("testType", document1.get(Constants.M_MATERIAL_TYPE)); + assertEquals("7331", document1.get("1337")); + assertEquals("Bar", document1.get("Foo")); + assertEquals(Arrays.asList(1, 2, 3, 5, 8), document1.get("Complex")); + + Document document2 = map.get(2L); + assertEquals(2L, document2.get(Constants.I_MATERIAL)); + assertEquals("testType2", document2.get(Constants.M_MATERIAL_TYPE)); + assertEquals("654321", document2.get("123456")); + assertEquals("B@r", document2.get("F00")); + assertEquals(Arrays.asList(4, 6, 7, 9), document2.get("Complex2")); + } + +} diff --git a/ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_2aTest.java b/ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_2aTest.java new file mode 100644 index 0000000..5a3968f --- /dev/null +++ b/ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_2aTest.java @@ -0,0 +1,51 @@ +package dst.ass1.doc.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.util.List; + +import org.bson.Document; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; + +import dst.ass1.doc.DocumentTestData; +import dst.ass1.doc.EmbeddedMongo; +import dst.ass1.doc.IDocumentQuery; +import dst.ass1.doc.MongoService; +import dst.ass1.jpa.util.Constants; + +public class Ass1_4_2aTest { + + @ClassRule + public static EmbeddedMongo embeddedMongo = new EmbeddedMongo(); + + @Rule + public MongoService mongo = new MongoService(new DocumentTestData()); + + @SuppressWarnings("unchecked") + @Test + public void findByMaterialId_returnsCorrectDocument() { + IDocumentQuery documentQuery = mongo.getDocumentQuery(); + + Document material = documentQuery.findByMaterialId(2L); + assertEquals(2L, material.getLong(Constants.I_MATERIAL), 0); + assertEquals("quiz", material.getString(Constants.M_MATERIAL_TYPE)); + assertEquals("text", material.getString("quiz_type")); + + List questions = (List) material.get("questions"); + assertNotNull(questions); + assertEquals(7, questions.size()); + assertEquals("How exactly does the rabies pathogen work?", questions.get(3).get("text")); + assertEquals(10, questions.get(3).get("points")); + } + + @Test + public void findByMaterialId_withInvalidId_returnsNull() throws Exception { + Document material = mongo.getDocumentQuery().findByMaterialId(1337L); + assertNull(material); + } + +} diff --git a/ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_2bTest.java b/ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_2bTest.java new file mode 100644 index 0000000..08cb6aa --- /dev/null +++ b/ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_2bTest.java @@ -0,0 +1,39 @@ +package dst.ass1.doc.tests; + +import static org.hamcrest.Matchers.hasItems; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; + +import dst.ass1.doc.DocumentTestData; +import dst.ass1.doc.EmbeddedMongo; +import dst.ass1.doc.MongoService; + +public class Ass1_4_2bTest { + + @ClassRule + public static EmbeddedMongo embeddedMongo = new EmbeddedMongo(); + + @Rule + public MongoService mongo = new MongoService(new DocumentTestData()); + + @Test + public void findIdsByType_returnsCorrectMaterialIds() throws Exception { + List quizMaterialIds = mongo.getDocumentQuery().findIdsByType("quiz"); + assertThat(quizMaterialIds, hasItems(1L, 2L, 3L, 5L)); + } + + @Test + public void findIdsByType_withNonExistingType_returnsNoMaterialIds() throws Exception { + List quizMaterialIds = mongo.getDocumentQuery().findIdsByType("NONEXISTING"); + assertNotNull(quizMaterialIds); + assertTrue(quizMaterialIds.isEmpty()); + } + +} diff --git a/ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_3_01Test.java b/ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_3_01Test.java new file mode 100644 index 0000000..dab7867 --- /dev/null +++ b/ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_3_01Test.java @@ -0,0 +1,34 @@ +package dst.ass1.doc.tests; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.bson.Document; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; + +import dst.ass1.doc.EmbeddedMongo; +import dst.ass1.doc.MongoService; +import dst.ass1.jpa.util.Constants; + +public class Ass1_4_3_01Test { + + @ClassRule + public static EmbeddedMongo embeddedMongo = new EmbeddedMongo(); + + @Rule + public MongoService mongo = new MongoService(db -> { + db.createCollection(Constants.COLL_MATERIAL_DATA); // make sure the empty collection exists + }); + + @Test + public void getDocumentStatistics_withEmptyData_returnsEmptyStatistics() throws Exception { + List documentStatistics = mongo.getDocumentQuery().getDocumentStatistics(); + assertNotNull(documentStatistics); + assertTrue(documentStatistics.isEmpty()); + } + +} diff --git a/ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_3_02Test.java b/ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_3_02Test.java new file mode 100644 index 0000000..7e56821 --- /dev/null +++ b/ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_3_02Test.java @@ -0,0 +1,48 @@ +package dst.ass1.doc.tests; + +import static org.hamcrest.CoreMatchers.hasItems; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.bson.Document; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; + +import dst.ass1.doc.DocumentTestData; +import dst.ass1.doc.EmbeddedMongo; +import dst.ass1.doc.MongoService; + +public class Ass1_4_3_02Test { + + @ClassRule + public static EmbeddedMongo embeddedMongo = new EmbeddedMongo(); + + @Rule + public MongoService mongo = new MongoService(new DocumentTestData()); + + @Test + public void getDocumentStatistics_returnsCorrectStatistics() throws Exception { + List documentStatistics = mongo.getDocumentQuery().getDocumentStatistics(); + assertNotNull(documentStatistics); + assertEquals(3, documentStatistics.size()); + + List types = documentStatistics.stream().map(d -> d.getString("_id")).collect(Collectors.toList()); + assertThat("expected three aggregation keys", types, hasItems("single-choice", "multiple-choice", "text")); + + Map dsMap = documentStatistics.stream().collect(Collectors.toMap( + d -> d.getString("_id"), + d -> d.getDouble("value")) + ); + + assertEquals(4.0d, dsMap.get("single-choice"), 0); + assertEquals(1.0d, dsMap.get("multiple-choice"), 0); + assertEquals(7.0d, dsMap.get("text"), 0); + } + +} diff --git a/ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_Suite.java b/ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_Suite.java new file mode 100644 index 0000000..475e086 --- /dev/null +++ b/ass1-doc/src/test/java/dst/ass1/doc/tests/Ass1_4_Suite.java @@ -0,0 +1,16 @@ +package dst.ass1.doc.tests; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + Ass1_4_1Test.class, + Ass1_4_2aTest.class, + Ass1_4_2bTest.class, + Ass1_4_3_01Test.class, + Ass1_4_3_02Test.class +}) +public class Ass1_4_Suite { +} diff --git a/ass1-doc/src/test/resources/documents.json b/ass1-doc/src/test/resources/documents.json new file mode 100644 index 0000000..38ea42c --- /dev/null +++ b/ass1-doc/src/test/resources/documents.json @@ -0,0 +1,182 @@ +{ + "documents": [ + { + "material_id": NumberLong(1), + "type": "quiz", + "quiz_type": "single-choice", + "questions": [ + { + "text": "What is the answer to life, the universe and everything?", + "choices": [ + { + "text": "42", + "points": 1 + }, + { + "text": "Leeloo Minai Lekatariba-Lamina-Tchai Ekbat De Sebat", + "points": 0 + } + ] + }, + { + "text": "Only you and DEAD people can read Hex. How many perople can read Hex?", + "choices": [ + { + "text": "1", + "points": 0 + }, + { + "text": "0", + "points": 0 + }, + { + "text": "57006", + "points": 1 + }, + { + "text": "Dead people can't read!", + "points": 0 + } + ] + }, + { + "text": "What are the first 6 numbers of pi?", + "choices": [ + { + "text": "It's spelled pie!", + "points": 0 + }, + { + "text": "There aren't any numbers in pie!", + "points": 0 + }, + { + "text": "3.14159", + "points": 1 + }, + { + "text": "3.14158", + "points": 0 + }, + { + "text": "3.14157", + "points": 0 + } + ] + } + ] + }, + { + "material_id": NumberLong(2), + "type": "quiz", + "quiz_type": "text", + "questions": [ + { + "text": "Explain the concept of life.", + "points": 30 + }, + { + "text": "Explain what Shakespeare thought of the uneducated groundlings who gathered during every performance?", + "points": 10 + }, + { + "text": "Explain what happens to the cell cycle if both p53 alleles are mutated?", + "points": 20 + }, + { + "text": "How exactly does the rabies pathogen work?", + "points": 10 + }, + { + "text": "Why do we use gradient descent to solve optimization problems, when we can just derive the function and make it equals to zero?", + "points": 10 + }, + { + "text": "What is the suns 11 years cycle and how does it work?", + "points": 10 + }, + { + "text": "How do magnets exist without violating the law of conservation of energy?", + "points": 10 + } + ] + }, + { + "material_id": NumberLong(3), + "type": "quiz", + "quiz_type": "multiple-choice", + "questions": [ + { + "text": "i is an initialized int-variable. Which Java-expressions are side-effect free?", + "choices": [ + { + "text": "i >> 2", + "points": 25 + }, + { + "text": "i++", + "points": 0 + }, + { + "text": "i * i", + "points": 25 + }, + { + "text": "i *= i", + "points": 0 + }, + { + "text": "i > 0 ? i : -i", + "points": 25 + }, + { + "text": "i > 0 ? i & 1 : i | 1", + "points": 25 + } + ] + } + ] + }, + { + "material_id": NumberLong(4), + "type": "description", + "text": "This is just some random description in order to have some other types than quizes ;)" + }, + { + "material_id": NumberLong(5), + "type": "quiz", + "quiz_type": "single-choice", + "questions": [ + { + "text": "How many planets are in our solar system?", + "choices": [ + { + "text": "5", + "points": 0 + }, + { + "text": "6", + "points": 0 + }, + { + "text": "7", + "points": 0 + }, + { + "text": "8", + "points": 1 + }, + { + "text": "9", + "points": 0 + }, + { + "text": "10", + "points": 0 + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/ass1-doc/src/test/resources/logback.xml b/ass1-doc/src/test/resources/logback.xml new file mode 100644 index 0000000..698878a --- /dev/null +++ b/ass1-doc/src/test/resources/logback.xml @@ -0,0 +1,17 @@ + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} - %highlight(%5p) [%12.12thread] %cyan(%-40.40logger{39}): %m%n + + + + + + + + + + + diff --git a/ass1-jpa/pom.xml b/ass1-jpa/pom.xml new file mode 100644 index 0000000..adf9c1c --- /dev/null +++ b/ass1-jpa/pom.xml @@ -0,0 +1,31 @@ + + + + 4.0.0 + + + at.ac.tuwien.infosys.dst + dst + 2018.1 + .. + + + ass1-jpa + + jar + + DST :: Assignment 1 :: JPA + + + + org.hibernate + hibernate-core + + + com.h2database + h2 + + + + diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/dao/GenericDAO.java b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/GenericDAO.java new file mode 100644 index 0000000..4cb4180 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/GenericDAO.java @@ -0,0 +1,9 @@ +package dst.ass1.jpa.dao; + +import java.util.List; + +public interface GenericDAO { + T findById(Long id); + + List findAll(); +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/dao/ICourseDAO.java b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/ICourseDAO.java new file mode 100644 index 0000000..ecea2a6 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/ICourseDAO.java @@ -0,0 +1,14 @@ +package dst.ass1.jpa.dao; + +import java.util.Collection; +import java.util.Date; + +import dst.ass1.jpa.model.ICourse; + +public interface ICourseDAO extends GenericDAO { + + Collection findOngoingAndFreeCoursesForPlatform(String platformName); + + Collection findNonCancelledCoursesBetweenStartAndEnd(Date start, Date end); + +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/dao/ICoursePlatformDAO.java b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/ICoursePlatformDAO.java new file mode 100644 index 0000000..7093a5f --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/ICoursePlatformDAO.java @@ -0,0 +1,6 @@ +package dst.ass1.jpa.dao; + +import dst.ass1.jpa.model.ICoursePlatform; + +public interface ICoursePlatformDAO extends GenericDAO { +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IDAOFactory.java b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IDAOFactory.java new file mode 100644 index 0000000..a4eff1e --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IDAOFactory.java @@ -0,0 +1,24 @@ +package dst.ass1.jpa.dao; + +public interface IDAOFactory { + + IMembershipDAO createMembershipDAO(); + + IParticipantDAO createParticipantDAO(); + + ILessonDAO createLessonDAO(); + + ILecturerDAO createLecturerDAO(); + + IEnrollmentDAO createEnrollmentDAO(); + + ICourseDAO createCourseDAO(); + + IMaterialDAO createMaterialDAO(); + + IMaterialServerDAO createMaterialServerDAO(); + + IMetadataDAO createMetadataDAO(); + + ICoursePlatformDAO createCoursePlatformDAO(); +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IEnrollmentDAO.java b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IEnrollmentDAO.java new file mode 100644 index 0000000..03f7574 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IEnrollmentDAO.java @@ -0,0 +1,6 @@ +package dst.ass1.jpa.dao; + +import dst.ass1.jpa.model.IEnrollment; + +public interface IEnrollmentDAO extends GenericDAO { +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/dao/ILecturerDAO.java b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/ILecturerDAO.java new file mode 100644 index 0000000..a64ea67 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/ILecturerDAO.java @@ -0,0 +1,13 @@ +package dst.ass1.jpa.dao; + +import java.util.Map; + +import dst.ass1.jpa.model.ICourse; +import dst.ass1.jpa.model.ILecturer; +import dst.ass1.jpa.model.ILesson; + +public interface ILecturerDAO extends GenericDAO { + + Map findUpcomingLessonForLecturersOfCourse(ICourse course); + +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/dao/ILessonDAO.java b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/ILessonDAO.java new file mode 100644 index 0000000..128a141 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/ILessonDAO.java @@ -0,0 +1,6 @@ +package dst.ass1.jpa.dao; + +import dst.ass1.jpa.model.ILesson; + +public interface ILessonDAO extends GenericDAO { +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IMaterialDAO.java b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IMaterialDAO.java new file mode 100644 index 0000000..f53418b --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IMaterialDAO.java @@ -0,0 +1,6 @@ +package dst.ass1.jpa.dao; + +import dst.ass1.jpa.model.IMaterial; + +public interface IMaterialDAO extends GenericDAO { +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IMaterialServerDAO.java b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IMaterialServerDAO.java new file mode 100644 index 0000000..c98d783 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IMaterialServerDAO.java @@ -0,0 +1,12 @@ +package dst.ass1.jpa.dao; + +import java.util.Collection; + +import dst.ass1.jpa.model.ICourse; +import dst.ass1.jpa.model.IMaterialServer; + +public interface IMaterialServerDAO extends GenericDAO { + + Collection findMaterialServersForCourse(ICourse course); + +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IMembershipDAO.java b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IMembershipDAO.java new file mode 100644 index 0000000..82d3d80 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IMembershipDAO.java @@ -0,0 +1,6 @@ +package dst.ass1.jpa.dao; + +import dst.ass1.jpa.model.IMembership; + +public interface IMembershipDAO extends GenericDAO { +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IMetadataDAO.java b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IMetadataDAO.java new file mode 100644 index 0000000..5e40eb8 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IMetadataDAO.java @@ -0,0 +1,6 @@ +package dst.ass1.jpa.dao; + +import dst.ass1.jpa.model.IMetadata; + +public interface IMetadataDAO extends GenericDAO { +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IParticipantDAO.java b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IParticipantDAO.java new file mode 100644 index 0000000..c2e45d4 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/IParticipantDAO.java @@ -0,0 +1,14 @@ +package dst.ass1.jpa.dao; + +import dst.ass1.jpa.model.IParticipant; + +public interface IParticipantDAO extends GenericDAO { + + /** + * Returns the participant associated with the given email. Returns null if the email does not exist. + * + * @param email the email address + * @return the participant or null + */ + IParticipant findByEmail(String email); +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/dao/impl/DAOFactory.java b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/impl/DAOFactory.java new file mode 100644 index 0000000..9c7ad55 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/dao/impl/DAOFactory.java @@ -0,0 +1,90 @@ +package dst.ass1.jpa.dao.impl; + +import javax.persistence.EntityManager; + +import dst.ass1.jpa.dao.ICourseDAO; +import dst.ass1.jpa.dao.ICoursePlatformDAO; +import dst.ass1.jpa.dao.IDAOFactory; +import dst.ass1.jpa.dao.IEnrollmentDAO; +import dst.ass1.jpa.dao.ILecturerDAO; +import dst.ass1.jpa.dao.ILessonDAO; +import dst.ass1.jpa.dao.IMaterialDAO; +import dst.ass1.jpa.dao.IMaterialServerDAO; +import dst.ass1.jpa.dao.IMembershipDAO; +import dst.ass1.jpa.dao.IMetadataDAO; +import dst.ass1.jpa.dao.IParticipantDAO; + +public class DAOFactory implements IDAOFactory { + + /* + * HINT: When using the org.hibernate.Session in your DAOs you can extract it from the EntityManager reference with + * e.g., em.unwrap(org.hibernate.Session.class). Do not store this org.hibernate.Session in your DAOs, but unwrap it + * every time you actually need it. + */ + + private EntityManager em; + + public DAOFactory(EntityManager em) { + this.em = em; + } + + @Override + public IMembershipDAO createMembershipDAO() { + // TODO + return null; + } + + @Override + public IParticipantDAO createParticipantDAO() { + // TODO + return null; + } + + @Override + public ILessonDAO createLessonDAO() { + // TODO + return null; + } + + @Override + public ILecturerDAO createLecturerDAO() { + // TODO + return null; + } + + @Override + public IEnrollmentDAO createEnrollmentDAO() { + // TODO + return null; + } + + @Override + public ICourseDAO createCourseDAO() { + // TODO + return null; + } + + @Override + public IMaterialDAO createMaterialDAO() { + // TODO + return null; + } + + @Override + public IMaterialServerDAO createMaterialServerDAO() { + // TODO + return null; + } + + @Override + public IMetadataDAO createMetadataDAO() { + // TODO + return null; + } + + @Override + public ICoursePlatformDAO createCoursePlatformDAO() { + // TODO + return null; + } +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/interceptor/SQLInterceptor.java b/ass1-jpa/src/main/java/dst/ass1/jpa/interceptor/SQLInterceptor.java new file mode 100644 index 0000000..16baccb --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/interceptor/SQLInterceptor.java @@ -0,0 +1,33 @@ +package dst.ass1.jpa.interceptor; + +import org.hibernate.EmptyInterceptor; + +public class SQLInterceptor extends EmptyInterceptor { + + private static final long serialVersionUID = -3082243834965597947L; + + @Override + public String onPrepareStatement(String sql) { + // TODO + return sql; + } + + public static void resetCounter() { + // TODO + } + + public static int getSelectCount() { + // TODO + return -1; + } + + /** + * If the verbose argument is set, the interceptor prints the intercepted SQL statements to System.out. + * + * @param verbose whether or not to be verbose + */ + public static void setVerbose(boolean verbose) { + // TODO + } + +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/listener/DefaultListener.java b/ass1-jpa/src/main/java/dst/ass1/jpa/listener/DefaultListener.java new file mode 100644 index 0000000..bd3a7bf --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/listener/DefaultListener.java @@ -0,0 +1,44 @@ +package dst.ass1.jpa.listener; + + +public class DefaultListener { + + // TODO + + public static int getLoadOperations() { + // TODO + return -1; + } + + public static int getUpdateOperations() { + // TODO + return -1; + } + + public static int getRemoveOperations() { + // TODO + return -1; + } + + public static int getPersistOperations() { + // TODO + return -1; + } + + public static long getOverallTimeToPersist() { + // TODO + return -1; + } + + public static double getAverageTimeToPersist() { + // TODO + return -1; + } + + /** + * Clears the internal data structures that are used for storing the operations. + */ + public static void clear() { + // TODO + } +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/model/CourseStatus.java b/ass1-jpa/src/main/java/dst/ass1/jpa/model/CourseStatus.java new file mode 100644 index 0000000..efc8123 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/model/CourseStatus.java @@ -0,0 +1,5 @@ +package dst.ass1.jpa.model; + +public enum CourseStatus { + CREATED, ONGOING, FINISHED, CANCELLED +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/model/IAddress.java b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IAddress.java new file mode 100644 index 0000000..efc9fa7 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IAddress.java @@ -0,0 +1,17 @@ +package dst.ass1.jpa.model; + +public interface IAddress { + + String getStreet(); + + void setStreet(String street); + + String getCity(); + + void setCity(String city); + + String getZipCode(); + + void setZipCode(String zipCode); + +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/model/ICourse.java b/ass1-jpa/src/main/java/dst/ass1/jpa/model/ICourse.java new file mode 100644 index 0000000..ae29701 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/model/ICourse.java @@ -0,0 +1,65 @@ +package dst.ass1.jpa.model; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Date; + +public interface ICourse { + + Long getId(); + + void setId(Long id); + + String getName(); + + void setName(String name); + + Integer getCapacity(); + + void setCapacity(Integer capacity); + + Boolean getPremium(); + + void setPremium(Boolean premium); + + BigDecimal getCost(); + + void setCost(BigDecimal cost); + + CourseStatus getStatus(); + + void setStatus(CourseStatus status); + + Date getStart(); + + void setStart(Date start); + + Date getEnd(); + + void setEnd(Date end); + + ICoursePlatform getCoursePlatform(); + + void setCoursePlatform(ICoursePlatform coursePlatform); + + ILecturer getLecturer(); + + void setLecturer(ILecturer lecturer); + + Collection getLessons(); + + void setLessons(Collection lessons); + + void addLesson(ILesson lesson); + + IMetadata getMetadata(); + + void setMetadata(IMetadata metadata); + + Collection getEnrollments(); + + void setEnrollments(Collection enrollments); + + void addEnrollment(IEnrollment enrollment); + +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/model/ICoursePlatform.java b/ass1-jpa/src/main/java/dst/ass1/jpa/model/ICoursePlatform.java new file mode 100644 index 0000000..107c9a3 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/model/ICoursePlatform.java @@ -0,0 +1,25 @@ +package dst.ass1.jpa.model; + +import java.util.Collection; + +public interface ICoursePlatform { + + Long getId(); + + void setId(Long id); + + String getName(); + + void setName(String name); + + String getUrl(); + + void setUrl(String url); + + Collection getMaterialServers(); + + void setMaterialServers(Collection materialServers); + + void addMaterialServer(IMaterialServer materialServer); + +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/model/IEnrollment.java b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IEnrollment.java new file mode 100644 index 0000000..8182457 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IEnrollment.java @@ -0,0 +1,18 @@ +package dst.ass1.jpa.model; + +import java.util.Date; + +public interface IEnrollment { + + IEnrollmentKey getId(); + + void setId(IEnrollmentKey id); + + Date getEnrolledAt(); + + void setEnrolledAt(Date date); + + Boolean getPaid(); + + void setPaid(Boolean paid); +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/model/IEnrollmentKey.java b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IEnrollmentKey.java new file mode 100644 index 0000000..bdde636 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IEnrollmentKey.java @@ -0,0 +1,13 @@ +package dst.ass1.jpa.model; + +public interface IEnrollmentKey { + + IParticipant getParticipant(); + + void setParticipant(IParticipant participant); + + ICourse getCourse(); + + void setCourse(ICourse course); + +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/model/ILecturer.java b/ass1-jpa/src/main/java/dst/ass1/jpa/model/ILecturer.java new file mode 100644 index 0000000..bbaf39c --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/model/ILecturer.java @@ -0,0 +1,19 @@ +package dst.ass1.jpa.model; + +import java.util.Collection; + +public interface ILecturer extends IPerson { + + Collection getCourses(); + + void setCourses(Collection courses); + + void addCourse(ICourse course); + + Collection getLessons(); + + void setLessons(Collection lessons); + + void addLesson(ILesson lesson); + +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/model/ILesson.java b/ass1-jpa/src/main/java/dst/ass1/jpa/model/ILesson.java new file mode 100644 index 0000000..1ec50c5 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/model/ILesson.java @@ -0,0 +1,52 @@ +package dst.ass1.jpa.model; + +import java.util.Collection; +import java.util.Date; + +public interface ILesson { + + Long getId(); + + void setId(Long id); + + String getDescription(); + + void setDescription(String description); + + Date getStart(); + + void setStart(Date start); + + Date getEnd(); + + void setEnd(Date end); + + ICourse getCourse(); + + void setCourse(ICourse course); + + Collection getLecturers(); + + void setLecturers(Collection lecturers); + + void addLecturer(ILecturer lecturer); + + Collection getRequiredLessons(); + + void setRequiredLessons(Collection requiredLessons); + + void addRequiredLesson(ILesson lesson); + + Collection getRequiredByLessons(); + + void setRequiredByLessons(Collection requiredByLessons); + + void addRequiredByLesson(ILesson lesson); + + Collection getMaterials(); + + void setMaterials(Collection materials); + + void addMaterial(IMaterial material); + +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/model/IMaterial.java b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IMaterial.java new file mode 100644 index 0000000..968abbe --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IMaterial.java @@ -0,0 +1,38 @@ +package dst.ass1.jpa.model; + +import java.util.Collection; +import java.util.Date; + +public interface IMaterial { + + Long getId(); + + void setId(Long id); + + String getUrn(); + + void setUrn(String urn); + + String getType(); + + void setType(String type); + + Date getUploaded(); + + void setUploaded(Date uploaded); + + Date getLastUpdate(); + + void setLastUpdate(Date lastUpdate); + + ILesson getLesson(); + + void setLesson(ILesson lesson); + + Collection getMaterialServers(); + + void setMaterialServers(Collection materialServers); + + void addMaterialServer(IMaterialServer materialServer); + +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/model/IMaterialServer.java b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IMaterialServer.java new file mode 100644 index 0000000..727b0f0 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IMaterialServer.java @@ -0,0 +1,30 @@ +package dst.ass1.jpa.model; + +import java.util.Collection; +import java.util.Date; + +public interface IMaterialServer { + + Long getId(); + + void setId(Long id); + + String getName(); + + void setName(String name); + + Date getLastMaintenance(); + + void setLastMaintenance(Date lastMaintenance); + + Date getNextMaintenance(); + + void setNextMaintenance(Date nextMaintenance); + + Collection getMaterials(); + + void setMaterials(Collection materials); + + void addMaterial(IMaterial material); + +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/model/IMembership.java b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IMembership.java new file mode 100644 index 0000000..0631a9d --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IMembership.java @@ -0,0 +1,24 @@ +package dst.ass1.jpa.model; + +public interface IMembership { + + Long getId(); + + void setId(Long id); + + Boolean getPremium(); + + void setPremium(Boolean premium); + + Double getDiscount(); + + void setDiscount(Double discount); + + ICoursePlatform getCoursePlatform(); + + void setCoursePlatform(ICoursePlatform coursePlatform); + + IParticipant getParticipant(); + + void setParticipant(IParticipant participant); +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/model/IMetadata.java b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IMetadata.java new file mode 100644 index 0000000..c1b6053 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IMetadata.java @@ -0,0 +1,17 @@ +package dst.ass1.jpa.model; + +import java.util.Map; + +public interface IMetadata { + + Long getId(); + + void setId(Long id); + + Map getData(); + + void setData(Map settings); + + void putData(String key, String value); + +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/model/IModelFactory.java b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IModelFactory.java new file mode 100644 index 0000000..ad44f42 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IModelFactory.java @@ -0,0 +1,30 @@ +package dst.ass1.jpa.model; + +public interface IModelFactory { + + IAddress createAddress(); + + ICourse createCourse(); + + ICoursePlatform createCoursePlatform(); + + IEnrollment createEnrollment(); + + IEnrollmentKey createEnrollmentKey(); + + ILecturer createLecturer(); + + ILesson createLesson(); + + IMaterial createMaterial(); + + IMaterialServer createMaterialServer(); + + IMembership createMembership(); + + IMetadata createMetadata(); + + IModelFactory createModelFactory(); + + IParticipant createParticipant(); +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/model/IParticipant.java b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IParticipant.java new file mode 100644 index 0000000..206004b --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IParticipant.java @@ -0,0 +1,35 @@ +package dst.ass1.jpa.model; + +import java.util.Collection; + +public interface IParticipant extends IPerson { + + String getEmail(); + + void setEmail(String email); + + byte[] getPassword(); + + void setPassword(byte[] password); + + String getAccountNo(); + + void setAccountNo(String accountNo); + + String getBankCode(); + + void setBankCode(String bankCode); + + Collection getEnrollments(); + + void setEnrollments(Collection enrollments); + + void addEnrollment(IEnrollment enrollment); + + Collection getMemberships(); + + void setMemberships(Collection memberships); + + void addMembership(IMembership membership); + +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/model/IPerson.java b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IPerson.java new file mode 100644 index 0000000..8e44902 --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/model/IPerson.java @@ -0,0 +1,17 @@ +package dst.ass1.jpa.model; + +public interface IPerson { + + Long getId(); + + void setId(Long id); + + String getName(); + + void setName(String name); + + IAddress getAddress(); + + void setAddress(IAddress address); + +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/model/impl/ModelFactory.java b/ass1-jpa/src/main/java/dst/ass1/jpa/model/impl/ModelFactory.java new file mode 100644 index 0000000..704d71b --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/model/impl/ModelFactory.java @@ -0,0 +1,99 @@ +package dst.ass1.jpa.model.impl; + +import dst.ass1.jpa.model.IAddress; +import dst.ass1.jpa.model.ICourse; +import dst.ass1.jpa.model.ICoursePlatform; +import dst.ass1.jpa.model.IEnrollment; +import dst.ass1.jpa.model.IEnrollmentKey; +import dst.ass1.jpa.model.ILecturer; +import dst.ass1.jpa.model.ILesson; +import dst.ass1.jpa.model.IMaterial; +import dst.ass1.jpa.model.IMaterialServer; +import dst.ass1.jpa.model.IMembership; +import dst.ass1.jpa.model.IMetadata; +import dst.ass1.jpa.model.IModelFactory; +import dst.ass1.jpa.model.IParticipant; + +/** + * Creates new instances of your model implementations. + */ +public class ModelFactory implements IModelFactory { + + @Override + public IAddress createAddress() { + // TODO + return null; + } + + @Override + public ICourse createCourse() { + // TODO + return null; + } + + @Override + public ICoursePlatform createCoursePlatform() { + // TODO + return null; + } + + @Override + public IEnrollment createEnrollment() { + // TODO + return null; + } + + @Override + public IEnrollmentKey createEnrollmentKey() { + // TODO + return null; + } + + @Override + public ILecturer createLecturer() { + // TODO + return null; + } + + @Override + public ILesson createLesson() { + // TODO + return null; + } + + @Override + public IMaterial createMaterial() { + // TODO + return null; + } + + @Override + public IMaterialServer createMaterialServer() { + // TODO + return null; + } + + @Override + public IMembership createMembership() { + // TODO + return null; + } + + @Override + public IMetadata createMetadata() { + // TODO + return null; + } + + @Override + public IModelFactory createModelFactory() { + // TODO + return null; + } + + @Override + public IParticipant createParticipant() { + // TODO + return null; + } +} diff --git a/ass1-jpa/src/main/java/dst/ass1/jpa/util/Constants.java b/ass1-jpa/src/main/java/dst/ass1/jpa/util/Constants.java new file mode 100644 index 0000000..039d5af --- /dev/null +++ b/ass1-jpa/src/main/java/dst/ass1/jpa/util/Constants.java @@ -0,0 +1,106 @@ +package dst.ass1.jpa.util; + +public final class Constants { + + // FIXME: update according to model updates (membership, enrollment, course capacity, ...) + + public static final String JPA_PERSISTENCE_UNIT = "dst_pu"; + + /* TYPES (CLASSES) */ + public static final String T_COURSE = "Course"; + public static final String T_COURSEPLATFORM = "CoursePlatform"; + public static final String T_ENROLLMENT = "Enrollment"; + public static final String T_LECTURER = "Lecturer"; + public static final String T_LESSON = "Lesson"; + public static final String T_MATERIAL = "Material"; + public static final String T_MATERIALSERVER = "MaterialServer"; + public static final String T_MEMBERSHIP = "Membership"; + public static final String T_METADATA = "Metadata"; + public static final String T_PARTICIPANT = "Participant"; + public static final String T_PERSON = "Person"; + + /* IDs (FOREIGN KEYS) */ + public static final String I_COURSE = "course_id"; + public static final String I_COURSEPLATFORM = "courseplatform_id"; + public static final String I_LECTURER = "lecturer_id"; + public static final String I_LESSON = "lesson_id"; + public static final String I_MATERIAL = "material_id"; + public static final String I_MATERIALSERVER = "materialserver_id"; + public static final String I_MEMBERSHIP = "membership_id"; + public static final String I_METADATA = "metadata_id"; + public static final String I_PARTICIPANT = "participant_id"; + public static final String I_PERSON = "person_id"; + public static final String I_LESSON_REQUIRED = "requiredLessons_id"; + public static final String I_LESSON_REQUIRED_BY = "requiredLessonsBy_id"; + + /* MEMBER ATTRIBUTES */ + public static final String M_ADDRESS_STREET = "street"; + public static final String M_ADDRESS_CITY = "city"; + public static final String M_ADDRESS_ZIP_CODE = "zipCode"; + public static final String M_COURSE_NAME = "name"; + public static final String M_COURSE_PREMIUM = "premium"; + public static final String M_COURSE_COST = "cost"; + public static final String M_COURSE_CAPACITY = "capacity"; + public static final String M_COURSE_STATUS = "status"; + public static final String M_COURSE_START = "start"; + public static final String M_COURSE_END = "end"; + public static final String M_COURSE_LECTURER = "lecturer"; + public static final String M_COURSE_COURSEPLATFORM = "coursePlatform"; + public static final String M_COURSE_PARTICIPANTS = "participants"; + public static final String M_COURSEPLATFORM_NAME = "name"; + public static final String M_COURSEPLATFORM_URL = "url"; + public static final String M_ENROLLMENT_ENROLLED_AT = "enrolledAt"; + public static final String M_ENROLLMENT_PAID = "paid"; + public static final String M_LECTURER_LESSONS = "lessons"; + public static final String M_LESSON_DESCRIPTION = "description"; + public static final String M_LESSON_START = "start"; + public static final String M_LESSON_END = "end"; + public static final String M_LESSON_REQUIRED = "requiredLessons"; + public static final String M_LESSON_COURSE = "course"; + public static final String M_MATERIAL_URN = "urn"; + public static final String M_MATERIAL_TYPE = "type"; + public static final String M_MATERIAL_UPLOADED = "uploaded"; + public static final String M_MATERIAL_LAST_UPDATE = "lastUpdate"; + public static final String M_MATERIAL_LESSON = "lesson"; + public static final String M_MATERIALSERVER_NAME = "name"; + public static final String M_MATERIALSERVER_LAST_MAINTENANCE = "lastMaintenance"; + public static final String M_MATERIALSERVER_NEXT_MAINTENANCE = "nextMaintenance"; + public static final String M_MATERIALSERVER_COURSE_PLATFORM = "coursePlatform"; + public static final String M_MEMBERSHIP_PREMIUM = "premium"; + public static final String M_MEMBERSHIP_DISCOUNT = "discount"; + public static final String M_METADATA_DATA = "data"; + public static final String M_PARTICIPANT_ACCOUNT = "accountNo"; + public static final String M_PARTICIPANT_BANK_CODE = "bankCode"; + public static final String M_PERSON_NAME = "name"; + public static final String M_PERSON_EMAIL = "email"; + public static final String M_PERSON_PASSWORD = "password"; + + /* ASSOCIATION NAMES (FOR QUERIES) */ + public static final String A_MATERIALS = "materials"; + public static final String A_LESSONS = "lessons"; + public static final String A_COURSE = "course"; + + /* NAMED QUERIES */ + public static final String Q_PARTICIPANT_BY_EMAIL = "participantByEmail"; + public static final String Q_ONGOING_AND_FREE_PLATFORM_COURSES = "ongoingAndFreeCoursesByPlatform"; + public static final String Q_MOST_ACTIVE_LECTURER = "mostActiveLecturer"; + public static final String Q_UPCOMING_LESSONS = "upcomingLessonsPerLecturerForCourse"; + + /* JOIN TABLES */ + public static final String J_LESSONS_REQUIRED = "lesson_required"; + public static final String J_METADATA_DATA = "metadata_data"; + public static final String J_MATERIALSERVER_MATERIAL = "materialserver_material"; + public static final String J_LECTURER_LESSON = "lecturer_lesson"; + public static final String J_PARTICIPANT_MEMBERSHIP = "participant_membership"; + public static final String J_PARTICIPANT_ENROLLMENT = "participant_enrollment"; + public static final String J_COURSE_ENROLLMENT = "course_enrollment"; + public static final String J_COURSEPLATFORM_MATERIALSERVER = "courseplatform_materialserver"; + + /* MONGODB */ + public static final String MONGO_DB_NAME = "dst"; + public static final String COLL_MATERIAL_DATA = "MaterialData"; + + private Constants() { + // final + } +} diff --git a/ass1-jpa/src/main/resources/META-INF/Material.xml b/ass1-jpa/src/main/resources/META-INF/Material.xml new file mode 100644 index 0000000..1291bec --- /dev/null +++ b/ass1-jpa/src/main/resources/META-INF/Material.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/ass1-jpa/src/main/resources/META-INF/orm.xml b/ass1-jpa/src/main/resources/META-INF/orm.xml new file mode 100644 index 0000000..1291bec --- /dev/null +++ b/ass1-jpa/src/main/resources/META-INF/orm.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/ass1-jpa/src/main/resources/META-INF/persistence.xml b/ass1-jpa/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000..7798d62 --- /dev/null +++ b/ass1-jpa/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,24 @@ + + + + org.hibernate.jpa.HibernatePersistenceProvider + META-INF/Material.xml + META-INF/orm.xml + + + + + + + + + + + + + + + diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/CaseInsensitiveStringCollectionMatcher.java b/ass1-jpa/src/test/java/dst/ass1/jpa/CaseInsensitiveStringCollectionMatcher.java new file mode 100644 index 0000000..38ece95 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/CaseInsensitiveStringCollectionMatcher.java @@ -0,0 +1,52 @@ +package dst.ass1.jpa; + +import java.util.ArrayList; +import java.util.List; + +import org.hamcrest.Description; +import org.hamcrest.Factory; +import org.hamcrest.TypeSafeDiagnosingMatcher; + +/** + * Matcher that finds items in string collections in a case-insensitive way. + */ +public class CaseInsensitiveStringCollectionMatcher extends TypeSafeDiagnosingMatcher> { + + private final String[] items; + + public CaseInsensitiveStringCollectionMatcher(String... items) { + this.items = items; + } + + @Override + protected boolean matchesSafely(List collection, Description description) { + List missing = new ArrayList<>(); + + for (String item : items) { + if (collection.stream().noneMatch(i -> i.equalsIgnoreCase(item))) { + missing.add(item); + } + } + + if (!missing.isEmpty()) { + if (missing.size() == items.length) { + description.appendValueList("was [", ", ", "]", collection); + } else { + description.appendValueList("missing [", ", ", "]", missing) + .appendValueList(" in [", ", ", "]", collection); + } + } + + return missing.isEmpty(); + } + + @Override + public void describeTo(Description description) { + description.appendValueList("collection containing ", " and ", "", items); + } + + @Factory + public static CaseInsensitiveStringCollectionMatcher hasItems(String... items) { + return new CaseInsensitiveStringCollectionMatcher(items); + } +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/DatabaseGateway.java b/ass1-jpa/src/test/java/dst/ass1/jpa/DatabaseGateway.java new file mode 100644 index 0000000..4c14dbc --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/DatabaseGateway.java @@ -0,0 +1,293 @@ +package dst.ass1.jpa; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import javax.persistence.EntityManager; +import javax.persistence.metamodel.Type; + +import org.hibernate.Session; +import org.hibernate.jdbc.ReturningWork; + +// DO NOT MODIFY THIS CLASS. + +/** + * Contains various methods for accessing the database underlying an EntityManager. + * + * Note that the caller is responsible for dealing with possible exceptions as well as doing the connection handling. A + * connection will not be closed even if a fatal error occurs. However, other SQL resources i.e., + * {@link Statement Statements} and {@link ResultSet ResultSets} created within the methods, which are not returned to + * the caller, are closed before the method returns. + */ +public class DatabaseGateway { + + private final EntityManager em; + + public DatabaseGateway(EntityManager em) { + this.em = em; + } + + /** + * Returns a list of all table-names for the given database/connection. + * + * @return List of table names + */ + public List getTables() { + return getSession().doReturningWork(new CollectionWork<>("show tables", rs -> rs.getString(1))); + } + + /** + * Returns a list of all column names in the given table. + * + * @param tableName the table + * @return a list of column names + */ + public List getColumns(String tableName) { + return getColumnsDefinitions(tableName).stream().map(m -> m.get("COLUMN_NAME")).collect(Collectors.toList()); + } + + public List> getColumnsDefinitions(String tableName) { + String sql = String.format("SELECT * FROM information_schema.columns " + + "WHERE table_name='%s'", tableName.toUpperCase()); + + return getSession().doReturningWork(new QueryWork>>(sql) { + @Override + protected List> execute(ResultSet rs) throws SQLException { + List> list = new ArrayList<>(); + while (rs.next()) { + ResultSetMetaData meta = rs.getMetaData(); + Map map = new HashMap<>(); + for (int i = 1; i <= meta.getColumnCount(); i++) { + String key = meta.getColumnName(i); + String value = rs.getString(key); + map.put(key, value); + } + list.add(map); + } + return list; + } + }); + } + + /** + * Returns the java types of all managed entity types. + * + * @return a list of java types + */ + public List> getManagedJavaTypes() { + return em.getMetamodel() + .getManagedTypes().stream() + .map(Type::getJavaType) + .collect(Collectors.toList()); + } + + /** + * Checks if the named table can be accessed via the given EntityManager. + * + * @param tableName the name of the table to find + * @return {@code true} if the database schema contains a table with the given name, {@code false} otherwise + */ + public boolean isTable(final String tableName) { + return getSession().doReturningWork(new QueryWork("show tables") { + @Override + public Boolean execute(ResultSet rs) throws SQLException { + while (rs.next()) { + String tbl = rs.getString(1); + if (tbl.equalsIgnoreCase(tableName)) { + return true; + } + } + return false; + } + + }); + } + + /** + * Checks whether a certain database table contains a column with the given + * name. + * + * @param tableName the name of the table to check + * @param column the name of the column to find + * @return {@code true} if the table contains the column, {@code false} otherwise + */ + public boolean isColumnInTable(String tableName, String column) { + String sql = String.format( + "SELECT * FROM information_schema.columns WHERE table_name='%s' and column_name='%s'", + tableName.toUpperCase(), column.toUpperCase() + ); + + return getSession().doReturningWork(new HasAtLeastOneEntry(sql)); + } + + /** + * Checks whether a table contains a column of the given type and length. + * + * @param tableName the table to look for + * @param column the expected column name + * @param type the expected column type + * @param length the expected column length + * @return true if the information schema has at least one such column + */ + public boolean isColumnInTableWithType(String tableName, String column, String type, String length) { + String sql = String.format("SELECT * FROM information_schema.columns " + + "WHERE table_name='%s' and column_name='%s' and " + + "type_name='%s' and character_maximum_length='%s'", + tableName.toUpperCase(), column.toUpperCase(), type.toUpperCase(), length); + + return getSession().doReturningWork(new HasAtLeastOneEntry(sql)); + } + + /** + * Checks whether a certain table contains an index for the given column + * name. + * + * @param tableName the name of the table to check + * @param indexName the name of the column the index is created for + * @param nonUnique {@code true} if the index is non unique, {@code false} otherwise + * @return {@code true} if the index exists, {@code false} otherwise + */ + public boolean isIndex(String tableName, String indexName, boolean nonUnique) { + + String sql = String.format( + "SELECT * FROM information_schema.indexes WHERE table_name='%s' and column_name='%s' and non_unique='%s'", + tableName.toUpperCase(), indexName.toUpperCase(), nonUnique ? "1" : "0" + ); + + return getSession().doReturningWork(new HasAtLeastOneEntry(sql)); + } + + public boolean isComposedIndex(String tableName, String columnName1, String columnName2) { + String indexName1 = getIndexName(tableName, columnName1); + String indexName2 = getIndexName(tableName, columnName2); + + return Objects.nonNull(indexName1) && Objects.equals(indexName1, indexName2); + } + + private String getIndexName(String tableName, String columnName) { + String sql = String.format( + "SELECT index_name FROM information_schema.indexes WHERE table_name='%s' and column_name='%s'", + tableName.toUpperCase(), columnName.toUpperCase() + ); + + return getSession().doReturningWork(new QueryWork(sql) { + @Override + protected String execute(ResultSet rs) throws SQLException { + return (rs.next()) ? rs.getString(1) : null; + } + }); + } + + /** + * Checks whether the given column of a certain table can contain {@code NULL} values. + * + * @param tableName the name of the table to check + * @param columnName the name of the column to check + * @return {@code true} if the column is nullable, {@code false} otherwise + */ + public boolean isNullable(String tableName, String columnName) { + String sql = String.format( + "SELECT * FROM information_schema.columns " + + "WHERE table_name='%s' and column_name='%s' and IS_NULLABLE=true", + tableName.toUpperCase(), columnName.toUpperCase() + ); + + return getSession().doReturningWork(new HasAtLeastOneEntry(sql)); + } + + /** + * Deletes all data from all tables that can be accessed via the given EntityManager. + */ + public void truncateTables() { + List tables = getTables(); + tables.removeIf(t -> t.toLowerCase().startsWith("hibernate")); + + getSession().doWork(connection -> { + try (Statement stmt = connection.createStatement()) { + stmt.addBatch("SET FOREIGN_KEY_CHECKS=0"); + for (String table : tables) { + stmt.addBatch("TRUNCATE TABLE " + table); + } + stmt.addBatch("SET FOREIGN_KEY_CHECKS=1"); + stmt.executeBatch(); + } + }); + } + + public Session getSession() { + return em.unwrap(Session.class); + } + + public interface StatementWork extends ReturningWork { + + default T execute(Connection connection) throws SQLException { + try (Statement stmt = connection.createStatement()) { + return execute(stmt); + } + } + + T execute(Statement stmt) throws SQLException; + } + + public static abstract class QueryWork implements StatementWork { + private final String sql; + + public QueryWork(String sql) { + this.sql = sql; + } + + @Override + public T execute(Statement stmt) throws SQLException { + try (ResultSet rs = stmt.executeQuery(sql)) { + return execute(rs); + } + } + + protected abstract T execute(ResultSet rs) throws SQLException; + } + + public static class HasAtLeastOneEntry extends QueryWork { + + public HasAtLeastOneEntry(String sql) { + super(sql); + } + + @Override + protected Boolean execute(ResultSet rs) throws SQLException { + return rs.next(); + } + } + + public static class CollectionWork extends QueryWork> { + + private final CheckedFunction extractor; + + public CollectionWork(String sql, CheckedFunction extractor) { + super(sql); + this.extractor = extractor; + } + + @Override + protected List execute(ResultSet rs) throws SQLException { + List list = new ArrayList<>(); + while (rs.next()) { + list.add(extractor.apply(rs)); + } + return list; + } + } + + @FunctionalInterface + public interface CheckedFunction { + R apply(T t) throws E; + } +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/ITestData.java b/ass1-jpa/src/test/java/dst/ass1/jpa/ITestData.java new file mode 100644 index 0000000..4cc482f --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/ITestData.java @@ -0,0 +1,21 @@ +package dst.ass1.jpa; + +import javax.persistence.EntityManager; + +import dst.ass1.jpa.model.IModelFactory; + +// DO NOT MODIFY THIS CLASS. + +/** + * The ITestData interface is used by the {@link ORMService} to insert test data before each test run. You can pass + * custom implementation of {@link ITestData} to the constructor of {@link ORMService} to create your own test fixture. + */ +public interface ITestData { + /** + * Creates test data using the model factory and inserts them into the entity manager. + * + * @param modelFactory the model factory + * @param em the entity manager + */ + void insert(IModelFactory modelFactory, EntityManager em); +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/ORMService.java b/ass1-jpa/src/test/java/dst/ass1/jpa/ORMService.java new file mode 100644 index 0000000..089ec82 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/ORMService.java @@ -0,0 +1,173 @@ +package dst.ass1.jpa; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.EntityTransaction; +import javax.persistence.Persistence; + +import org.junit.rules.ExternalResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import dst.ass1.jpa.dao.IDAOFactory; +import dst.ass1.jpa.dao.impl.DAOFactory; +import dst.ass1.jpa.model.IModelFactory; +import dst.ass1.jpa.model.impl.ModelFactory; +import dst.ass1.jpa.util.Constants; + +// DO NOT MODIFY THIS CLASS. + +/** + * The ORMService class is used as a JUnit rule that, before each test run, + * a) creates an entity manager factory from the persistence unit referenced in {@link Constants#JPA_PERSISTENCE_UNIT}, + * b) creates an entity manager using the factory, + * c) creates dao and model factory instances, and + * d) creates a database gateway for the entity manager. + * + * It provides methods to access these services, and it closes the entity manager and corresponding factory after each + * test run. If you pass an {@link ITestData} instance to the constructor, the {@link ORMService} will also insert test + * data via a transaction before each run, and truncate tables after each run. + */ +public class ORMService extends ExternalResource { + + private static final Logger LOG = LoggerFactory.getLogger(ORMService.class); + + private static EntityManagerFactory emf; + private EntityManager em; + + private DatabaseGateway databaseGateway; + + private IModelFactory modelFactory; + private IDAOFactory daoFactory; + + private ITestData testData; + private boolean insertTestData; + private boolean truncateTables; + + /** + * Creates a new ORMService. By default, the ORMService rule only creates the database connection and other + * ORM facilities. If you want to also insert a test fixture, use {@link #ORMService(ITestData)}. + */ + public ORMService() { + this(null, false, false); + } + + /** + * Creates a new ORMService that also inserts the given {@link ITestData} before each run and truncates the tables + * afterwards. + * + * @param testData the test data to insert + */ + public ORMService(ITestData testData) { + this(testData, true, true); + } + + public ORMService(ITestData testData, boolean insertTestData, boolean truncateTables) { + this.testData = testData; + this.insertTestData = insertTestData; + this.truncateTables = truncateTables; + } + + public EntityManager getEntityManager() { + return em; + } + + public EntityManager createEntityManager() { + return emf.createEntityManager(); + } + + public IModelFactory getModelFactory() { + return modelFactory; + } + + public IDAOFactory getDaoFactory() { + return daoFactory; + } + + public DatabaseGateway getDatabaseGateway() { + return databaseGateway; + } + + /** + * Alias for {@link #getEntityManager()}. + * + * @return an entity manager + */ + public EntityManager em() { + return getEntityManager(); + } + + @Override + protected void before() throws Throwable { + LOG.debug("Creating EntityManagerFactory"); + emf = createEntityManagerFactory(); + + LOG.debug("Creating EntityManager"); + em = emf.createEntityManager(); + databaseGateway = new DatabaseGateway(em); + + LOG.debug("Initializing factories"); + // initialize factories + modelFactory = new ModelFactory(); + daoFactory = new DAOFactory(em); + + if (testData != null && insertTestData) { + insertTestData(testData); + } + } + + @Override + protected void after() { + if (truncateTables) { + truncateTables(); + } + + try { + LOG.debug("Closing EntityManager"); + em.close(); + } catch (Exception e) { + LOG.error("Error while closing entity manager", e); + } + + try { + LOG.debug("Closing EntityManagerFactory"); + emf.close(); + } catch (Exception e) { + LOG.error("Error while closing entity manager factory", e); + } + } + + protected void insertTestData(ITestData data) { + EntityTransaction tx = getEntityManager().getTransaction(); + + tx.begin(); + try { + data.insert(getModelFactory(), getEntityManager()); + tx.commit(); + } catch (Exception e) { + try { + if (tx.isActive()) { + tx.rollback(); + } + } catch (Exception rollbackException) { + LOG.error("Error while rolling back transaction after exception", rollbackException); + } finally { + throw new IllegalStateException("Couldn't insert fixture. Can't proceed with tests", e); // rethrow original exception + } + } + } + + protected void truncateTables() { + try { + LOG.debug("Truncating database tables"); + getDatabaseGateway().truncateTables(); + } catch (Exception e) { + LOG.error("Error while trying to truncate tables after test", e); + } + } + + private static EntityManagerFactory createEntityManagerFactory() { + return Persistence.createEntityManagerFactory(Constants.JPA_PERSISTENCE_UNIT); + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/examples/ExampleTestWithCustomTestData.java b/ass1-jpa/src/test/java/dst/ass1/jpa/examples/ExampleTestWithCustomTestData.java new file mode 100644 index 0000000..81bbdcd --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/examples/ExampleTestWithCustomTestData.java @@ -0,0 +1,68 @@ +package dst.ass1.jpa.examples; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.List; + +import javax.persistence.EntityManager; + +import org.junit.Rule; +import org.junit.Test; + +import dst.ass1.jpa.ITestData; +import dst.ass1.jpa.ORMService; +import dst.ass1.jpa.dao.ICoursePlatformDAO; +import dst.ass1.jpa.model.ICoursePlatform; +import dst.ass1.jpa.model.IModelFactory; + +/** + * This examples shows how you can write your own tests with custom fixtures that are injected it into the + * {@link ORMService} rule. Using rules instead of abstract tests is considered good practice as it follows the + * principle of composition over inheritance. + */ +public class ExampleTestWithCustomTestData { + + @Rule + public ORMService orm = new ORMService(new MyTestData()); + + @Test + public void coursePlatformDAO_findAll_returnsCorrectValues() throws Exception { + ICoursePlatformDAO coursePlatformDAO = orm.getDaoFactory().createCoursePlatformDAO(); + + List all = coursePlatformDAO.findAll(); + + assertThat(all.isEmpty(), is(false)); + assertThat(all.size(), is(2)); + + System.out.println(all); + } + + @Test + public void coursePlatformDAO_findById_returnsCorrectValue() throws Exception { + ICoursePlatformDAO coursePlatformDAO = orm.getDaoFactory().createCoursePlatformDAO(); + + ICoursePlatform actual = coursePlatformDAO.findById(1L); + + assertThat(actual.getUrl(), is("http://cp1.example")); + } + + public static class MyTestData implements ITestData { + + @Override + public void insert(IModelFactory modelFactory, EntityManager em) { + ICoursePlatform cp1 = modelFactory.createCoursePlatform(); + cp1.setName("cp1"); + cp1.setUrl("http://cp1.example"); + + ICoursePlatform cp2 = modelFactory.createCoursePlatform(); + cp2.setName("cp2"); + cp2.setUrl("http://cp1.example"); + + em.persist(cp1); + em.persist(cp2); + + em.flush(); // transaction is done through the ORMTestFixture + } + } +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/examples/ExampleTestWithDependencies.java b/ass1-jpa/src/test/java/dst/ass1/jpa/examples/ExampleTestWithDependencies.java new file mode 100644 index 0000000..75d9922 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/examples/ExampleTestWithDependencies.java @@ -0,0 +1,68 @@ +package dst.ass1.jpa.examples; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; + +import java.util.List; + +import javax.persistence.EntityManager; + +import org.junit.ClassRule; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import dst.ass1.jpa.ORMService; +import dst.ass1.jpa.dao.ICoursePlatformDAO; +import dst.ass1.jpa.dao.IDAOFactory; +import dst.ass1.jpa.model.ICoursePlatform; +import dst.ass1.jpa.model.IModelFactory; + +/** + * This test has no test fixture and dependencies between tests. This is possible by declaring {@link ORMService} as a + * static class-level rule via {@link ClassRule}. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class ExampleTestWithDependencies { + + @ClassRule + public static ORMService orm = new ORMService(); + + @Test + public void t01_insert() throws Exception { + EntityManager em = orm.getEntityManager(); + IModelFactory modelFactory = orm.getModelFactory(); + + ICoursePlatform cp1 = modelFactory.createCoursePlatform(); + cp1.setName("cp1"); + cp1.setUrl("http://cp1.example"); + + ICoursePlatform cp2 = modelFactory.createCoursePlatform(); + cp2.setName("cp2"); + cp2.setUrl("http://cp1.example"); + + em.persist(cp1); + em.persist(cp2); + + em.getTransaction().begin(); + em.flush(); + em.getTransaction().commit(); + + assertThat(cp1.getId(), notNullValue()); + assertThat(cp2.getId(), notNullValue()); + } + + @Test + public void t02_query() throws Exception { + IDAOFactory daoFactory = orm.getDaoFactory(); + ICoursePlatformDAO coursePlatformDAO = daoFactory.createCoursePlatformDAO(); + + List all = coursePlatformDAO.findAll(); + + assertThat(all.isEmpty(), is(false)); + assertThat(all.size(), is(2)); + + System.out.println(all); + } +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/examples/package-info.java b/ass1-jpa/src/test/java/dst/ass1/jpa/examples/package-info.java new file mode 100644 index 0000000..079e109 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/examples/package-info.java @@ -0,0 +1,5 @@ +/** + * This package contains a couple of examples of how you can use JUnit and our simple ORM test framework to create your + * own tests. + */ +package dst.ass1.jpa.examples; \ No newline at end of file diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_00Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_00Test.java new file mode 100644 index 0000000..d3c324b --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_00Test.java @@ -0,0 +1,127 @@ +package dst.ass1.jpa.tests; + +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.isA; +import static org.hamcrest.object.IsCompatibleType.typeCompatibleWith; +import static org.junit.Assert.assertThat; + +import java.util.List; + +import javax.persistence.EntityTransaction; + +import org.junit.ClassRule; +import org.junit.FixMethodOrder; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ErrorCollector; +import org.junit.runners.MethodSorters; + +import dst.ass1.jpa.ITestData; +import dst.ass1.jpa.ORMService; +import dst.ass1.jpa.dao.ICourseDAO; +import dst.ass1.jpa.dao.ICoursePlatformDAO; +import dst.ass1.jpa.dao.IDAOFactory; +import dst.ass1.jpa.dao.ILecturerDAO; +import dst.ass1.jpa.dao.ILessonDAO; +import dst.ass1.jpa.dao.IMaterialDAO; +import dst.ass1.jpa.dao.IMaterialServerDAO; +import dst.ass1.jpa.dao.IMembershipDAO; +import dst.ass1.jpa.dao.IMetadataDAO; +import dst.ass1.jpa.dao.IParticipantDAO; +import dst.ass1.jpa.model.IAddress; +import dst.ass1.jpa.model.ICourse; +import dst.ass1.jpa.model.ICoursePlatform; +import dst.ass1.jpa.model.IEnrollment; +import dst.ass1.jpa.model.IEnrollmentKey; +import dst.ass1.jpa.model.ILecturer; +import dst.ass1.jpa.model.ILesson; +import dst.ass1.jpa.model.IMaterial; +import dst.ass1.jpa.model.IMaterialServer; +import dst.ass1.jpa.model.IMembership; +import dst.ass1.jpa.model.IMetadata; +import dst.ass1.jpa.model.IModelFactory; +import dst.ass1.jpa.model.IParticipant; + +/** + * Tests the basic setup of the model and dao factory (makes sure they don't return null), and also tests whether all + * relevant entities have been mapped at all and test data can be inserted. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class Ass1_1_1_00Test { + + @ClassRule + public static ORMService orm = new ORMService(); + + @Rule + public ErrorCollector err = new ErrorCollector(); + + @Test + public void test01_modelFactoryReturnsThings() { + IModelFactory modelFactory = orm.getModelFactory(); + + err.checkThat(modelFactory.createAddress(), isA(IAddress.class)); + err.checkThat(modelFactory.createCourse(), isA(ICourse.class)); + err.checkThat(modelFactory.createCoursePlatform(), isA(ICoursePlatform.class)); + err.checkThat(modelFactory.createEnrollment(), isA(IEnrollment.class)); + err.checkThat(modelFactory.createEnrollmentKey(), isA(IEnrollmentKey.class)); + err.checkThat(modelFactory.createLecturer(), isA(ILecturer.class)); + err.checkThat(modelFactory.createLesson(), isA(ILesson.class)); + err.checkThat(modelFactory.createMaterial(), isA(IMaterial.class)); + err.checkThat(modelFactory.createMaterialServer(), isA(IMaterialServer.class)); + err.checkThat(modelFactory.createMembership(), isA(IMembership.class)); + err.checkThat(modelFactory.createMetadata(), isA(IMetadata.class)); + err.checkThat(modelFactory.createParticipant(), isA(IParticipant.class)); + } + + @Test + public void test02_daoFactoryReturnsThings() { + IDAOFactory daoFactory = orm.getDaoFactory(); + + err.checkThat(daoFactory.createMembershipDAO(), isA(IMembershipDAO.class)); + err.checkThat(daoFactory.createParticipantDAO(), isA(IParticipantDAO.class)); + err.checkThat(daoFactory.createLessonDAO(), isA(ILessonDAO.class)); + err.checkThat(daoFactory.createLecturerDAO(), isA(ILecturerDAO.class)); + err.checkThat(daoFactory.createCourseDAO(), isA(ICourseDAO.class)); + err.checkThat(daoFactory.createMaterialDAO(), isA(IMaterialDAO.class)); + err.checkThat(daoFactory.createMaterialServerDAO(), isA(IMaterialServerDAO.class)); + err.checkThat(daoFactory.createMetadataDAO(), isA(IMetadataDAO.class)); + err.checkThat(daoFactory.createCoursePlatformDAO(), isA(ICoursePlatformDAO.class)); + } + + @Test + public void test03_entityTypesManagedCorrectly() throws Exception { + List> types = orm.getDatabaseGateway().getManagedJavaTypes(); + + assertThat("No managed types found", types.isEmpty(), is(false)); + System.out.println("Managed types: " + types); + err.checkThat(types, hasItem(typeCompatibleWith(ICourse.class))); + err.checkThat(types, hasItem(typeCompatibleWith(IAddress.class))); + err.checkThat(types, hasItem(typeCompatibleWith(ICoursePlatform.class))); + err.checkThat(types, hasItem(typeCompatibleWith(IEnrollment.class))); + err.checkThat(types, hasItem(typeCompatibleWith(IEnrollmentKey.class))); + err.checkThat(types, hasItem(typeCompatibleWith(ILecturer.class))); + err.checkThat(types, hasItem(typeCompatibleWith(ILesson.class))); + err.checkThat(types, hasItem(typeCompatibleWith(IMaterial.class))); + err.checkThat(types, hasItem(typeCompatibleWith(IMaterialServer.class))); + err.checkThat(types, hasItem(typeCompatibleWith(IMembership.class))); + err.checkThat(types, hasItem(typeCompatibleWith(IMetadata.class))); + err.checkThat(types, hasItem(typeCompatibleWith(IParticipant.class))); + } + + @Test + public void test04_canInsertTestFixture() throws Exception { + ITestData testData = new TestData(); + + EntityTransaction tx = orm.em().getTransaction(); + tx.begin(); + try { + testData.insert(orm.getModelFactory(), orm.em()); + } catch (Exception e) { + throw new AssertionError("Exception while inserting test fixture.", e); + } finally { + tx.rollback(); + } + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_01Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_01Test.java new file mode 100644 index 0000000..6e7d5ed --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_01Test.java @@ -0,0 +1,178 @@ +package dst.ass1.jpa.tests; + +import static dst.ass1.jpa.CaseInsensitiveStringCollectionMatcher.hasItems; +import static dst.ass1.jpa.util.Constants.*; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; + +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.FixMethodOrder; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ErrorCollector; +import org.junit.runners.MethodSorters; + +import dst.ass1.jpa.DatabaseGateway; +import dst.ass1.jpa.ORMService; +import dst.ass1.jpa.util.Constants; + +/** + * Tests the basic object-relational mapping by examining the created database tables and constraints. + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class Ass1_1_1_01Test { + + @ClassRule + public static ORMService orm = new ORMService(); + + @Rule + public ErrorCollector err = new ErrorCollector(); + + private DatabaseGateway db; + + @Before + public void setUp() throws Exception { + db = orm.getDatabaseGateway(); + } + + @Test + public void printTables() throws Exception { + // not a test, just some systout output that may help you to gain insight into the created database schema + for (String table : db.getTables()) { + System.out.printf("%-30s %s%n", table, db.getColumns(table)); + } + } + + @Test + public void testBasicTablesJdbc() throws Exception { + // checks that all basic tables exist + err.checkThat(db.getTables(), hasItems( + T_LECTURER, + T_PARTICIPANT, + T_MEMBERSHIP, + T_LESSON, + T_COURSE, + T_ENROLLMENT, + T_COURSEPLATFORM, + T_MATERIAL, + T_METADATA, + T_MATERIALSERVER + )); + } + + @Test + public void testRelation01Jdbc() throws Exception { + // lecturer <-> lesson + err.checkThat(db.getTables(), hasItems(J_LECTURER_LESSON)); + err.checkThat(db.getColumns(J_LECTURER_LESSON), hasItems( + I_LESSON, + I_LECTURER + )); + } + + @Test + public void testRelation02Jdbc() throws Exception { + // lecturer <-> course + err.checkThat(db.getColumns(T_COURSE), hasItems(I_LECTURER)); + } + + @Test + public void testRelation03Jdbc() throws Exception { + // participant <-enrollment-> course + + err.checkThat(db.getColumns(T_ENROLLMENT), hasItems( + I_PARTICIPANT, + I_COURSE + )); + err.checkThat(db.getTables(), hasItems( + J_COURSE_ENROLLMENT, + J_PARTICIPANT_ENROLLMENT + )); + } + + @Test + public void testRelation04Jdbc() throws Exception { + // participant <-> membership -> courseplatform + + err.checkThat(db.getColumns(T_MEMBERSHIP), hasItems( + I_COURSEPLATFORM, + I_PARTICIPANT + )); + err.checkThat(db.getColumns(T_PARTICIPANT), not(hasItems(I_MEMBERSHIP))); + err.checkThat(db.getColumns(T_COURSEPLATFORM), not(hasItems(I_MEMBERSHIP))); + + err.checkThat(db.getTables(), hasItems(J_PARTICIPANT_MEMBERSHIP)); + err.checkThat(db.getColumns(J_PARTICIPANT_MEMBERSHIP), hasItems(I_PARTICIPANT)); + } + + @Test + public void testRelation05Jdbc() throws Exception { + // lesson <-> lesson + + err.checkThat("join table should be explicitly renamed!", db.getTables(), not(hasItems( + T_LESSON + "_" + T_LESSON + ))); + err.checkThat(db.getTables(), hasItems( + J_LESSONS_REQUIRED + )); + err.checkThat(db.getColumns(J_LESSONS_REQUIRED), hasItems( + I_LESSON_REQUIRED, + I_LESSON_REQUIRED_BY + )); + } + + @Test + public void testRelation06Jdbc() throws Exception { + // lesson <-> course + err.checkThat(db.getColumns(T_LESSON), hasItems(I_COURSE)); + err.checkThat(db.getColumns(T_COURSE), not(hasItems(I_LESSON))); + err.checkThat(db.isIndex(T_LESSON, I_COURSE, true), is(true)); + } + + @Test + public void testRelation07Jdbc() throws Exception { + // lesson <-> material + + err.checkThat(db.getColumns(T_MATERIAL), hasItems(I_LESSON)); + err.checkThat(db.getColumns(T_LESSON), not(hasItems(I_MATERIAL))); + err.checkThat(db.isIndex(T_MATERIAL, I_LESSON, true), is(true)); + } + + @Test + public void testRelation08Jdbc() throws Exception { + // course -> courseplatform + err.checkThat(db.getColumns(T_COURSE), hasItems(I_COURSEPLATFORM)); + err.checkThat(db.isIndex(T_COURSE, I_COURSEPLATFORM, true), is(true)); + } + + @Test + public void testRelation09Jdbc() throws Exception { + // course -> metadata + err.checkThat(db.getTables(), hasItems(T_METADATA)); + err.checkThat(db.getColumns(T_COURSE), hasItems(I_METADATA)); + err.checkThat(db.getColumns(T_METADATA), not(hasItems(I_COURSE))); + err.checkThat(db.isIndex(Constants.T_COURSE, Constants.I_METADATA, false), is(true)); + + } + + @Test + public void testRelation10Jdbc() throws Exception { + // courseplatform -> materialserver + err.checkThat(db.getTables(), hasItems(J_COURSEPLATFORM_MATERIALSERVER)); + err.checkThat(db.getColumns(T_MATERIALSERVER), not(hasItems(I_COURSEPLATFORM))); + } + + @Test + public void testRelation11Jdbc() throws Exception { + // material <-> materialserver + + err.checkThat(db.getTables(), hasItems(J_MATERIALSERVER_MATERIAL)); + } + + @Test + public void testColumnType01Jdbc() { + err.checkThat(db.isColumnInTableWithType(T_PARTICIPANT, M_PERSON_PASSWORD, "VARBINARY", "20"), is(true)); + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_02Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_02Test.java new file mode 100644 index 0000000..ebc07ea --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_02Test.java @@ -0,0 +1,31 @@ +package dst.ass1.jpa.tests; + +import static org.junit.Assert.assertTrue; + +import org.junit.Rule; +import org.junit.Test; + +import dst.ass1.jpa.ORMService; +import dst.ass1.jpa.util.Constants; + +/** + * Tests the ICoursePlatform name unique constraint. + */ +public class Ass1_1_1_02Test { + + @Rule + public ORMService orm = new ORMService(); + + @Test + public void testConstraint() { + new UniqueConstraintTester<>(() -> orm.getModelFactory().createCoursePlatform(), e -> e.setName("uniquevalue")) + .run(orm.getEntityManager()); + } + + @Test + public void testConstraintJdbc() { + assertTrue(orm.getDatabaseGateway().isIndex(Constants.T_COURSEPLATFORM, Constants.M_COURSEPLATFORM_NAME, false)); + assertTrue(orm.getDatabaseGateway().isNullable(Constants.T_COURSEPLATFORM, Constants.M_COURSEPLATFORM_NAME)); + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_03Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_03Test.java new file mode 100644 index 0000000..7e1e1e5 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_03Test.java @@ -0,0 +1,30 @@ +package dst.ass1.jpa.tests; + +import static org.junit.Assert.assertTrue; + +import org.junit.Rule; +import org.junit.Test; + +import dst.ass1.jpa.ORMService; +import dst.ass1.jpa.util.Constants; + +/** + * Tests the IMaterialServer name unique constraint. + */ +public class Ass1_1_1_03Test { + + @Rule + public ORMService orm = new ORMService(); + + @Test + public void testConstraint() { + new UniqueConstraintTester<>(() -> orm.getModelFactory().createMaterialServer(), e -> e.setName("uniquevalue")) + .run(orm.getEntityManager()); + } + + @Test + public void testConstraintJdbc() { + assertTrue(orm.getDatabaseGateway().isIndex(Constants.T_MATERIALSERVER, Constants.M_MATERIALSERVER_NAME, false)); + assertTrue(orm.getDatabaseGateway().isNullable(Constants.T_MATERIALSERVER, Constants.M_MATERIALSERVER_NAME)); + } +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_04Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_04Test.java new file mode 100644 index 0000000..5f42d88 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_04Test.java @@ -0,0 +1,30 @@ +package dst.ass1.jpa.tests; + +import static org.junit.Assert.assertTrue; + +import org.junit.Rule; +import org.junit.Test; + +import dst.ass1.jpa.ORMService; +import dst.ass1.jpa.util.Constants; + +/** + * Tests the IMaterials urn unique constraint. + */ +public class Ass1_1_1_04Test { + + @Rule + public ORMService orm = new ORMService(); + + @Test + public void testConstraint() { + new UniqueConstraintTester<>(() -> orm.getModelFactory().createMaterial(), e -> e.setUrn("uniquevalue")) + .run(orm.getEntityManager()); + } + + @Test + public void testConstraintJdbc() { + assertTrue(orm.getDatabaseGateway().isIndex(Constants.T_MATERIAL, Constants.M_MATERIAL_URN, false)); + assertTrue(orm.getDatabaseGateway().isNullable(Constants.T_MATERIAL, Constants.M_MATERIAL_URN)); + } +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_05Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_05Test.java new file mode 100644 index 0000000..6880714 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_05Test.java @@ -0,0 +1,57 @@ +package dst.ass1.jpa.tests; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + +import javax.persistence.metamodel.ManagedType; +import javax.persistence.metamodel.Type; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import dst.ass1.jpa.ORMService; +import dst.ass1.jpa.model.IAddress; + +/** + * Tests if IAddress is implemented correctly. + */ +public class Ass1_1_1_05Test { + + @Rule + public ORMService orm = new ORMService(); + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + public void addressEntityCannotBePersisted() { + IAddress address = orm.getModelFactory().createAddress(); + assertNotNull(address); + + address.setCity("city1"); + address.setStreet("street1"); + address.setZipCode("zip1"); + + expectedException.expect(IllegalArgumentException.class); + orm.getEntityManager().persist(address); + } + + @Test + public void addressIsEmbeddableType() { + IAddress address = orm.getModelFactory().createAddress(); + assertNotNull(address); + + ManagedType type = orm.getEntityManager().getMetamodel().managedType(address.getClass()); + assertNotNull(type); + assertThat(type.getPersistenceType(), is(Type.PersistenceType.EMBEDDABLE)); + } + + @Test + public void addressHasNoTable() throws Exception { + assertFalse(orm.getDatabaseGateway().isTable("ADDRESS")); + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_06Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_06Test.java new file mode 100644 index 0000000..ab56714 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_06Test.java @@ -0,0 +1,60 @@ +package dst.ass1.jpa.tests; + +import static org.hamcrest.CoreMatchers.hasItems; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.Map; + +import javax.persistence.EntityManager; + +import org.junit.Rule; +import org.junit.Test; + +import dst.ass1.jpa.ORMService; +import dst.ass1.jpa.model.IMetadata; +import dst.ass1.jpa.util.Constants; + +/** + * Tests that IMetadata is persisted correctly. + */ +public class Ass1_1_1_06Test { + + @Rule + public ORMService orm = new ORMService(); + + @Test + public void testMetadataMap() { + IMetadata md1 = orm.getModelFactory().createMetadata(); + + md1.putData("key1", "value1"); + md1.putData("key2", "value2"); + + EntityManager em = orm.getEntityManager(); + em.getTransaction().begin(); + + em.persist(md1); + em.flush(); + em.getTransaction().commit(); + + EntityManager em2 = orm.createEntityManager(); + IMetadata md2 = em2.find(md1.getClass(), md1.getId()); + + Map map = md2.getData(); + + assertThat(map.size(), is(2)); + assertThat(map.keySet(), hasItems("key1", "key2")); + assertThat(map.get("key1"), is("value1")); + assertThat(map.get("key2"), is("value2")); + } + + @Test + public void testMetadataMapJdbc() { + assertTrue(orm.getDatabaseGateway().isTable(Constants.T_METADATA)); + assertTrue(orm.getDatabaseGateway().isTable(Constants.J_METADATA_DATA)); + assertTrue(orm.getDatabaseGateway().isColumnInTable(Constants.J_METADATA_DATA, Constants.I_METADATA)); + assertTrue(orm.getDatabaseGateway().isColumnInTable(Constants.J_METADATA_DATA, Constants.M_METADATA_DATA + "_KEY")); + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_07Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_07Test.java new file mode 100644 index 0000000..0315131 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_07Test.java @@ -0,0 +1,86 @@ +package dst.ass1.jpa.tests; + +import static org.hamcrest.CoreMatchers.isA; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import javax.persistence.PersistenceException; + +import org.hibernate.PropertyValueException; +import org.hibernate.exception.ConstraintViolationException; +import org.junit.Test; + +import dst.ass1.jpa.model.ICourse; +import dst.ass1.jpa.model.IMetadata; + +/** + * Tests if the ICourse and IMetadata relation is implemented correctly. + */ +public class Ass1_1_1_07Test extends Ass1_TestBase { + + @Test + public void testMetadataAssociation() { + ICourse course1 = daoFactory.createCourseDAO().findById(testData.course1Id); + assertNotNull(course1); + assertEquals(testData.metadata1Id, course1.getMetadata().getId()); + + ICourse course2 = daoFactory.createCourseDAO().findById(testData.course2Id); + assertNotNull(course2); + assertEquals(testData.metadata2Id, course2.getMetadata().getId()); + } + + @Test + public void testMetadataNonOptionalConstraint() { + expectedException.expect(PersistenceException.class); + expectedException.expectCause(isA(PropertyValueException.class)); + expectedException.expectMessage("not-null property"); + + ICourse course1 = daoFactory.createCourseDAO().findById(testData.course1Id); + assertNotNull(course1); + course1.setMetadata(null); + em.getTransaction().begin(); + em.persist(course1); + em.flush(); + } + + @Test + public void testMetadataUniqueConstraint() throws Exception { + ICourse course1 = daoFactory.createCourseDAO().findById(testData.course1Id); + IMetadata metadata1 = course1.getMetadata(); + + ICourse course5 = modelFactory.createCourse(); + course5.setName("course5"); + course5.setMetadata(metadata1); + + em.getTransaction().begin(); + expectedException.expect(PersistenceException.class); + expectedException.expectCause(isA(ConstraintViolationException.class)); + expectedException.reportMissingExceptionWithMessage( + "Persisting the same metadata object with a different course should result in a constraint violation" + ); + em.persist(course5); + em.flush(); + } + + @Test + public void testCourseMetadataDeleteCascade() throws Exception { + ICourse course = daoFactory.createCourseDAO().findById(testData.course4Id); + Long metadataId = course.getMetadata().getId(); + + em.getTransaction().begin(); + try { + em.remove(course); + em.flush(); + } catch (PersistenceException e) { + throw new AssertionError("Removing a course should not result in a PersistenceException", e); + } + em.getTransaction().commit(); + + em.getTransaction().begin(); + IMetadata metadata = em.find(modelFactory.createMetadata().getClass(), metadataId); + assertNull("Expected metadata to be null after associated course was deleted", metadata); + } + + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_08Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_08Test.java new file mode 100644 index 0000000..8b441b0 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_08Test.java @@ -0,0 +1,51 @@ +package dst.ass1.jpa.tests; + +import static org.hamcrest.CoreMatchers.hasItem; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + +import java.util.List; + +import org.junit.Test; + +import dst.ass1.jpa.model.CourseStatus; +import dst.ass1.jpa.model.ICourse; +import dst.ass1.jpa.model.ILecturer; + +/** + * Tests the 1-N association between ICourse and ILecturer (its organizer). + */ +public class Ass1_1_1_08Test extends Ass1_TestBase { + + @Test + public void testCourseLecturerAssociation() { + + ILecturer lecturer1 = daoFactory.createLecturerDAO().findById(testData.lecturer1Id); + assertNotNull(lecturer1); + assertNotNull(lecturer1.getCourses()); + + List courseIds = map(lecturer1.getCourses(), ICourse::getId); + + assertEquals(1, courseIds.size()); + assertThat(courseIds, hasItem(testData.course1Id)); + + ICourse course1 = daoFactory.createCourseDAO().findById(testData.course1Id); + ICourse course2 = daoFactory.createCourseDAO().findById(testData.course2Id); + + assertNotNull(course1); + assertNotNull(course2); + + assertEquals(testData.lecturer1Id, course1.getLecturer().getId()); + assertEquals(testData.lecturer2Id, course2.getLecturer().getId()); + } + + @Test + public void testCourseStatus() { + ICourse course1 = daoFactory.createCourseDAO().findById(testData.course1Id); + assertEquals(CourseStatus.CREATED, course1.getStatus()); + ICourse course2 = daoFactory.createCourseDAO().findById(testData.course2Id); + assertEquals(CourseStatus.ONGOING, course2.getStatus()); + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_09Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_09Test.java new file mode 100644 index 0000000..2d16c7a --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_09Test.java @@ -0,0 +1,68 @@ +package dst.ass1.jpa.tests; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.core.IsCollectionContaining.hasItems; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + +import java.util.List; + +import javax.persistence.EntityManager; + +import org.junit.Test; + +import dst.ass1.jpa.dao.ICoursePlatformDAO; +import dst.ass1.jpa.dao.IMaterialServerDAO; +import dst.ass1.jpa.dao.impl.DAOFactory; +import dst.ass1.jpa.model.ICoursePlatform; +import dst.ass1.jpa.model.IMaterialServer; + +/** + * Tests the association between ICoursePlatform and IMaterialServer. + */ +public class Ass1_1_1_09Test extends Ass1_TestBase { + + @Test + public void testCoursePlatformMaterialServerAssociation() { + EntityManager em = orm.createEntityManager(); + DAOFactory daoFactory = new DAOFactory(em); + + IMaterialServerDAO materialServerDAO = daoFactory.createMaterialServerDAO(); + ICoursePlatformDAO coursePlatformDAO = daoFactory.createCoursePlatformDAO(); + + List materialServers = materialServerDAO.findAll(); + + assertNotNull(materialServers); + assertEquals(3, materialServers.size()); + + IMaterialServer materialServer1 = materialServerDAO.findById(testData.materialServer1Id); + IMaterialServer materialServer2 = materialServerDAO.findById(testData.materialServer2Id); + IMaterialServer materialServer3 = materialServerDAO.findById(testData.materialServer3Id); + + assertEquals(testData.materialServer1Id, materialServer1.getId()); + assertEquals(testData.materialServer2Id, materialServer2.getId()); + assertEquals(testData.materialServer3Id, materialServer3.getId()); + + List coursePlatforms = coursePlatformDAO.findAll(); + + assertNotNull(coursePlatforms); + assertEquals(2, coursePlatforms.size()); + + ICoursePlatform coursePlatform1 = coursePlatformDAO.findById(testData.coursePlatform1Id); + ICoursePlatform coursePlatform2 = coursePlatformDAO.findById(testData.coursePlatform2Id); + + assertEquals(testData.coursePlatform1Id, coursePlatform1.getId()); + assertNotNull(coursePlatform1.getMaterialServers()); + assertThat(coursePlatform1.getMaterialServers().size(), is(2)); + List materialServerIds1 = map(coursePlatform1.getMaterialServers(), IMaterialServer::getId); + assertThat(materialServerIds1, hasItems(testData.materialServer1Id, testData.materialServer2Id)); + + assertEquals(testData.coursePlatform2Id, coursePlatform2.getId()); + assertNotNull(coursePlatform2.getMaterialServers()); + assertThat(coursePlatform2.getMaterialServers().size(), is(1)); + List materialServerIds2 = map(coursePlatform2.getMaterialServers(), IMaterialServer::getId); + assertThat(materialServerIds2, hasItems(testData.materialServer3Id)); + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_10Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_10Test.java new file mode 100644 index 0000000..52a7b8f --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_1_10Test.java @@ -0,0 +1,98 @@ +package dst.ass1.jpa.tests; + +import static org.hamcrest.core.IsCollectionContaining.hasItem; +import static org.hamcrest.core.IsCollectionContaining.hasItems; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.List; + +import javax.persistence.EntityManager; + +import org.hibernate.Session; +import org.junit.Test; + +import dst.ass1.jpa.dao.ILessonDAO; +import dst.ass1.jpa.dao.impl.DAOFactory; +import dst.ass1.jpa.model.ILesson; +import dst.ass1.jpa.util.Constants; + +/** + * Tests the self reference of ILesson. + */ +public class Ass1_1_1_10Test extends Ass1_TestBase { + + @Test + public void testLessonSelfAssociation() { + EntityManager em = orm.createEntityManager(); + ILessonDAO dao = new DAOFactory(em).createLessonDAO(); + + ILesson lesson1 = dao.findById(testData.lesson1Id); + ILesson lesson2 = dao.findById(testData.lesson2Id); + ILesson lesson3 = dao.findById(testData.lesson3Id); + ILesson lesson4 = dao.findById(testData.lesson4Id); + assertNotNull(lesson1.getRequiredByLessons()); + assertNotNull(lesson2.getRequiredLessons()); + assertNotNull(lesson2.getRequiredByLessons()); + assertNotNull(lesson3.getRequiredLessons()); + assertNotNull(lesson3.getRequiredByLessons()); + assertNotNull(lesson4.getRequiredLessons()); + + List lesson1requiredBy = map(lesson1.getRequiredByLessons(), ILesson::getId); + List lesson2required = map(lesson2.getRequiredLessons(), ILesson::getId); + List lesson2requiredBy = map(lesson2.getRequiredByLessons(), ILesson::getId); + List lesson3required = map(lesson3.getRequiredLessons(), ILesson::getId); + List lesson3requiredBy = map(lesson3.getRequiredByLessons(), ILesson::getId); + List lesson4required = map(lesson4.getRequiredLessons(), ILesson::getId); + + assertThat(lesson1requiredBy, hasItems(testData.lesson2Id, testData.lesson3Id)); + assertThat(lesson2required, hasItem(testData.lesson1Id)); + assertThat(lesson3required, hasItem(testData.lesson1Id)); + assertThat(lesson2requiredBy, hasItem(testData.lesson4Id)); + assertThat(lesson3requiredBy, hasItem(testData.lesson4Id)); + assertThat(lesson4required, hasItems(testData.lesson2Id, testData.lesson3Id)); + } + + @Test + public void testLessonSelfAssociationJdbc() { + String sql = "SELECT " + Constants.I_LESSON_REQUIRED + ", " + Constants.I_LESSON_REQUIRED_BY + + " FROM " + Constants.J_LESSONS_REQUIRED + + " ORDER BY " + Constants.I_LESSON_REQUIRED + ", " + Constants.I_LESSON_REQUIRED_BY; + + em.unwrap(Session.class).doWork(connection -> { + + try (Statement stmt = connection.createStatement()) { + ResultSet rs = stmt.executeQuery(sql); + assertTrue(rs.next()); + + assertEquals((long) testData.lesson1Id, rs.getLong(Constants.I_LESSON_REQUIRED)); + assertEquals((long) testData.lesson2Id, rs.getLong(Constants.I_LESSON_REQUIRED_BY)); + + assertTrue(rs.next()); + + assertEquals((long) testData.lesson1Id, rs.getLong(Constants.I_LESSON_REQUIRED)); + assertEquals((long) testData.lesson3Id, rs.getLong(Constants.I_LESSON_REQUIRED_BY)); + + assertTrue(rs.next()); + + assertEquals((long) testData.lesson2Id, rs.getLong(Constants.I_LESSON_REQUIRED)); + assertEquals((long) testData.lesson4Id, rs.getLong(Constants.I_LESSON_REQUIRED_BY)); + + assertTrue(rs.next()); + + assertEquals((long) testData.lesson3Id, rs.getLong(Constants.I_LESSON_REQUIRED)); + assertEquals((long) testData.lesson4Id, rs.getLong(Constants.I_LESSON_REQUIRED_BY)); + + assertFalse(rs.next()); + + rs.close(); + } + }); + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_2_01Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_2_01Test.java new file mode 100644 index 0000000..1d7ea2b --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_2_01Test.java @@ -0,0 +1,48 @@ +package dst.ass1.jpa.tests; + +import static org.junit.Assert.assertTrue; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import dst.ass1.jpa.ORMService; +import dst.ass1.jpa.model.IParticipant; +import dst.ass1.jpa.util.Constants; + +/** + * Tests the constraint for IParticipant bank data. + */ +public class Ass1_1_2_01Test { + + @Rule + public ORMService orm = new ORMService(); + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + public void testParticipantAccountNoBankCodeConstraint() { + IParticipant p1 = orm.getModelFactory().createParticipant(); + IParticipant p2 = orm.getModelFactory().createParticipant(); + + p1.setEmail("p1@example.com"); + p2.setEmail("p2@example.com"); + + new UniqueConstraintTester<>(p1, p2, e -> { + e.setAccountNo("uniqueVal1"); + e.setBankCode("uniqueVal2"); + }).run(orm.getEntityManager()); + } + + @Test + public void testParticipantAccountNoBankCodeConstraintJdbc() { + assertTrue(orm.getDatabaseGateway().isIndex(Constants.T_PARTICIPANT, Constants.M_PARTICIPANT_ACCOUNT, false)); + assertTrue(orm.getDatabaseGateway().isIndex(Constants.T_PARTICIPANT, Constants.M_PARTICIPANT_BANK_CODE, false)); + assertTrue(orm.getDatabaseGateway().isComposedIndex(Constants.T_PARTICIPANT, Constants.M_PARTICIPANT_ACCOUNT, Constants.M_PARTICIPANT_BANK_CODE)); + + assertTrue(orm.getDatabaseGateway().isNullable(Constants.T_PARTICIPANT, Constants.M_PARTICIPANT_ACCOUNT)); + assertTrue(orm.getDatabaseGateway().isNullable(Constants.T_PARTICIPANT, Constants.M_PARTICIPANT_BANK_CODE)); + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_2_02Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_2_02Test.java new file mode 100644 index 0000000..c6da936 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_1_2_02Test.java @@ -0,0 +1,54 @@ +package dst.ass1.jpa.tests; + +import static org.hamcrest.CoreMatchers.isA; +import static org.junit.Assert.assertFalse; + +import java.sql.SQLException; + +import javax.persistence.PersistenceException; + +import org.hibernate.PropertyValueException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import dst.ass1.jpa.ORMService; +import dst.ass1.jpa.model.IParticipant; +import dst.ass1.jpa.util.Constants; + +/** + * Tests the constraint for IParticipant email. + */ +public class Ass1_1_2_02Test { + + @Rule + public ORMService orm = new ORMService(); + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + public void testUniqueConstraint() { + new UniqueConstraintTester<>(() -> orm.getModelFactory().createParticipant(), e -> e.setEmail("unique@example.com")) + .run(orm.getEntityManager()); + } + + @Test + public void testNotNullConstraint() { + expectedException.expect(PersistenceException.class); + expectedException.expectCause(isA(PropertyValueException.class)); + expectedException.expectMessage("not-null property"); + + IParticipant e1 = orm.getModelFactory().createParticipant(); + e1.setEmail(null); + orm.em().getTransaction().begin(); + orm.em().persist(e1); + orm.em().flush(); + } + + @Test + public void testPersonEmailNotNullConstraintJdbc() throws SQLException { + assertFalse(orm.getDatabaseGateway().isNullable(Constants.T_PARTICIPANT, Constants.M_PERSON_EMAIL)); + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_1aTest.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_1aTest.java new file mode 100644 index 0000000..8acd8a9 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_1aTest.java @@ -0,0 +1,55 @@ +package dst.ass1.jpa.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; + +import javax.persistence.Query; + +import org.junit.Before; +import org.junit.Test; + +import dst.ass1.jpa.dao.IParticipantDAO; +import dst.ass1.jpa.model.IParticipant; +import dst.ass1.jpa.util.Constants; + +public class Ass1_2_1aTest extends Ass1_TestBase { + + private IParticipantDAO dao; + private Class entityClass; + + @Before + public void setUp() throws Exception { + dao = daoFactory.createParticipantDAO(); + entityClass = modelFactory.createParticipant().getClass(); + } + + @Test + public void namedQuery_withEmailParameter_returnsNonEmptyResultSet() throws Exception { + Query query = em.createNamedQuery(Constants.Q_PARTICIPANT_BY_EMAIL); + + try { + query.setParameter("email", TestData.PARTICIPANT_1_EMAIL); + } catch (IllegalArgumentException e) { + throw new AssertionError("Could not set parameter 'email' in named query " + Constants.Q_PARTICIPANT_BY_EMAIL, e); + } + + assertEquals("Expected exactly one result", 1, query.getResultList().size()); + } + + @Test + public void findByEmail_returnsCorrectResult() throws Exception { + Long participantId = testData.participant1Id; + + IParticipant actual = dao.findByEmail(TestData.PARTICIPANT_1_EMAIL); + IParticipant expected = em.find(entityClass, participantId); + + assertEquals(participantId, actual.getId()); + assertSame(expected, actual); // note that they should actually be the same object due EntityManager caching! + } + + @Test + public void findByEmail_withNonExistingEmail_returnsNull() throws Exception { + assertNull(dao.findByEmail("non@existing.com")); + } +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_1bTest.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_1bTest.java new file mode 100644 index 0000000..b56d3ca --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_1bTest.java @@ -0,0 +1,46 @@ +package dst.ass1.jpa.tests; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.Collection; +import java.util.List; + +import javax.persistence.Query; + +import org.junit.Test; + +import dst.ass1.jpa.dao.ICourseDAO; +import dst.ass1.jpa.model.ICourse; +import dst.ass1.jpa.util.Constants; + +public class Ass1_2_1bTest extends Ass1_TestBase { + + @Test + public void namedQuery_returnsCorrectResult() throws Exception { + Query query = em.createNamedQuery(Constants.Q_ONGOING_AND_FREE_PLATFORM_COURSES); + query.setParameter("platformName", TestData.COURSE_PLATFORM_2_NAME); + + List resultList = query.getResultList(); + assertThat("Expected a single results", resultList.size(), is(1)); + + ICourse result = (ICourse) resultList.get(0); + assertThat(result.getName(), is(TestData.COURSE_2_NAME)); + } + + @Test + public void daoFind_returnsCorrectResult() throws Exception { + ICourseDAO dao = daoFactory.createCourseDAO(); + Collection resultList; + + resultList = dao.findOngoingAndFreeCoursesForPlatform(TestData.COURSE_PLATFORM_1_NAME); + assertThat("Expected an empty result for " + TestData.COURSE_PLATFORM_1_NAME, resultList.isEmpty(), is(true)); + + resultList = dao.findOngoingAndFreeCoursesForPlatform(TestData.COURSE_PLATFORM_2_NAME); + assertThat("Expected a single results for " + TestData.COURSE_PLATFORM_2_NAME, resultList.size(), is(1)); + ICourse result = resultList.iterator().next(); + assertThat(result.getName(), is(TestData.COURSE_2_NAME)); + + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_1cTest.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_1cTest.java new file mode 100644 index 0000000..0ca54ee --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_1cTest.java @@ -0,0 +1,62 @@ +package dst.ass1.jpa.tests; + +import static org.hamcrest.core.IsCollectionContaining.hasItems; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import java.util.List; + +import javax.persistence.EntityTransaction; +import javax.persistence.Query; + +import org.junit.Test; + +import dst.ass1.jpa.model.ILecturer; +import dst.ass1.jpa.model.ILesson; +import dst.ass1.jpa.util.Constants; + +public class Ass1_2_1cTest extends Ass1_TestBase { + + @SuppressWarnings("unchecked") + @Test + public void namedQuery_returnsCorrectResult() { + Query query = em.createNamedQuery(Constants.Q_MOST_ACTIVE_LECTURER); + + List result = (List) query.getResultList(); + assertEquals(1, result.size()); + assertEquals(testData.lecturer2Id, result.get(0).getId()); + } + + @Test + public void namedQuery_withAdditionalAssociation_returnsCorrectResult() throws Exception { + ILesson lesson2 = daoFactory.createLessonDAO().findById(testData.lesson2Id); + ILecturer lecturer1 = daoFactory.createLecturerDAO().findById(testData.lecturer1Id); + ILecturer lecturer2 = daoFactory.createLecturerDAO().findById(testData.lecturer2Id); + + EntityTransaction tx = em.getTransaction(); + tx.begin(); + lesson2.addLecturer(lecturer1); + lecturer1.addLesson(lesson2); + em.persist(lesson2); + em.persist(lecturer1); + em.flush(); + tx.commit(); + + Query query = em.createNamedQuery(Constants.Q_MOST_ACTIVE_LECTURER); + + List result = (List) query.getResultList(); + assertEquals(2, result.size()); + assertThat(result, hasItems(lecturer1, lecturer2)); + } + + @SuppressWarnings("unchecked") + @Test + public void namedQuery_onEmptyDatabase_returnsEmptyResult() { + db.truncateTables(); + + Query query = em.createNamedQuery(Constants.Q_MOST_ACTIVE_LECTURER); + + List result = (List) query.getResultList(); + assertEquals(0, result.size()); + } +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_2Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_2Test.java new file mode 100644 index 0000000..4425969 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_2Test.java @@ -0,0 +1,95 @@ +package dst.ass1.jpa.tests; + +import static org.hamcrest.CoreMatchers.hasItems; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.Map; +import java.util.stream.Collectors; + +import javax.persistence.EntityManager; + +import org.junit.Before; +import org.junit.Test; + +import dst.ass1.jpa.dao.ICourseDAO; +import dst.ass1.jpa.dao.IDAOFactory; +import dst.ass1.jpa.dao.ILecturerDAO; +import dst.ass1.jpa.dao.impl.DAOFactory; +import dst.ass1.jpa.model.ICourse; +import dst.ass1.jpa.model.ILecturer; +import dst.ass1.jpa.model.ILesson; +import dst.ass1.jpa.model.IMetadata; +import dst.ass1.jpa.util.Constants; + +public class Ass1_2_2Test extends Ass1_TestBase { + + private ILecturerDAO lecturerDAO; + private ICourseDAO courseDAO; + + @Before + public void setUp() throws Exception { + // makes sure there's no cache from creating entities + EntityManager em = orm.createEntityManager(); + IDAOFactory daoFactory = new DAOFactory(em); + + lecturerDAO = daoFactory.createLecturerDAO(); + courseDAO = daoFactory.createCourseDAO(); + } + + @Test + public void testUpcomingLessonsExists() { + em.createNamedQuery(Constants.Q_UPCOMING_LESSONS); + } + + @Test + public void testUpcomingLessonsQuery() { + ICourse course = courseDAO.findById(testData.course1Id); + Map result = lecturerDAO.findUpcomingLessonForLecturersOfCourse(course); + + assertEquals(3, result.size()); + Map resultIds = convertMapKeys(result); + System.out.println(resultIds); + assertThat(resultIds.keySet(), hasItems(testData.lecturer1Id, testData.lecturer2Id, testData.lecturer3Id)); + + assertEquals(testData.lesson4Id, resultIds.get(testData.lecturer1Id).getId()); + assertEquals(testData.lesson2Id, resultIds.get(testData.lecturer2Id).getId()); + assertEquals(testData.lesson3Id, resultIds.get(testData.lecturer3Id).getId()); + } + + @Test + public void testUpcomingLessonsQuery2() { + ICourse course = courseDAO.findById(testData.course2Id); + Map result = lecturerDAO.findUpcomingLessonForLecturersOfCourse(course); + + assertEquals(1, result.size()); + Map resultIds = convertMapKeys(result); + System.out.println(resultIds); + assertThat(resultIds.keySet(), hasItems(testData.lecturer2Id)); + + assertEquals(testData.lesson5Id, resultIds.get(testData.lecturer2Id).getId()); + } + + @Test + public void testUpcomingLessonsQuery_onEmptyDatabase() { + db.truncateTables(); + + ICourse course = modelFactory.createCourse(); + IMetadata metadata = modelFactory.createMetadata(); + course.setMetadata(metadata); + em.persist(metadata); + em.persist(course); + + Map result = daoFactory.createLecturerDAO().findUpcomingLessonForLecturersOfCourse(course); + assertTrue(result.isEmpty()); + } + + private Map convertMapKeys(Map result) { + return result.entrySet().stream().collect(Collectors.toMap( + kv -> kv.getKey().getId(), + kv -> kv.getValue() + )); + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_3a_01Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_3a_01Test.java new file mode 100644 index 0000000..24c0537 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_3a_01Test.java @@ -0,0 +1,50 @@ +package dst.ass1.jpa.tests; + +import static org.hamcrest.CoreMatchers.hasItems; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.Collection; + +import org.junit.Before; +import org.junit.Test; + +import dst.ass1.jpa.dao.ICourseDAO; +import dst.ass1.jpa.dao.IMaterialServerDAO; +import dst.ass1.jpa.model.ICourse; +import dst.ass1.jpa.model.IMaterialServer; + +public class Ass1_2_3a_01Test extends Ass1_TestBase { + + private IMaterialServerDAO materialServerDAO; + private ICourseDAO courseDAO; + + @Before + public void setUp() throws Exception { + materialServerDAO = daoFactory.createMaterialServerDAO(); + courseDAO = daoFactory.createCourseDAO(); + } + + @Test + public void testMaterialServersForCourse() { + ICourse course = courseDAO.findById(testData.course1Id); + Collection materialServers = materialServerDAO.findMaterialServersForCourse(course); + assertNotNull(materialServers); + + assertThat(map(materialServers, e -> e.getId()), hasItems( + testData.materialServer1Id, + testData.materialServer2Id, + testData.materialServer3Id + )); + } + + @Test + public void testMaterialServersForCourse2() { + ICourse course = courseDAO.findById(testData.course2Id); + Collection materialServers = materialServerDAO.findMaterialServersForCourse(course); + assertNotNull(materialServers); + assertTrue(materialServers.isEmpty()); + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_3a_02Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_3a_02Test.java new file mode 100644 index 0000000..4e15a81 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_3a_02Test.java @@ -0,0 +1,69 @@ +package dst.ass1.jpa.tests; + +import static org.hamcrest.CoreMatchers.hasItems; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + +import java.util.Collection; + +import javax.persistence.EntityTransaction; + +import org.junit.Before; +import org.junit.Test; + +import dst.ass1.jpa.dao.ICourseDAO; +import dst.ass1.jpa.dao.ILessonDAO; +import dst.ass1.jpa.dao.IMaterialServerDAO; +import dst.ass1.jpa.model.ICourse; +import dst.ass1.jpa.model.ILesson; +import dst.ass1.jpa.model.IMaterialServer; + +public class Ass1_2_3a_02Test extends Ass1_TestBase { + + private ILessonDAO lessonDAO; + private ICourseDAO courseDAO; + private IMaterialServerDAO materialServerDAO; + + @Before + public void setUpDatabase() throws Exception { + lessonDAO = daoFactory.createLessonDAO(); + courseDAO = daoFactory.createCourseDAO(); + materialServerDAO = daoFactory.createMaterialServerDAO(); + + ILesson lesson1 = lessonDAO.findById(testData.lesson1Id); + ILesson lesson2 = lessonDAO.findById(testData.lesson2Id); + ICourse course2 = courseDAO.findById(testData.course2Id); + + EntityTransaction tx = em.getTransaction(); + tx.begin(); + lesson1.setCourse(course2); + lesson2.setCourse(course2); + em.persist(lesson1); + em.persist(lesson2); + em.flush(); + tx.commit(); + } + + @Test + public void testMaterialServersForCourse() { + ICourse course = courseDAO.findById(testData.course1Id); + Collection materialServers = materialServerDAO.findMaterialServersForCourse(course); + assertNotNull(materialServers); + + assertThat(map(materialServers, e -> e.getId()), hasItems( + testData.materialServer2Id, + testData.materialServer3Id + )); + } + + @Test + public void testMaterialServersForCourse2() { + ICourse course = courseDAO.findById(testData.course2Id); + Collection materialServers = materialServerDAO.findMaterialServersForCourse(course); + assertNotNull(materialServers); + + assertThat(map(materialServers, e -> e.getId()), hasItems( + testData.materialServer1Id + )); + } +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_3b_01Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_3b_01Test.java new file mode 100644 index 0000000..2a76289 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_3b_01Test.java @@ -0,0 +1,84 @@ +package dst.ass1.jpa.tests; + +import static org.hamcrest.core.IsCollectionContaining.hasItems; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.Collection; +import java.util.Date; +import java.util.GregorianCalendar; + +import org.junit.Before; +import org.junit.Test; + +import dst.ass1.jpa.dao.ICourseDAO; +import dst.ass1.jpa.model.ICourse; + +public class Ass1_2_3b_01Test extends Ass1_TestBase { + + private ICourseDAO dao; + + @Before + public void setUp() throws Exception { + dao = daoFactory.createCourseDAO(); + } + + @Test + public void testFindNonCancelledCoursesBetweenStartAndFinish() { + Collection courses = dao.findNonCancelledCoursesBetweenStartAndEnd(null, null); + + assertThat(map(courses, e -> e.getId()), hasItems( + testData.course1Id, + testData.course2Id + )); + } + + @Test + public void testFindEventsForStatusFinishedBetweenStartAndFinish2() { + Date start = createDate(2017, 1, 1, 1, 1); + Collection courses = dao.findNonCancelledCoursesBetweenStartAndEnd(start, null); + Collection courseIds = map(courses, ICourse::getId); + assertThat(courseIds, hasItems(testData.course1Id, testData.course2Id)); + + assertThat(map(courses, e -> e.getId()), hasItems( + testData.course1Id, + testData.course2Id + )); + } + + @Test + public void testFindEventsForStatusFinishedBetweenStartAndFinish3() { + Date start = dao.findById(testData.course1Id).getStart(); + Collection courses = dao.findNonCancelledCoursesBetweenStartAndEnd(start, null); + + assertThat(map(courses, e -> e.getId()), hasItems( + testData.course2Id + )); + } + + @Test + public void testFindEventsForStatusFinishedBetweenStartAndFinish4() { + Date end = dao.findById(testData.course2Id).getEnd(); + Collection courses = dao.findNonCancelledCoursesBetweenStartAndEnd(null, end); + + assertThat(map(courses, e -> e.getId()), hasItems( + testData.course1Id + )); + } + + @Test + public void testFindEventsForStatusFinishedBetweenStartAndFinish5() { + Date start = dao.findById(testData.course1Id).getEnd(); + Date end = dao.findById(testData.course2Id).getEnd(); + Collection courses = dao.findNonCancelledCoursesBetweenStartAndEnd(start, end); + + assertNotNull(courses); + assertTrue(courses.isEmpty()); + } + + private Date createDate(int year, int month, int day, int hours, int minutes) { + return new GregorianCalendar(year, month, day, hours, minutes).getTime(); + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_3b_02Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_3b_02Test.java new file mode 100644 index 0000000..e47c689 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_2_3b_02Test.java @@ -0,0 +1,69 @@ +package dst.ass1.jpa.tests; + +import static org.hamcrest.core.IsCollectionContaining.hasItems; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.Collection; +import java.util.Date; +import java.util.GregorianCalendar; + +import javax.persistence.EntityTransaction; + +import org.junit.Before; +import org.junit.Test; + +import dst.ass1.jpa.dao.ICourseDAO; +import dst.ass1.jpa.model.CourseStatus; +import dst.ass1.jpa.model.ICourse; + +public class Ass1_2_3b_02Test extends Ass1_TestBase { + + private ICourseDAO dao; + + @Before + public void setUp() throws Exception { + dao = daoFactory.createCourseDAO(); + + EntityTransaction tx = em.getTransaction(); + tx.begin(); + ICourse course1 = dao.findById(testData.course1Id); + course1.setStatus(CourseStatus.CANCELLED); + em.persist(course1); + em.flush(); + tx.commit(); + } + + @Test + public void testFindNonCancelledCoursesBetweenStartAndFinish() { + Collection courses = dao.findNonCancelledCoursesBetweenStartAndEnd(null, null); + + assertThat(map(courses, e -> e.getId()), hasItems( + testData.course2Id + )); + } + + @Test + public void testFindEventsForStatusFinishedBetweenStartAndFinish2() { + Date start = createDate(2017, 1, 1, 1, 1); + Collection courses = dao.findNonCancelledCoursesBetweenStartAndEnd(start, null); + + assertThat(map(courses, e -> e.getId()), hasItems( + testData.course2Id + )); + } + + @Test + public void testFindEventsForStatusFinishedBetweenStartAndFinish3() { + Date end = dao.findById(testData.course2Id).getEnd(); + Collection courses = dao.findNonCancelledCoursesBetweenStartAndEnd(null, end); + assertNotNull(courses); + assertTrue(courses.isEmpty()); + } + + private Date createDate(int year, int month, int day, int hours, int minutes) { + return new GregorianCalendar(year, month, day, hours, minutes).getTime(); + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_3_1Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_3_1Test.java new file mode 100644 index 0000000..cca4231 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_3_1Test.java @@ -0,0 +1,82 @@ +package dst.ass1.jpa.tests; + +import static org.hamcrest.Matchers.greaterThan; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + +import java.util.Date; + +import javax.persistence.EntityManager; +import javax.persistence.EntityTransaction; + +import org.junit.Rule; +import org.junit.Test; + +import dst.ass1.jpa.ORMService; +import dst.ass1.jpa.model.IMaterial; + +public class Ass1_3_1Test { + + @Rule + public ORMService orm = new ORMService(); + + @Test + public void entityListener_prePersistSetsPropertiesCorrectly() throws InterruptedException { + Date then = new Date(); + Thread.sleep(50); + + EntityManager em = orm.getEntityManager(); + + IMaterial material1 = orm.getModelFactory().createMaterial(); + + material1.setUrn("material1"); + + + EntityTransaction tx; + // persist + tx = em.getTransaction(); + tx.begin(); + em.persist(material1); + em.flush(); + tx.commit(); + + assertNotNull(material1.getUploaded()); + assertNotNull(material1.getLastUpdate()); + + assertThat(material1.getUploaded(), greaterThan(then)); + assertThat(material1.getLastUpdate(), greaterThan(then)); + } + + @Test + public void entityListener_preUpdateSetsPropertiesCorrectly() throws InterruptedException { + EntityManager em = orm.getEntityManager(); + + IMaterial material1 = orm.getModelFactory().createMaterial(); + + material1.setUrn("material1"); + + EntityTransaction tx; + // persist + tx = em.getTransaction(); + tx.begin(); + em.persist(material1); + em.flush(); + tx.commit(); + + Date then = new Date(); + + Thread.sleep(50); + + // update + tx = em.getTransaction(); + tx.begin(); + material1.setType("sometype"); + em.persist(material1); + em.flush(); + tx.commit(); + + assertNotNull(material1.getLastUpdate()); + assertThat(material1.getLastUpdate(), greaterThan(then)); + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_3_2Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_3_2Test.java new file mode 100644 index 0000000..7abf21b --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_3_2Test.java @@ -0,0 +1,72 @@ +package dst.ass1.jpa.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import javax.persistence.EntityManager; + +import org.junit.Rule; +import org.junit.Test; + +import dst.ass1.jpa.ORMService; +import dst.ass1.jpa.dao.IDAOFactory; +import dst.ass1.jpa.listener.DefaultListener; +import dst.ass1.jpa.model.IModelFactory; +import dst.ass1.jpa.model.IParticipant; + +public class Ass1_3_2Test { + + @Rule + public ORMService orm = new ORMService(); + + @Test + public void testDefaultListener() { + DefaultListener.clear(); + + IDAOFactory daoFactory = orm.getDaoFactory(); + IModelFactory modelFactory = orm.getModelFactory(); + EntityManager em = orm.getEntityManager(); + + em.getTransaction().begin(); + + // do some inserts + IParticipant participant = modelFactory.createParticipant(); + participant.setName(TestData.PARTICIPANT_1_NAME); + participant.setEmail(TestData.PARTICIPANT_1_EMAIL); + em.persist(participant); + em.flush(); + em.remove(participant); + em.flush(); + + participant = modelFactory.createParticipant(); + participant.setName(TestData.PARTICIPANT_2_NAME); + participant.setEmail(TestData.PARTICIPANT_2_EMAIL); + em.persist(participant); + + assertEquals(1, DefaultListener.getRemoveOperations()); + assertTrue(DefaultListener.getPersistOperations() > 0); + assertEquals((double) DefaultListener.getOverallTimeToPersist() / DefaultListener.getPersistOperations(), DefaultListener.getAverageTimeToPersist(), 0.0); + + List participants = daoFactory.createParticipantDAO().findAll(); + assertNotNull(participants); + assertFalse(participants.isEmpty()); + + int loadOperations = DefaultListener.getLoadOperations(); + em.refresh(participants.get(0)); + assertEquals(loadOperations + 1, DefaultListener.getLoadOperations()); + + participants = daoFactory.createParticipantDAO().findAll(); + assertNotNull(participants); + assertFalse(participants.isEmpty()); + + participants.get(0).setName("updated"); + em.persist(participants.get(0)); + em.flush(); + + assertEquals(1, DefaultListener.getUpdateOperations()); + } +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_3_3Test.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_3_3Test.java new file mode 100644 index 0000000..bc430da --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_3_3Test.java @@ -0,0 +1,35 @@ +package dst.ass1.jpa.tests; + +import static org.junit.Assert.assertEquals; + +import javax.persistence.Query; + +import org.junit.Test; + +import dst.ass1.jpa.interceptor.SQLInterceptor; +import dst.ass1.jpa.util.Constants; + +public class Ass1_3_3Test extends Ass1_TestBase { + + @Test + public void sqlInterceptor_countsSelectsCorrectly() { + em.getTransaction().begin(); + SQLInterceptor.resetCounter(); + assertEquals(0, SQLInterceptor.getSelectCount()); + + Query c = em.createQuery("select c from " + Constants.T_LECTURER + " c"); + c.getResultList(); + + assertEquals(1, SQLInterceptor.getSelectCount()); + + c = em.createQuery("select distinct c from " + Constants.T_LECTURER + " c"); + c.getResultList(); + + assertEquals(2, SQLInterceptor.getSelectCount()); + + c = em.createQuery("select e from " + Constants.T_LESSON + " e"); + c.getResultList(); + assertEquals(3, SQLInterceptor.getSelectCount()); + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_Suite.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_Suite.java new file mode 100644 index 0000000..90b019b --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_Suite.java @@ -0,0 +1,16 @@ +package dst.ass1.jpa.tests; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + Ass1_1_1_00Test.class, Ass1_1_1_01Test.class, Ass1_1_1_02Test.class, Ass1_1_1_03Test.class, Ass1_1_1_04Test.class, Ass1_1_1_05Test.class, Ass1_1_1_06Test.class, Ass1_1_1_07Test.class, Ass1_1_1_08Test.class, Ass1_1_1_09Test.class, Ass1_1_1_10Test.class, + Ass1_1_2_01Test.class, Ass1_1_2_02Test.class, + Ass1_2_1aTest.class, Ass1_2_1bTest.class, Ass1_2_1cTest.class, + Ass1_2_2Test.class, Ass1_2_3a_01Test.class, Ass1_2_3a_02Test.class, Ass1_2_3b_01Test.class, Ass1_2_3b_02Test.class, + Ass1_3_1Test.class, Ass1_3_2Test.class, Ass1_3_3Test.class, +}) +public class Ass1_Suite { +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_TestBase.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_TestBase.java new file mode 100644 index 0000000..bf5361d --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/Ass1_TestBase.java @@ -0,0 +1,51 @@ +package dst.ass1.jpa.tests; + +import java.util.Collection; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +import javax.persistence.EntityManager; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.rules.ErrorCollector; +import org.junit.rules.ExpectedException; + +import dst.ass1.jpa.DatabaseGateway; +import dst.ass1.jpa.ORMService; +import dst.ass1.jpa.dao.IDAOFactory; +import dst.ass1.jpa.model.IModelFactory; + +public class Ass1_TestBase { + + protected final TestData testData = new TestData(); + + @Rule + public ORMService orm = new ORMService(testData); + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Rule + public ErrorCollector err = new ErrorCollector(); + + // commonly used classes unwrapped from ORMService + protected EntityManager em; + protected IModelFactory modelFactory; + protected IDAOFactory daoFactory; + protected DatabaseGateway db; + + public static List map(Collection collection, Function fn) { + return collection.stream().map(fn).collect(Collectors.toList()); + } + + @Before + public void setUpBase() throws Exception { + em = orm.getEntityManager(); + modelFactory = orm.getModelFactory(); + daoFactory = orm.getDaoFactory(); + db = orm.getDatabaseGateway(); + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/TestData.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/TestData.java new file mode 100644 index 0000000..e5075b1 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/TestData.java @@ -0,0 +1,498 @@ +package dst.ass1.jpa.tests; + +import java.math.BigDecimal; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +import javax.persistence.EntityManager; + +import dst.ass1.jpa.ITestData; +import dst.ass1.jpa.model.CourseStatus; +import dst.ass1.jpa.model.IAddress; +import dst.ass1.jpa.model.ICourse; +import dst.ass1.jpa.model.ICoursePlatform; +import dst.ass1.jpa.model.IEnrollment; +import dst.ass1.jpa.model.IEnrollmentKey; +import dst.ass1.jpa.model.ILecturer; +import dst.ass1.jpa.model.ILesson; +import dst.ass1.jpa.model.IMaterial; +import dst.ass1.jpa.model.IMaterialServer; +import dst.ass1.jpa.model.IMembership; +import dst.ass1.jpa.model.IMetadata; +import dst.ass1.jpa.model.IModelFactory; +import dst.ass1.jpa.model.IParticipant; + +/** + * Test data used by the default set of tests. + */ +public class TestData implements ITestData { + + public static final String COURSE_PLATFORM_1_NAME = "coursePlatform1"; + public static final String COURSE_PLATFORM_2_NAME = "coursePlatform2"; + public static final String COURSE_1_NAME = "course1"; + public static final String COURSE_2_NAME = "course2"; + public static final String COURSE_3_NAME = "course3"; + public static final String COURSE_4_NAME = "course4"; + public static final String MATERIAL_SERVER_1_NAME = "materialServer1"; + public static final String MATERIAL_SERVER_2_NAME = "materialServer2"; + public static final String MATERIAL_SERVER_3_NAME = "materialServer3"; + public static final String MATERIAL_1_URN = "material1"; + public static final String MATERIAL_2_URN = "material2"; + public static final String MATERIAL_3_URN = "material3"; + public static final String MATERIAL_4_URN = "material4"; + public static final String MATERIAL_5_URN = "material5"; + public static final String METADATA_1_KEY_1 = "key11"; + public static final String METADATA_1_VALUE_1 = "setting11"; + public static final String METADATA_1_KEY_2 = "key12"; + public static final String METADATA_1_VALUE_2 = "setting12"; + public static final String METADATA_2_KEY_1 = "key21"; + public static final String METADATA_2_VALUE_1 = "setting21"; + public static final String LECTURER_1_NAME = "Alex"; + public static final String LECTURER_2_NAME = "Alexandra"; + public static final String LECTURER_3_NAME = "Alexander"; + public static final String PARTICIPANT_1_NAME = "Participant1"; + public static final String PARTICIPANT_1_PW = "pw4"; + public static final String PARTICIPANT_1_ACCOUNT_NO = "account1"; + public static final String PARTICIPANT_1_BANK_CODE = "bank1"; + public static final String PARTICIPANT_1_EMAIL = PARTICIPANT_1_NAME + "@example.com"; + public static final String PARTICIPANT_2_NAME = "Participant2"; + public static final String PARTICIPANT_2_PW = "pw5"; + public static final String PARTICIPANT_2_ACCOUNT_NO = "account2"; + public static final String PARTICIPANT_2_BANK_CODE = "bank2"; + public static final String PARTICIPANT_2_EMAIL = PARTICIPANT_2_NAME + "@example.com"; + public static final String LESSON_1_DESC = "Advanced Enterprise Cloud Machine Learning"; + public static final String LESSON_2_DESC = "Why you should invest in Bitcoin right now"; + public static final String LESSON_3_DESC = "Blockchain for whatever domain your company works in"; + public static final String LESSON_4_DESC = "The Dark Net and other terrible things"; + public static final String LESSON_5_DESC = "Build nano-services to solve all your problems"; + + public Long lecturer1Id; + public Long lecturer2Id; + public Long lecturer3Id; + public Long participant1Id; + public Long participant2Id; + public Long lesson1Id; + public Long lesson2Id; + public Long lesson3Id; + public Long lesson4Id; + public Long lesson5Id; + public Long coursePlatform1Id; + public Long coursePlatform2Id; + public Long metadata1Id; + public Long metadata2Id; + public Long material1Id; + public Long material2Id; + public Long material3Id; + public Long material4Id; + public Long material5Id; + public Long materialServer1Id; + public Long materialServer2Id; + public Long materialServer3Id; + public Long course1Id; + public Long course2Id; + public Long course3Id; + public Long course4Id; + + public static Date createDate(int year, int month, int day, int hours, int minutes) { + GregorianCalendar cal = new GregorianCalendar(year, month, day, hours, minutes); + cal.setTimeZone(TimeZone.getTimeZone("UTC")); + return cal.getTime(); + } + + @Override + public void insert(IModelFactory modelFactory, EntityManager em) { + MessageDigest md = getMessageDigest(); + + // Addresses + IAddress address1 = modelFactory.createAddress(); + IAddress address2 = modelFactory.createAddress(); + IAddress address3 = modelFactory.createAddress(); + IAddress address4 = modelFactory.createAddress(); + IAddress address5 = modelFactory.createAddress(); + + address1.setCity("city1"); + address1.setStreet("street1"); + address1.setZipCode("zip1"); + + address2.setCity("city2"); + address2.setStreet("street2"); + address2.setZipCode("zip2"); + + address3.setCity("city3"); + address3.setStreet("street3"); + address3.setZipCode("zip3"); + + address4.setCity("city4"); + address4.setStreet("street4"); + address4.setZipCode("zip4"); + + address5.setCity("city5"); + address5.setStreet("street5"); + address5.setZipCode("zip5"); + + // Lecturers + ILecturer lecturer1 = modelFactory.createLecturer(); + ILecturer lecturer2 = modelFactory.createLecturer(); + ILecturer lecturer3 = modelFactory.createLecturer(); + + lecturer1.setName(LECTURER_1_NAME); + lecturer1.setAddress(address1); + + lecturer2.setName(LECTURER_2_NAME); + lecturer2.setAddress(address2); + + lecturer3.setName(LECTURER_3_NAME); + lecturer3.setAddress(address5); + + // Participants + IParticipant participant1 = modelFactory.createParticipant(); + participant1.setName(PARTICIPANT_1_NAME); + participant1.setAddress(address3); + participant1.setAccountNo(PARTICIPANT_1_ACCOUNT_NO); + participant1.setBankCode(PARTICIPANT_1_BANK_CODE); + participant1.setEmail(PARTICIPANT_1_EMAIL); + participant1.setPassword(md.digest(PARTICIPANT_1_PW.getBytes())); + + IParticipant participant2 = modelFactory.createParticipant(); + participant2.setName(PARTICIPANT_2_NAME); + participant2.setAddress(address4); + participant2.setAccountNo(PARTICIPANT_2_ACCOUNT_NO); + participant2.setBankCode(PARTICIPANT_2_BANK_CODE); + participant2.setEmail(PARTICIPANT_2_EMAIL); + participant2.setPassword(md.digest(PARTICIPANT_2_PW.getBytes())); + + // Materials + IMaterial material1 = modelFactory.createMaterial(); + material1.setUrn(MATERIAL_1_URN); + material1.setType("MPEG"); + material1.setUploaded(new Date()); + material1.setLastUpdate(new Date()); + + IMaterial material2 = modelFactory.createMaterial(); + material2.setUrn(MATERIAL_2_URN); + material2.setType("PDF"); + material2.setUploaded(new Date()); + material2.setLastUpdate(new Date()); + + IMaterial material3 = modelFactory.createMaterial(); + material3.setUrn(MATERIAL_3_URN); + material3.setType("PNG"); + material3.setUploaded(new Date()); + material3.setLastUpdate(new Date()); + + IMaterial material4 = modelFactory.createMaterial(); + material4.setUrn(MATERIAL_4_URN); + material4.setType("PDF"); + material4.setUploaded(new Date()); + material4.setLastUpdate(new Date()); + + IMaterial material5 = modelFactory.createMaterial(); + material5.setUrn(MATERIAL_5_URN); + material5.setType("PNG"); + material5.setUploaded(new Date()); + material5.setLastUpdate(new Date()); + + // Material Servers + IMaterialServer materialServer1 = modelFactory.createMaterialServer(); + materialServer1.setName(MATERIAL_SERVER_1_NAME); + materialServer1.setLastMaintenance(new Date()); + materialServer1.setNextMaintenance(new Date()); + + IMaterialServer materialServer2 = modelFactory.createMaterialServer(); + materialServer2.setName(MATERIAL_SERVER_2_NAME); + materialServer2.setLastMaintenance(new Date()); + materialServer2.setNextMaintenance(new Date()); + + IMaterialServer materialServer3 = modelFactory.createMaterialServer(); + materialServer3.setName(MATERIAL_SERVER_3_NAME); + materialServer3.setLastMaintenance(new Date()); + materialServer3.setNextMaintenance(new Date()); + + materialServer1.addMaterial(material1); + materialServer1.addMaterial(material2); + material1.addMaterialServer(materialServer1); + material2.addMaterialServer(materialServer1); + + materialServer2.addMaterial(material2); + materialServer2.addMaterial(material3); + materialServer2.addMaterial(material4); + material2.addMaterialServer(materialServer2); + material3.addMaterialServer(materialServer2); + material4.addMaterialServer(materialServer2); + + materialServer3.addMaterial(material3); + materialServer3.addMaterial(material4); + materialServer3.addMaterial(material5); + material3.addMaterialServer(materialServer3); + material4.addMaterialServer(materialServer3); + material5.addMaterialServer(materialServer3); + + // Metadata + IMetadata metadata1 = modelFactory.createMetadata(); + metadata1.putData(METADATA_1_KEY_1, METADATA_1_VALUE_1); + metadata1.putData(METADATA_1_KEY_2, METADATA_1_VALUE_2); + + IMetadata metadata2 = modelFactory.createMetadata(); + metadata1.putData(METADATA_2_KEY_1, METADATA_2_VALUE_1); + + IMetadata metadata3 = modelFactory.createMetadata(); + IMetadata metadata4 = modelFactory.createMetadata(); + + // Course + ICourse course1 = modelFactory.createCourse(); + course1.setName(COURSE_1_NAME); + course1.setStatus(CourseStatus.CREATED); + course1.setPremium(true); + course1.setCost(new BigDecimal(1337)); + course1.setStart(createDate(2018, 1, 1, 8, 0)); + course1.setEnd(createDate(2019, 1, 31, 17, 0)); + course1.setCapacity(10); + + ICourse course2 = modelFactory.createCourse(); + course2.setName(COURSE_2_NAME); + course2.setStatus(CourseStatus.ONGOING); + course2.setPremium(false); + course2.setCost(new BigDecimal(0)); + course2.setStart(createDate(2018, 2, 1, 8, 0)); + course2.setEnd(createDate(2019, 6, 30, 17, 0)); + course2.setCapacity(2); + + ICourse course3 = modelFactory.createCourse(); + course3.setName(COURSE_3_NAME); + course3.setStatus(CourseStatus.ONGOING); + course3.setPremium(true); + course3.setCost(new BigDecimal(0)); + course3.setStart(createDate(2018, 2, 1, 8, 0)); + course3.setEnd(createDate(2019, 6, 30, 17, 0)); + course3.setCapacity(0); + + ICourse course4 = modelFactory.createCourse(); + course4.setName(COURSE_4_NAME); + course4.setStatus(CourseStatus.CREATED); + course4.setPremium(true); + course4.setCost(new BigDecimal(0)); + course4.setStart(createDate(2018, 2, 1, 8, 0)); + course4.setEnd(createDate(2019, 6, 30, 17, 0)); + course4.setCapacity(10); + + course1.setMetadata(metadata1); + course2.setMetadata(metadata2); + course3.setMetadata(metadata3); + course4.setMetadata(metadata4); + + course1.setLecturer(lecturer1); + lecturer1.addCourse(course1); + course2.setLecturer(lecturer2); + lecturer2.addCourse(course2); + + // enrollments + IEnrollmentKey ekey1 = modelFactory.createEnrollmentKey(); + ekey1.setParticipant(participant1); + ekey1.setCourse(course1); + + IEnrollment enrollment1 = modelFactory.createEnrollment(); + enrollment1.setId(ekey1); + enrollment1.setEnrolledAt(new Date()); + + course1.addEnrollment(enrollment1); + participant1.addEnrollment(enrollment1); + + IEnrollmentKey ekey2 = modelFactory.createEnrollmentKey(); + ekey2.setParticipant(participant2); + ekey2.setCourse(course2); + + IEnrollment enrollment2 = modelFactory.createEnrollment(); + enrollment2.setId(ekey2); + enrollment2.setEnrolledAt(new Date()); + + course2.addEnrollment(enrollment2); + participant2.addEnrollment(enrollment2); + + + // Course Platform + ICoursePlatform coursePlatform1 = modelFactory.createCoursePlatform(); + coursePlatform1.setName(COURSE_PLATFORM_1_NAME); + coursePlatform1.setUrl("https://www.openmoocs.com"); + + ICoursePlatform coursePlatform2 = modelFactory.createCoursePlatform(); + coursePlatform2.setName(COURSE_PLATFORM_2_NAME); + coursePlatform2.setUrl("https://www.youdecity.com"); + + coursePlatform1.addMaterialServer(materialServer1); + coursePlatform1.addMaterialServer(materialServer2); + coursePlatform2.addMaterialServer(materialServer3); + + course1.setCoursePlatform(coursePlatform1); + course2.setCoursePlatform(coursePlatform2); + course3.setCoursePlatform(coursePlatform2); + course4.setCoursePlatform(coursePlatform2); + + // Memberships + IMembership membership1 = modelFactory.createMembership(); + membership1.setDiscount(200.0); + membership1.setPremium(true); + membership1.setParticipant(participant1); + membership1.setCoursePlatform(coursePlatform1); + participant1.addMembership(membership1); + + IMembership membership2 = modelFactory.createMembership(); + membership2.setDiscount(0.0); + membership2.setPremium(false); + membership2.setParticipant(participant1); + membership2.setCoursePlatform(coursePlatform2); + participant1.addMembership(membership2); + + IMembership membership3 = modelFactory.createMembership(); + membership3.setDiscount(10.0); + membership3.setPremium(false); + membership3.setParticipant(participant2); + membership3.setCoursePlatform(coursePlatform1); + participant2.addMembership(membership3); + + // Lesson + ILesson lesson1 = modelFactory.createLesson(); + lesson1.setDescription(LESSON_1_DESC); + lesson1.setStart(createDate(2018, 1, 6, 11, 1)); // date in the past! + lesson1.setEnd(createDate(2018, 1, 6, 12, 1)); + + ILesson lesson2 = modelFactory.createLesson(); + lesson2.setDescription(LESSON_2_DESC); + lesson2.setStart(createDate(2018, 10, 3, 11, 2)); + lesson2.setEnd(createDate(2018, 10, 3, 12, 2)); + + ILesson lesson3 = modelFactory.createLesson(); + lesson3.setDescription(LESSON_3_DESC); + lesson3.setStart(createDate(2018, 10, 4, 11, 3)); + lesson3.setEnd(createDate(2018, 10, 4, 12, 3)); + + ILesson lesson4 = modelFactory.createLesson(); + lesson4.setDescription(LESSON_4_DESC); + lesson4.setStart(createDate(2018, 10, 5, 11, 4)); + lesson4.setEnd(createDate(2018, 10, 5, 12, 4)); + + ILesson lesson5 = modelFactory.createLesson(); + lesson5.setDescription(LESSON_5_DESC); + lesson5.setStart(createDate(2018, 12, 1, 11, 5)); + lesson5.setEnd(createDate(2018, 12, 0, 12, 5)); + + lesson1.addLecturer(lecturer1); + lecturer1.addLesson(lesson1); + lesson1.addLecturer(lecturer2); + lecturer2.addLesson(lesson1); + lesson2.addLecturer(lecturer2); + lecturer2.addLesson(lesson2); + lesson3.addLecturer(lecturer3); + lecturer3.addLesson(lesson3); + lesson4.addLecturer(lecturer1); + lecturer1.addLesson(lesson4); + lesson5.addLecturer(lecturer2); + lecturer2.addLesson(lesson5); + + lesson1.addRequiredByLesson(lesson2); + lesson1.addRequiredByLesson(lesson3); + lesson2.addRequiredLesson(lesson1); + lesson3.addRequiredLesson(lesson1); + lesson2.addRequiredByLesson(lesson4); + lesson3.addRequiredByLesson(lesson4); + lesson4.addRequiredLesson(lesson2); + lesson4.addRequiredLesson(lesson3); + + lesson1.setCourse(course1); + lesson2.setCourse(course1); + lesson3.setCourse(course1); + lesson4.setCourse(course1); + course1.addLesson(lesson1); + course1.addLesson(lesson2); + course1.addLesson(lesson3); + course1.addLesson(lesson4); + lesson5.setCourse(course2); + course2.addLesson(lesson5); + + lesson1.addMaterial(material1); + material1.setLesson(lesson1); + lesson2.addMaterial(material2); + material2.setLesson(lesson2); + lesson3.addMaterial(material3); + material3.setLesson(lesson3); + lesson3.addMaterial(material4); + material4.setLesson(lesson3); + lesson3.addMaterial(material5); + material5.setLesson(lesson3); + + // Persist all the things! + em.persist(lecturer1); + em.persist(lecturer2); + em.persist(lecturer3); + em.persist(participant1); + em.persist(participant2); + em.persist(lesson1); + em.persist(lesson2); + em.persist(lesson3); + em.persist(lesson4); + em.persist(lesson5); + em.persist(coursePlatform1); + em.persist(coursePlatform2); + em.persist(metadata1); + em.persist(metadata2); + em.persist(metadata3); + em.persist(metadata4); + em.persist(material1); + em.persist(material2); + em.persist(material3); + em.persist(material4); + em.persist(material5); + em.persist(materialServer1); + em.persist(materialServer2); + em.persist(materialServer3); + em.persist(course1); + em.persist(course2); + em.persist(course3); + em.persist(course4); + em.persist(enrollment1); + em.persist(enrollment2); + em.persist(membership1); + em.persist(membership2); + em.persist(membership3); + + lecturer1Id = lecturer1.getId(); + lecturer2Id = lecturer2.getId(); + lecturer3Id = lecturer3.getId(); + participant1Id = participant1.getId(); + participant2Id = participant2.getId(); + lesson1Id = lesson1.getId(); + lesson2Id = lesson2.getId(); + lesson3Id = lesson3.getId(); + lesson4Id = lesson4.getId(); + lesson5Id = lesson5.getId(); + coursePlatform1Id = coursePlatform1.getId(); + coursePlatform2Id = coursePlatform2.getId(); + metadata1Id = metadata1.getId(); + metadata2Id = metadata2.getId(); + material1Id = material1.getId(); + material2Id = material2.getId(); + material3Id = material3.getId(); + material4Id = material4.getId(); + material5Id = material5.getId(); + materialServer1Id = materialServer1.getId(); + materialServer2Id = materialServer2.getId(); + materialServer3Id = materialServer3.getId(); + course1Id = course1.getId(); + course2Id = course2.getId(); + course3Id = course3.getId(); + course4Id = course3.getId(); + + em.flush(); + } + + private MessageDigest getMessageDigest() { + try { + return MessageDigest.getInstance("SHA1"); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException(e); + } + } + +} diff --git a/ass1-jpa/src/test/java/dst/ass1/jpa/tests/UniqueConstraintTester.java b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/UniqueConstraintTester.java new file mode 100644 index 0000000..7e13ad3 --- /dev/null +++ b/ass1-jpa/src/test/java/dst/ass1/jpa/tests/UniqueConstraintTester.java @@ -0,0 +1,58 @@ +package dst.ass1.jpa.tests; + +import static org.junit.Assert.fail; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +import javax.persistence.EntityManager; +import javax.persistence.EntityTransaction; +import javax.persistence.PersistenceException; + +import org.hibernate.exception.ConstraintViolationException; + +/** + * Tests a unique constraint by creating two instances of an entity, calling the same value setter on each entity, + * and finally trying to persist them. + * + * @param the entity type + */ +public class UniqueConstraintTester { + + private Consumer valueSetter; + private E e1; + private E e2; + + public UniqueConstraintTester(E e1, E e2, Consumer valueSetter) { + this.e1 = e1; + this.e2 = e2; + this.valueSetter = valueSetter; + } + + public UniqueConstraintTester(Supplier entityFactory, Consumer valueSetter) { + this(entityFactory.get(), entityFactory.get(), valueSetter); + } + + public void run(EntityManager em) { + EntityTransaction tx = em.getTransaction(); + if (!tx.isActive()) { + tx.begin(); + } + + valueSetter.accept(e1); + em.persist(e1); + em.flush(); + + try { + valueSetter.accept(e2); + em.persist(e2); + em.flush(); + fail("Missing unique constraint in " + e2.getClass()); + } catch (PersistenceException e) { + Throwable cause = e.getCause(); + if (!(cause instanceof ConstraintViolationException)) { + fail("Missing unique constraint in " + e2.getClass()); + } + } + } +} diff --git a/ass1-jpa/src/test/resources/logback.xml b/ass1-jpa/src/test/resources/logback.xml new file mode 100644 index 0000000..0e0ca75 --- /dev/null +++ b/ass1-jpa/src/test/resources/logback.xml @@ -0,0 +1,16 @@ + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} - %highlight(%5p) [%12.12thread] %cyan(%-40.40logger{39}): %m%n + + + + + + + + + + diff --git a/ass1-kv/pom.xml b/ass1-kv/pom.xml new file mode 100644 index 0000000..7ea8ee3 --- /dev/null +++ b/ass1-kv/pom.xml @@ -0,0 +1,27 @@ + + + + 4.0.0 + + + at.ac.tuwien.infosys.dst + dst + 2018.1 + .. + + + ass1-kv + + jar + + DST :: Assignment 1 :: Key-Value Store + + + + redis.clients + jedis + + + + diff --git a/ass1-kv/src/main/java/dst/ass1/kv/ISessionManager.java b/ass1-kv/src/main/java/dst/ass1/kv/ISessionManager.java new file mode 100644 index 0000000..0a8f47d --- /dev/null +++ b/ass1-kv/src/main/java/dst/ass1/kv/ISessionManager.java @@ -0,0 +1,69 @@ +package dst.ass1.kv; + +public interface ISessionManager { + + /** + * Creates a new session id and stores the userId and session timeout under the given id in the session store. + * + * @param userId the user to create the session for + * @param timeToLive the session timeout after which the session expires in seconds + * @return the session id. + * @throws SessionCreationFailedException if the session couldn't be created, e.g., due to a failed transaction + */ + String createSession(Long userId, int timeToLive) throws SessionCreationFailedException; + + /** + * Sets a key--value pair in the given session. + * + * @param sessionId the session to store the variable in + * @param key the name of the variable + * @param value the value + * @throws SessionNotFoundException if the session wasn't found + */ + void setSessionVariable(String sessionId, String key, String value) throws SessionNotFoundException; + + /** + * Returns the value of the given session variable. + * + * @param sessionId the session id + * @param key the name of the variable + * @return the variable value, or null if it doesn't exist + * @throws SessionNotFoundException if the given session id has expired or doesn't exist + */ + String getSessionVariable(String sessionId, String key) throws SessionNotFoundException; + + /** + * Returns the user to whom the given session belongs. + * + * @param sessionId the session id + * @return the user id + * @throws SessionNotFoundException if the given session id has expired or doesn't exist + */ + Long getUserId(String sessionId) throws SessionNotFoundException; + + /** + * Returns the current time-to-live for the given session. + * + * @param sessionId the session id + * @return the session ttl in seconds + * @throws SessionNotFoundException if the given session id has expired or doesn't exist + */ + int getTimeToLive(String sessionId) throws SessionNotFoundException; + + /** + * Checks whether the given user has an open session, if so, the session id is returned (and the timeout + * parameter ignored), otherwise a new session is created with the given timeout and the newly generated id is + * returned. + * + * @param userId the user to require the session for + * @param timeToLive the session timeout after which the session expires in seconds + * @return the session id. + * @throws SessionCreationFailedException if the session couldn't be created, e.g., due to a failed transaction + */ + String requireSession(Long userId, int timeToLive) throws SessionCreationFailedException; + + /** + * Closes whatever underlying connection is required to maintain the session manager. + */ + void close(); +} diff --git a/ass1-kv/src/main/java/dst/ass1/kv/ISessionManagerFactory.java b/ass1-kv/src/main/java/dst/ass1/kv/ISessionManagerFactory.java new file mode 100644 index 0000000..ddca19c --- /dev/null +++ b/ass1-kv/src/main/java/dst/ass1/kv/ISessionManagerFactory.java @@ -0,0 +1,15 @@ +package dst.ass1.kv; + +import java.util.Properties; + +import dst.ass1.kv.ISessionManager; + +public interface ISessionManagerFactory { + /** + * Creates an implementation of an {@link ISessionManager}. + * + * @param properties the properties to use for instantiation + * @return a session manager object + */ + ISessionManager createSessionManager(Properties properties); +} diff --git a/ass1-kv/src/main/java/dst/ass1/kv/SessionCreationFailedException.java b/ass1-kv/src/main/java/dst/ass1/kv/SessionCreationFailedException.java new file mode 100644 index 0000000..b571a94 --- /dev/null +++ b/ass1-kv/src/main/java/dst/ass1/kv/SessionCreationFailedException.java @@ -0,0 +1,25 @@ +package dst.ass1.kv; + +/** + * Exception indicating that a request to create a new session could not be fulfilled. + */ +public class SessionCreationFailedException extends Exception { + + private static final long serialVersionUID = 1L; + + public SessionCreationFailedException() { + } + + public SessionCreationFailedException(String message) { + super(message); + } + + public SessionCreationFailedException(String message, Throwable cause) { + super(message, cause); + } + + public SessionCreationFailedException(Throwable cause) { + super(cause); + } + +} diff --git a/ass1-kv/src/main/java/dst/ass1/kv/SessionNotFoundException.java b/ass1-kv/src/main/java/dst/ass1/kv/SessionNotFoundException.java new file mode 100644 index 0000000..a548198 --- /dev/null +++ b/ass1-kv/src/main/java/dst/ass1/kv/SessionNotFoundException.java @@ -0,0 +1,24 @@ +package dst.ass1.kv; + +/** + * Exception to indicate that this is not the session you are looking for. + */ +public class SessionNotFoundException extends Exception { + + private static final long serialVersionUID = 1L; + + public SessionNotFoundException() { + } + + public SessionNotFoundException(String message) { + super(message); + } + + public SessionNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + public SessionNotFoundException(Throwable cause) { + super(cause); + } +} diff --git a/ass1-kv/src/main/java/dst/ass1/kv/impl/SessionManagerFactory.java b/ass1-kv/src/main/java/dst/ass1/kv/impl/SessionManagerFactory.java new file mode 100644 index 0000000..4b0a721 --- /dev/null +++ b/ass1-kv/src/main/java/dst/ass1/kv/impl/SessionManagerFactory.java @@ -0,0 +1,17 @@ +package dst.ass1.kv.impl; + +import java.util.Properties; + +import dst.ass1.kv.ISessionManager; +import dst.ass1.kv.ISessionManagerFactory; + +public class SessionManagerFactory implements ISessionManagerFactory { + + @Override + public ISessionManager createSessionManager(Properties properties) { + // TODO + // read "redis.host" and "redis.port" from the properties + + return null; + } +} diff --git a/ass1-kv/src/test/java/dst/ass1/kv/RedisCleaner.java b/ass1-kv/src/test/java/dst/ass1/kv/RedisCleaner.java new file mode 100644 index 0000000..08c7768 --- /dev/null +++ b/ass1-kv/src/test/java/dst/ass1/kv/RedisCleaner.java @@ -0,0 +1,61 @@ +package dst.ass1.kv; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import org.junit.rules.ExternalResource; + +import redis.clients.jedis.Jedis; + +/** + * Drops the entire key space of a redis instance before and after a test run. + */ +public class RedisCleaner extends ExternalResource { + + private Properties properties; + private Jedis jedis; + + @Override + protected void before() throws IOException { + properties = loadProperties(); + + String host = properties.getProperty("redis.host"); + int port = Integer.parseInt(properties.getProperty("redis.port")); + jedis = new Jedis(host, port); + + // completely clear the redis instance before each test + jedis.flushAll(); + } + + @Override + protected void after() { + // completely clear the redis instance after each test + try { + jedis.flushAll(); + } finally { + // close the connection pool + jedis.close(); + } + } + + /** + * @return loaded redis properties + */ + public Properties getProperties() { + return properties; + } + + public Jedis getJedis() { + return jedis; + } + + private Properties loadProperties() throws IOException { + Properties properties = new Properties(); + try (InputStream in = getClass().getClassLoader().getResourceAsStream("redis.properties")) { + properties.load(in); + } + return properties; + } + +} diff --git a/ass1-kv/src/test/java/dst/ass1/kv/tests/Ass1_5_1Test.java b/ass1-kv/src/test/java/dst/ass1/kv/tests/Ass1_5_1Test.java new file mode 100644 index 0000000..ec8fbd8 --- /dev/null +++ b/ass1-kv/src/test/java/dst/ass1/kv/tests/Ass1_5_1Test.java @@ -0,0 +1,113 @@ +package dst.ass1.kv.tests; + +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.lessThan; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import dst.ass1.kv.ISessionManager; +import dst.ass1.kv.ISessionManagerFactory; +import dst.ass1.kv.RedisCleaner; +import dst.ass1.kv.SessionNotFoundException; +import dst.ass1.kv.impl.SessionManagerFactory; + +public class Ass1_5_1Test { + + @Rule + public RedisCleaner redisRule = new RedisCleaner(); + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private ISessionManager sessionManager; + + @Before + public void setUp() { + ISessionManagerFactory sessionManagerFactory = new SessionManagerFactory(); + + sessionManager = sessionManagerFactory.createSessionManager(redisRule.getProperties()); + } + + @After + public void tearDown() { + sessionManager.close(); + } + + @Test + public void createSession_createsSessionId() throws Exception { + String sessionId = sessionManager.createSession(1337L, 15000); + assertNotNull(sessionId); + } + + @Test + public void getAndSetSessionVariable_behavesCorrectly() throws Exception { + String sessionId = sessionManager.createSession(1337L, 15000); + sessionManager.setSessionVariable(sessionId, "f00", "bar"); + assertEquals("bar", sessionManager.getSessionVariable(sessionId, "f00")); + } + + @Test(expected = SessionNotFoundException.class) + public void setSessionVariable_forNonExistingSession_throwsSessionNotFoundException() throws Exception { + sessionManager.setSessionVariable("nonExistingSessionId", "f00", "bar"); + } + + @Test(expected = SessionNotFoundException.class) + public void getSessionVariable_forNonExistingSession_throwsSessionNotFoundException() throws Exception { + sessionManager.getSessionVariable("nonExistingSessionId", "f00"); + } + + @Test + public void getSessionVariable_onNonExistingVariable_returnsNull() throws Exception { + String sessionId = sessionManager.createSession(1337L, 15000); + String value = sessionManager.getSessionVariable(sessionId, "f00"); + assertNull(value); + } + + @Test + public void getUserId_returnsCorrectUserID() throws Exception { + Long userId = 1337L; + String sessionId = sessionManager.createSession(userId, 15000); + assertEquals(userId, sessionManager.getUserId(sessionId)); + } + + @Test(expected = SessionNotFoundException.class) + public void getUserId_forNonExistingSession_throwsException() throws Exception { + sessionManager.getUserId("nonExistingSessionId"); + } + + @Test + public void getTimeToLive_returnsCorrectValue() throws Exception { + String sessionId = sessionManager.createSession(1337L, 60); + int ttl = sessionManager.getTimeToLive(sessionId); + assertThat(ttl, allOf(greaterThan(57), lessThan(61))); + } + + @Test + public void getTimeToLive_afterExpiry_throwsSessionNotFoundException() throws Exception { + String sessionId = sessionManager.createSession(1337L, 2); + int ttl = sessionManager.getTimeToLive(sessionId); + assertThat(ttl, greaterThan(0)); + Thread.sleep(3000); + + expectedException.expect(SessionNotFoundException.class); + sessionManager.getTimeToLive(sessionId); + } + + @Test(expected = SessionNotFoundException.class) + public void getTimeToLive_forNonExistingSession_throwsSessionNotFoundException() throws Exception { + sessionManager.getTimeToLive("nonExistingSessionId"); + } + +} \ No newline at end of file diff --git a/ass1-kv/src/test/java/dst/ass1/kv/tests/Ass1_5_2Test.java b/ass1-kv/src/test/java/dst/ass1/kv/tests/Ass1_5_2Test.java new file mode 100644 index 0000000..380d36c --- /dev/null +++ b/ass1-kv/src/test/java/dst/ass1/kv/tests/Ass1_5_2Test.java @@ -0,0 +1,51 @@ +package dst.ass1.kv.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import dst.ass1.kv.ISessionManager; +import dst.ass1.kv.ISessionManagerFactory; +import dst.ass1.kv.RedisCleaner; +import dst.ass1.kv.impl.SessionManagerFactory; + +public class Ass1_5_2Test { + + @Rule + public RedisCleaner redisRule = new RedisCleaner(); + + private ISessionManager sessionManager; + + @Before + public void setUp() { + ISessionManagerFactory sessionManagerFactory = new SessionManagerFactory(); + + sessionManager = sessionManagerFactory.createSessionManager(redisRule.getProperties()); + } + + @After + public void tearDown() { + sessionManager.close(); + } + + @Test + public void testRequireSessionForExistingSession_existingIdReturned() throws Exception { + String newId = sessionManager.createSession(1337L, 30000); + assertNotNull(newId); + + String requiredId = sessionManager.requireSession(1337L, 15000); + assertEquals(newId, requiredId); + } + + @Test + public void testRequireSessionForNonExistingSession_newSessionCreated() throws Exception { + String sessionId = sessionManager.requireSession(1337L, 15000); + + assertEquals(Long.valueOf(1337L), sessionManager.getUserId(sessionId)); + } + +} \ No newline at end of file diff --git a/ass1-kv/src/test/java/dst/ass1/kv/tests/Ass1_5_Suite.java b/ass1-kv/src/test/java/dst/ass1/kv/tests/Ass1_5_Suite.java new file mode 100644 index 0000000..e9593aa --- /dev/null +++ b/ass1-kv/src/test/java/dst/ass1/kv/tests/Ass1_5_Suite.java @@ -0,0 +1,13 @@ +package dst.ass1.kv.tests; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + Ass1_5_1Test.class, + Ass1_5_2Test.class +}) +public class Ass1_5_Suite { +} diff --git a/ass1-kv/src/test/resources/logback.xml b/ass1-kv/src/test/resources/logback.xml new file mode 100644 index 0000000..e16fad1 --- /dev/null +++ b/ass1-kv/src/test/resources/logback.xml @@ -0,0 +1,14 @@ + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} - %highlight(%5p) [%12.12thread] %cyan(%-40.40logger{39}): %m%n + + + + + + + + diff --git a/ass1-kv/src/test/resources/redis.properties b/ass1-kv/src/test/resources/redis.properties new file mode 100644 index 0000000..c1bbd02 --- /dev/null +++ b/ass1-kv/src/test/resources/redis.properties @@ -0,0 +1,4 @@ +# you can change this to, e.g., 127.0.0.1 if you have a local redis instance +redis.host=192.168.99.99 +#redis.host=127.0.0.1 +redis.port=6379 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..98887aa --- /dev/null +++ b/pom.xml @@ -0,0 +1,272 @@ + + + 4.0.0 + + at.ac.tuwien.infosys.dst + dst + 2018.1 + + DST :: Parent + + pom + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + false + alphabetical + + + + org.apache.maven.plugins + maven-jar-plugin + ${maven-jar-plugin.version} + + + + + test-jar + + + + + true + + + + com.spotify + dockerfile-maven-plugin + ${maven-dockerfile-plugin.version} + + + build-and-tag-latest + package + + build + + + + tag-version + package + + tag + + + ${project.version} + + + + + tuw-dst/${project.artifactId} + + + + org.apache.maven.plugins + maven-dependency-plugin + ${maven-dependency-plugin.version} + + + prepare-package + + copy-dependencies + + + + + false + false + true + runtime + ${project.build.directory}/lib + + + + + + + + + javax + javaee-api + 8.0 + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + junit + junit + + + org.hamcrest + hamcrest-all + + + + + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + ch.qos.logback + logback-classic + ${logback.version} + + + junit + junit + ${junit.version} + test + + + org.hamcrest + hamcrest-all + ${hamcrest.version} + test + + + + + org.hibernate + hibernate-core + ${hibernate.version} + + + + org.hibernate.javax.persistence + hibernate-jpa-2.1-api + + + + + com.h2database + h2 + ${h2.version} + + + org.mongodb + mongodb-driver + ${mongodb.version} + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + ${flapdoodle.version} + + + redis.clients + jedis + ${jedis.version} + + + + org.javassist + javassist + ${javassist.version} + + + + + + + + all + + ass1-jpa + ass1-doc + ass1-kv + + + + + ass1-jpa + + ass1-jpa + + + + + ass1-kv + + ass1-kv + + + + + ass1-doc + + ass1-doc + + + + + + + + + UTF-8 + + 3.7.0 + 2.20.1 + 1.3.7 + 3.0.2 + 3.0.2 + 2.20.1 + + + 1.7.25 + 1.2.3 + 3.7 + 4.12 + 1.3 + + 5.2.13.Final + 2.9.0 + 3.20.0-GA + 1.4.196 + 3.6.1 + 2.0.0 + + + + diff --git a/vm/Vagrantfile b/vm/Vagrantfile new file mode 100644 index 0000000..24bc4b8 --- /dev/null +++ b/vm/Vagrantfile @@ -0,0 +1,11 @@ +Vagrant.configure("2") do |config| + # ... other config up here + config.vm.box = "dst/18" + + config.vm.hostname = "dst18-vm" + config.vm.network :private_network, ip: "192.168.99.99" + + # Prefer VirtualBox before VMware Fusion + config.vm.provider "virtualbox" + config.vm.provider "vmware_fusion" +end -- 2.43.0