diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/profile/DevGuiProfile.java b/src/main/java/ch/ethz/seb/sebserver/gbl/profile/DevGuiProfile.java new file mode 100644 index 00000000..b9ea6a16 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/profile/DevGuiProfile.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gbl.profile; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Profile; + +/** Profile annotation for SEB-Server dev-gui components. + * + * Use this as profile annotation on components that are only needed in the web-gui environment + * and only for development and/or testing */ +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Profile({ "dev-gui", "test" }) +public @interface DevGuiProfile { +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/profile/DevWebServiceProfile.java b/src/main/java/ch/ethz/seb/sebserver/gbl/profile/DevWebServiceProfile.java new file mode 100644 index 00000000..6a5636df --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/profile/DevWebServiceProfile.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gbl.profile; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Profile; + +/** Profile annotation for SEB-Server dev-ws components. + * + * Use this as profile annotation on components that are only needed in the web-service environment + * and only for development and/or testing */ +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Profile({ "dev-ws", "test" }) +public @interface DevWebServiceProfile { +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/profile/GuiProfile.java b/src/main/java/ch/ethz/seb/sebserver/gbl/profile/GuiProfile.java index 9a3708c9..4a3162c2 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/profile/GuiProfile.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/profile/GuiProfile.java @@ -15,6 +15,10 @@ import java.lang.annotation.Target; import org.springframework.context.annotation.Profile; +/** Profile annotation for SEB-Server gui components. + * + * Use this as profile annotation on components that are only needed in the web-gui environment + * but for all vertical profiles like dev, prod and test */ @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Profile({ "dev-gui", "prod-gui", "test" }) diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/profile/ProdGuiProfile.java b/src/main/java/ch/ethz/seb/sebserver/gbl/profile/ProdGuiProfile.java new file mode 100644 index 00000000..bfe6f2b7 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/profile/ProdGuiProfile.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gbl.profile; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Profile; + +/** Profile annotation for SEB-Server prod-gui components. + * + * Use this as profile annotation on components that are only needed in the gui-service environment + * and only for production and/or testing */ +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Profile({ "prod-gui", "test" }) +public @interface ProdGuiProfile { +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/profile/ProdWebServiceProfile.java b/src/main/java/ch/ethz/seb/sebserver/gbl/profile/ProdWebServiceProfile.java new file mode 100644 index 00000000..23db34ff --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/profile/ProdWebServiceProfile.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gbl.profile; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Profile; + +/** Profile annotation for SEB-Server prod-ws components. + * + * Use this as profile annotation on components that are only needed in the web-service environment + * and only for production and/or testing */ +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Retention(RetentionPolicy.RUNTIME) +@Profile({ "prod-ws", "test" }) +public @interface ProdWebServiceProfile { +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/profile/WebServiceProfile.java b/src/main/java/ch/ethz/seb/sebserver/gbl/profile/WebServiceProfile.java index 190e085a..da121b6d 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/profile/WebServiceProfile.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/profile/WebServiceProfile.java @@ -15,6 +15,10 @@ import java.lang.annotation.Target; import org.springframework.context.annotation.Profile; +/** Profile annotation for SEB-Server web-service components. + * + * Use this as profile annotation on components that are only needed in the web-service environment + * but for all vertical profiles like dev, prod and test */ @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Profile({ "dev-ws", "prod-ws", "test" }) diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/util/Result.java b/src/main/java/ch/ethz/seb/sebserver/gbl/util/Result.java index 1e565789..6d705c7a 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/util/Result.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/util/Result.java @@ -61,6 +61,10 @@ public final class Result { return this.error; } + public boolean hasError() { + return this.error != null; + } + /** Use this to get the resulting value or (if null) to get a given other value * * @param other the other value to get if the computed value is null @@ -69,10 +73,19 @@ public final class Result { return this.value != null ? this.value : other; } + /** Use this to get the resulting value or (if null) to get a given other value + * + * @param supplier supplier to get the value from if the computed value is null + * @return return either the computed value if existing or a given other value */ public T orElse(final Supplier supplier) { return this.value != null ? this.value : supplier.get(); } + /** Use this to map a given Result of type T to another Result of type U + * within a given mapping function. + * + * @param mapf the mapping function + * @return mapped Result of type U */ public Result map(final Function mapf) { if (this.error == null) { return Result.of(mapf.apply(this.value)); @@ -81,6 +94,11 @@ public final class Result { } } + /** Use this to map a given Result of type T to another Result of type U + * within a given mapping function. + * + * @param mapf the mapping function + * @return mapped Result of type U */ public Result flatMap(final Function> mapf) { if (this.error == null) { return mapf.apply(this.value); @@ -89,18 +107,16 @@ public final class Result { } } + /** Use this to get the resulting value. In an error case, a given error handling + * function is used that receives the error and returns a resulting value instead + * (or throw some error instead) + * + * @param errorHandler the error handling function + * @return */ public T onError(final Function errorHandler) { return this.error != null ? errorHandler.apply(this.error) : this.value; } - public static final Result of(final T value) { - return new Result<>(value); - } - - public static final Result ofError(final Throwable error) { - return new Result<>(error); - } - /** Use this to get the resulting value of existing or throw an Runtime exception with * given message otherwise. * @@ -113,4 +129,23 @@ public final class Result { return this.value; } + + /** Use this to create a Result of a given resulting value. + * + * @param value resulting value + * @return Result instance contains a resulting value and no error */ + public static final Result of(final T value) { + assert value != null : "value has null reference"; + return new Result<>(value); + } + + /** Use this to create a Result with error + * + * @param error the error that is wrapped within the created Result + * @return Result of specified error */ + public static final Result ofError(final Throwable error) { + assert error != null : "error has null reference"; + return new Result<>(error); + } + } diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java b/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java new file mode 100644 index 00000000..5087ad82 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gbl.util; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; + +public final class Utils { + + /** Use this to extract a single element from a Collection. This also checks if there is only a single element + * within the Collection. + * + * @param collection the Collection to extract the single and only element + * @return The single element + * @throws IllegalArgumentException if the collection is null, or empty or has more then one element */ + public static final Result getSingle(final Collection collection) { + if (collection == null || collection.isEmpty() || collection.size() > 1) { + return Result.ofError( + new IllegalArgumentException( + "Collection has no or more then one element. Expected is exaclty one. Size: " + + ((collection != null) ? collection.size() : "null"))); + } + + return Result.of(collection.iterator().next()); + } + + /** Use this to create an immutable Collection of specified type from varargs + * + * @param values elements of the new immutable Collection + * @return an immutable Collection of specified type with given elements */ + @SafeVarargs + public static final Collection immutableCollectionOf(final T... values) { + if (values == null || values.length <= 0) { + return Collections.emptyList(); + } + return Collections.unmodifiableCollection(Arrays.asList(values)); + } + + /** Use this to create an immutable Set of specified type from varargs + * + * @param values elements of the new immutable Set + * @return an immutable Set of specified type with given elements */ + @SafeVarargs + public static final Set immutableSetOf(final T... items) { + if (items == null || items.length <= 0) { + return Collections.emptySet(); + } + return Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(items))); + } + +} diff --git a/src/main/resources/config/application-dev-gui.properties b/src/main/resources/config/application-dev-gui.properties index 8f91c79e..47e4b48c 100644 --- a/src/main/resources/config/application-dev-gui.properties +++ b/src/main/resources/config/application-dev-gui.properties @@ -1,3 +1,4 @@ +server.address=localhost server.port=8080 - +server.servlet.context-path=/ diff --git a/src/main/resources/config/application-dev-ws.properties b/src/main/resources/config/application-dev-ws.properties index 499d496a..24d67784 100644 --- a/src/main/resources/config/application-dev-ws.properties +++ b/src/main/resources/config/application-dev-ws.properties @@ -1,7 +1,9 @@ +server.address=localhost +server.port=8090 +server.servlet.context-path=/api/ + spring.datasource.initialize=true spring.datasource.initialization-mode=always spring.datasource.url=jdbc:mariadb://localhost:6603/SEBServer?useSSL=false&createDatabaseIfNotExist=true spring.datasource.driver-class-name=org.mariadb.jdbc.Driver -spring.datasource.platform=dev - -server.port=8090 \ No newline at end of file +spring.datasource.platform=dev \ No newline at end of file diff --git a/src/test/java/ch/ethz/seb/sebserver/gbl/util/ResultTest.java b/src/test/java/ch/ethz/seb/sebserver/gbl/util/ResultTest.java new file mode 100644 index 00000000..62af900f --- /dev/null +++ b/src/test/java/ch/ethz/seb/sebserver/gbl/util/ResultTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gbl.util; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class ResultTest { + + @Test + public void testCreate() { + final Result of = Result.of("VALUE"); + final Result ofError = Result.ofError(new RuntimeException("Some Error")); + + assertNotNull(of.get()); + assertEquals("VALUE", of.get()); + + assertTrue(ofError.hasError()); + assertEquals("Some Error", ofError.getError().getMessage()); + + try { + Result.of(null); + fail("Exception expected"); + } catch (final Throwable t) { + assertEquals("value has null reference", t.getMessage()); + } + + try { + Result.ofError(null); + fail("Exception expected"); + } catch (final Throwable t) { + assertEquals("error has null reference", t.getMessage()); + } + } + + @Test + public void testMap() { + final Result resultOf = Result.of("1"); + final Result resultOfError = Result.ofError(new RuntimeException("Some Error")); + + final Result numberResult = resultOf.map(r -> Integer.parseInt(r)); + final Result numberResultOfError = resultOfError.map(r -> Integer.parseInt(r)); + + assertNotNull(numberResult); + assertEquals(Integer.valueOf(1), numberResult.get()); + + assertTrue(numberResultOfError.hasError()); + assertEquals("Some Error", numberResultOfError.getError().getMessage()); + } + + @Test + public void testFlatMap() { + final Result resultOf = Result.of("1"); + final Result resultOfError = Result.ofError(new RuntimeException("Some Error")); + + final Result numberResult = resultOf.flatMap(r -> Result.of(Integer.parseInt(r))); + final Result numberResultOfError = resultOfError.flatMap(r -> Result.of(Integer.parseInt(r))); + + assertNotNull(numberResult); + assertEquals(Integer.valueOf(1), numberResult.get()); + + assertTrue(numberResultOfError.hasError()); + assertEquals("Some Error", numberResultOfError.getError().getMessage()); + } + + @Test + public void testOrElse() { + final Result resultOf = Result.of("ONE"); + final Result resultOfError = Result.ofError(new RuntimeException("Some Error")); + + assertEquals("ONE", resultOf.orElse("TWO")); + assertEquals("TWO", resultOfError.orElse("TWO")); + + assertEquals("ONE", resultOf.orElse(() -> "TWO")); + assertEquals("TWO", resultOfError.orElse(() -> "TWO")); + } + + @Test + public void testOnError() { + final Result resultOf = Result.of("ONE"); + final Result resultOfError = Result.ofError(new RuntimeException("Some Error")); + + assertEquals("ONE", resultOf.onError(t -> t.getMessage())); + assertEquals("Some Error", resultOfError.onError(t -> t.getMessage())); + + assertEquals("ONE", resultOf.onErrorThrow("Should not be thrown")); + try { + resultOfError.onErrorThrow("Should be thrown"); + fail("Excpetion expected here"); + } catch (final Throwable t) { + assertEquals("Should be thrown", t.getMessage()); + assertEquals("Some Error", t.getCause().getMessage()); + } + } + +} diff --git a/src/test/java/ch/ethz/seb/sebserver/gbl/util/UtilsTest.java b/src/test/java/ch/ethz/seb/sebserver/gbl/util/UtilsTest.java new file mode 100644 index 00000000..d1c570aa --- /dev/null +++ b/src/test/java/ch/ethz/seb/sebserver/gbl/util/UtilsTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gbl.util; + +import static org.junit.Assert.*; + +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +import org.junit.Test; + +public class UtilsTest { + + @Test + public void testGetSingle() { + final Collection singleCollection = Utils.immutableCollectionOf("ONE"); + final Collection collection = Utils.immutableCollectionOf("ONE", "TWO"); + + final Result r1 = Utils.getSingle(null); + final Result r2 = Utils.getSingle(Collections.emptyList()); + final Result r3 = Utils.getSingle(singleCollection); + final Result r4 = Utils.getSingle(collection); + + assertTrue(r1.hasError()); + assertTrue(r2.hasError()); + assertFalse(r3.hasError()); + assertTrue(r4.hasError()); + + assertEquals("ONE", r3.get()); + assertEquals("Collection has no or more then one element. Expected is exaclty one. Size: null", + r1.getError().getMessage()); + assertEquals("Collection has no or more then one element. Expected is exaclty one. Size: 2", + r4.getError().getMessage()); + } + + @Test + public void testImmutableCollectionOf() { + final Collection r1 = Utils.immutableCollectionOf((String[]) null); + final Collection r2 = Utils.immutableCollectionOf((String) null); + final Collection r3 = Utils.immutableCollectionOf(null, null); + final Collection r4 = Utils.immutableCollectionOf("ONE", "TWO"); + + assertEquals("[]", r1.toString()); + assertEquals("[null]", r2.toString()); + assertEquals("[null, null]", r3.toString()); + assertEquals("[ONE, TWO]", r4.toString()); + } + + @Test + public void testImmutableSetOf() { + final Set r1 = Utils.immutableSetOf((String[]) null); + final Set r2 = Utils.immutableSetOf((String) null); + final Set r3 = Utils.immutableSetOf(null, null); + final Set r4 = Utils.immutableSetOf("ONE", "TWO"); + final Set r5 = Utils.immutableSetOf("ONE", "TWO", "ONE"); + + assertEquals("[]", r1.toString()); + assertEquals("[null]", r2.toString()); + assertEquals("[null]", r3.toString()); + assertEquals("[ONE, TWO]", r4.toString()); + assertEquals("[ONE, TWO]", r5.toString()); + } + +}