diff --git a/fanout-fanin/README.md b/fanout-fanin/README.md new file mode 100644 index 000000000..5f9cc8df5 --- /dev/null +++ b/fanout-fanin/README.md @@ -0,0 +1,120 @@ +--- +layout: pattern +title: Fan-Out/Fan-In +folder: fanout-fanin +permalink: /patterns/fanout-fanin/ +categories: Integration +language: en +tags: +- Microservices +--- + +## Intent +The pattern is used when a source system needs to run one or more long-running processes that will fetch some data. +The source will not block itself waiting for the reply.
The pattern will run the same function in multiple +services or machines to fetch the data. This is equivalent to invoking the function multiple times on different chunks of data. + +## Explanation +The FanOut/FanIn service will take in a list of requests and a consumer. Each request might complete at a different time. +FanOut/FanIn service will accept the input params and returns the initial system an ID to acknowledge that the pattern +service has received the requests. Now the caller will not wait or expect the result in the same connection. + +Meanwhile, the pattern service will invoke the requests that have come. The requests might complete at different time. +These requests will be processed in different instances of the same function in different machines or services. As the +requests get completed, a callback service everytime is called that transforms the result into a common single object format +that gets pushed to a consumer. The caller will be at the other end of the consumer receiving the result. + +**Programmatic Example** + +The implementation provided has a list of numbers and end goal is to square the numbers and add them to a single result. +`FanOutFanIn` class receives the list of numbers in the form of list of `SquareNumberRequest` and a `Consumer` instance +that collects the results as the requests get over. `SquareNumberRequest` will square the number with a random delay +to give the impression of a long-running process that can complete at any time. `Consumer` instance will add the results from +different `SquareNumberRequest` that will come random time instances. + +Let's look at `FanOutFanIn` class that fans out the requests in async processes. + +```java +public class FanOutFanIn { + public static Long fanOutFanIn( + final List requests, final Consumer consumer) { + + ExecutorService service = Executors.newFixedThreadPool(requests.size()); + + // fanning out + List> futures = + requests.stream() + .map( + request -> + CompletableFuture.runAsync(() -> request.delayedSquaring(consumer), service)) + .collect(Collectors.toList()); + + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); + + return consumer.getSumOfSquaredNumbers().get(); + } +} +``` + +`Consumer` is used a callback class that will be called when a request is completed. This will aggregate +the result from all requests. + +```java +public class Consumer { + + private final AtomicLong sumOfSquaredNumbers; + + Consumer(Long init) { + sumOfSquaredNumbers = new AtomicLong(init); + } + + public Long add(final Long num) { + return sumOfSquaredNumbers.addAndGet(num); + } +} +``` + +Request is represented as a `SquareNumberRequest` that squares the number with random delay and calls the +`Consumer` once it is squared. + +```java +public class SquareNumberRequest { + + private final Long number; + public void delayedSquaring(final Consumer consumer) { + + var minTimeOut = 5000L; + + SecureRandom secureRandom = new SecureRandom(); + var randomTimeOut = secureRandom.nextInt(2000); + + try { + // this will make the thread sleep from 5-7s. + Thread.sleep(minTimeOut + randomTimeOut); + } catch (InterruptedException e) { + LOGGER.error("Exception while sleep ", e); + Thread.currentThread().interrupt(); + } finally { + consumer.add(number * number); + } + } +} +``` + +## Class diagram +![alt-text](./etc/fanout-fanin.png) + +## Applicability + +Use this pattern when you can divide the workload into multiple chunks that can be dealt with separately. + +## Related patterns + +* [Aggregator Microservices](https://java-design-patterns.com/patterns/aggregator-microservices/) +* [API Gateway](https://java-design-patterns.com/patterns/api-gateway/) + +## Credits + +* [Understanding Azure Durable Functions - Part 8: The Fan Out/Fan In Pattern](http://dontcodetired.com/blog/post/Understanding-Azure-Durable-Functions-Part-8-The-Fan-OutFan-In-Pattern) +* [Fan-out/fan-in scenario in Durable Functions - Cloud backup example](https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-cloud-backup) +* [Understanding the Fan-Out/Fan-In API Integration Pattern](https://dzone.com/articles/understanding-the-fan-out-fan-in-api-integration-p) \ No newline at end of file diff --git a/fanout-fanin/etc/fanout-fanin.png b/fanout-fanin/etc/fanout-fanin.png new file mode 100644 index 000000000..e4b85006c Binary files /dev/null and b/fanout-fanin/etc/fanout-fanin.png differ diff --git a/fanout-fanin/etc/fanout-fanin.urm.puml b/fanout-fanin/etc/fanout-fanin.urm.puml new file mode 100644 index 000000000..57b741335 --- /dev/null +++ b/fanout-fanin/etc/fanout-fanin.urm.puml @@ -0,0 +1,39 @@ +@startuml +package com.iluwatar.fanout.fanin { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Consumer { + - sumOfSquaredNumbers : AtomicLong + ~ Consumer(init : Long) + + add(num : Long) : Long + + getSumOfSquaredNumbers() : AtomicLong + } + class FanOutFanIn { + + FanOutFanIn() + + fanOutFanIn(requests : List, consumer : Consumer) : Long {static} + } + class SquareNumberRequest { + - LOGGER : Logger {static} + - number : Long + + SquareNumberRequest(number : Long) + + delayedSquaring(consumer : Consumer) + } + + object SquareNumberRequest1 + object SquareNumberRequest2 + object SquareNumberRequest3 + diamond dia +} + +App --> FanOutFanIn +FanOutFanIn --> "fan out - running in parallel" SquareNumberRequest1 +FanOutFanIn --> "fan out" SquareNumberRequest2 +FanOutFanIn --> "fan out" SquareNumberRequest3 +SquareNumberRequest1 --> "fan in - aggregate using callback" dia +SquareNumberRequest2 --> "fan in" dia +SquareNumberRequest3 --> "fan in" dia +dia --> Consumer +@enduml \ No newline at end of file diff --git a/fanout-fanin/pom.xml b/fanout-fanin/pom.xml new file mode 100644 index 000000000..382cc342e --- /dev/null +++ b/fanout-fanin/pom.xml @@ -0,0 +1,69 @@ + + + + + java-design-patterns + com.iluwatar + 1.25.0-SNAPSHOT + + 4.0.0 + + fanout-fanin + + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.fanout.fanin.App + + + + + + + + + + \ No newline at end of file diff --git a/fanout-fanin/src/main/java/com/iluwatar/fanout/fanin/App.java b/fanout-fanin/src/main/java/com/iluwatar/fanout/fanin/App.java new file mode 100644 index 000000000..cc70ff141 --- /dev/null +++ b/fanout-fanin/src/main/java/com/iluwatar/fanout/fanin/App.java @@ -0,0 +1,74 @@ +/* + * The MIT License + * Copyright © 2014-2021 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.fanout.fanin; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; + + + +/** + * FanOut/FanIn pattern is a concurrency pattern that refers to executing multiple instances of the + * activity function concurrently. The "fan out" part is essentially splitting the data into + * multiple chunks and then calling the activity function multiple times, passing the chunks. + * + *

When each chunk has been processed, the "fan in" takes place that aggregates results from each + * instance of function and forms a single final result. + * + *

This pattern is only really useful if you can “chunk” the workload in a meaningful way for + * splitting up to be processed in parallel. + */ +@Slf4j +public class App { + + /** + * Entry point. + * + *

Implementation provided has a list of numbers that has to be squared and added. The list can + * be chunked in any way and the "activity function" {@link + * SquareNumberRequest#delayedSquaring(Consumer)} i.e. squaring the number ca be done + * concurrently. The "fan in" part is handled by the {@link Consumer} that takes in the result + * from each instance of activity and aggregates it whenever that particular activity function + * gets over. + */ + public static void main(String[] args) { + final List numbers = Arrays.asList(1L, 3L, 4L, 7L, 8L); + + LOGGER.info("Numbers to be squared and get sum --> {}", numbers); + + final List requests = + numbers.stream().map(SquareNumberRequest::new).collect(Collectors.toList()); + + var consumer = new Consumer(0L); + + // Pass the request and the consumer to fanOutFanIn or sometimes referred as Orchestrator + // function + final Long sumOfSquaredNumbers = FanOutFanIn.fanOutFanIn(requests, consumer); + + LOGGER.info("Sum of all squared numbers --> {}", sumOfSquaredNumbers); + } +} diff --git a/fanout-fanin/src/main/java/com/iluwatar/fanout/fanin/Consumer.java b/fanout-fanin/src/main/java/com/iluwatar/fanout/fanin/Consumer.java new file mode 100644 index 000000000..79e3445dc --- /dev/null +++ b/fanout-fanin/src/main/java/com/iluwatar/fanout/fanin/Consumer.java @@ -0,0 +1,48 @@ +/* + * The MIT License + * Copyright © 2014-2021 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.fanout.fanin; + +import java.util.concurrent.atomic.AtomicLong; + +import lombok.Getter; + + + +/** + * Consumer or callback class that will be called everytime a request is complete This will + * aggregate individual result to form a final result. + */ +@Getter +public class Consumer { + + private final AtomicLong sumOfSquaredNumbers; + + Consumer(Long init) { + sumOfSquaredNumbers = new AtomicLong(init); + } + + public Long add(final Long num) { + return sumOfSquaredNumbers.addAndGet(num); + } +} diff --git a/fanout-fanin/src/main/java/com/iluwatar/fanout/fanin/FanOutFanIn.java b/fanout-fanin/src/main/java/com/iluwatar/fanout/fanin/FanOutFanIn.java new file mode 100644 index 000000000..71af5ae9f --- /dev/null +++ b/fanout-fanin/src/main/java/com/iluwatar/fanout/fanin/FanOutFanIn.java @@ -0,0 +1,62 @@ +/* + * The MIT License + * Copyright © 2014-2021 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.fanout.fanin; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; + +/** + * FanOutFanIn class processes long running requests, when any of the processes gets over, result is + * passed over to the consumer or the callback function. Consumer will aggregate the results as they + * keep on completing. + */ +public class FanOutFanIn { + + /** + * the main fanOutFanIn function or orchestrator function. + * @param requests List of numbers that need to be squared and summed up + * @param consumer Takes in the squared number from {@link SquareNumberRequest} and sums it up + * @return Aggregated sum of all squared numbers. + */ + public static Long fanOutFanIn( + final List requests, final Consumer consumer) { + + ExecutorService service = Executors.newFixedThreadPool(requests.size()); + + // fanning out + List> futures = + requests.stream() + .map( + request -> + CompletableFuture.runAsync(() -> request.delayedSquaring(consumer), service)) + .collect(Collectors.toList()); + + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); + + return consumer.getSumOfSquaredNumbers().get(); + } +} diff --git a/fanout-fanin/src/main/java/com/iluwatar/fanout/fanin/SquareNumberRequest.java b/fanout-fanin/src/main/java/com/iluwatar/fanout/fanin/SquareNumberRequest.java new file mode 100644 index 000000000..73db6ca87 --- /dev/null +++ b/fanout-fanin/src/main/java/com/iluwatar/fanout/fanin/SquareNumberRequest.java @@ -0,0 +1,63 @@ +/* + * The MIT License + * Copyright © 2014-2021 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.fanout.fanin; + +import java.security.SecureRandom; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * Squares the number with a little timeout to give impression of long running process that return + * at different times. + */ +@Slf4j +@AllArgsConstructor +public class SquareNumberRequest { + + private final Long number; + + /** + * Squares the number with a little timeout to give impression of long running process that return + * at different times. + * @param consumer callback class that takes the result after the delay. + * */ + public void delayedSquaring(final Consumer consumer) { + + var minTimeOut = 5000L; + + SecureRandom secureRandom = new SecureRandom(); + var randomTimeOut = secureRandom.nextInt(2000); + + try { + // this will make the thread sleep from 5-7s. + Thread.sleep(minTimeOut + randomTimeOut); + } catch (InterruptedException e) { + LOGGER.error("Exception while sleep ", e); + Thread.currentThread().interrupt(); + } finally { + consumer.add(number * number); + } + } +} diff --git a/fanout-fanin/src/test/java/com/iluwatar/fanout/fanin/AppTest.java b/fanout-fanin/src/test/java/com/iluwatar/fanout/fanin/AppTest.java new file mode 100644 index 000000000..d221066e2 --- /dev/null +++ b/fanout-fanin/src/test/java/com/iluwatar/fanout/fanin/AppTest.java @@ -0,0 +1,36 @@ +/* + * The MIT License + * Copyright © 2014-2021 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.fanout.fanin; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +class AppTest { + + @Test + void shouldLaunchApp() { + assertDoesNotThrow(() -> App.main(new String[]{})); + } +} diff --git a/fanout-fanin/src/test/java/com/iluwatar/fanout/fanin/FanOutFanInTest.java b/fanout-fanin/src/test/java/com/iluwatar/fanout/fanin/FanOutFanInTest.java new file mode 100644 index 000000000..4273d756a --- /dev/null +++ b/fanout-fanin/src/test/java/com/iluwatar/fanout/fanin/FanOutFanInTest.java @@ -0,0 +1,47 @@ +/* + * The MIT License + * Copyright © 2014-2021 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.fanout.fanin; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +class FanOutFanInTest { + + @Test + void fanOutFanInTest() { + final List numbers = Arrays.asList(1L, 3L, 4L, 7L, 8L); + + final List requests = + numbers.stream().map(SquareNumberRequest::new).collect(Collectors.toList()); + + final Consumer consumer = new Consumer(0L); + + final Long sumOfSquaredNumbers = FanOutFanIn.fanOutFanIn(requests, consumer); + + Assertions.assertEquals(139, sumOfSquaredNumbers); + } +} diff --git a/fanout-fanin/src/test/java/com/iluwatar/fanout/fanin/SquareNumberRequestTest.java b/fanout-fanin/src/test/java/com/iluwatar/fanout/fanin/SquareNumberRequestTest.java new file mode 100644 index 000000000..86560b38b --- /dev/null +++ b/fanout-fanin/src/test/java/com/iluwatar/fanout/fanin/SquareNumberRequestTest.java @@ -0,0 +1,41 @@ +/* + * The MIT License + * Copyright © 2014-2021 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.fanout.fanin; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class SquareNumberRequestTest { + + @Test + void delayedSquaringTest() { + Consumer consumer = new Consumer(10L); + + SquareNumberRequest squareNumberRequest = new SquareNumberRequest(5L); + + squareNumberRequest.delayedSquaring(consumer); + + Assertions.assertEquals(35, consumer.getSumOfSquaredNumbers().get()); + } +} diff --git a/gpl-3.0.txt b/gpl-3.0.txt index e72bfddab..6dc84f60c 100644 --- a/gpl-3.0.txt +++ b/gpl-3.0.txt @@ -1,3 +1,26 @@ +==== + The MIT License + Copyright © 2014-2021 Ilkka Seppälä + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +==== + GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 diff --git a/lgpl-3.0.txt b/lgpl-3.0.txt index 0a041280b..d1fcc084e 100644 --- a/lgpl-3.0.txt +++ b/lgpl-3.0.txt @@ -1,3 +1,26 @@ +==== + The MIT License + Copyright © 2014-2021 Ilkka Seppälä + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +==== + GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 diff --git a/pom.xml b/pom.xml index 1ebe0ad23..cfd0de127 100644 --- a/pom.xml +++ b/pom.xml @@ -232,6 +232,7 @@ table-module presentation lockable-object + fanout-fanin domain-model