diff --git a/filterer/README.MD b/filterer/README.MD index 8a2526048..3281e9ecc 100644 --- a/filterer/README.MD +++ b/filterer/README.MD @@ -1,6 +1,6 @@ --- # this is so called 'Yaml Front Matter', read up on it here: http://jekyllrb.com/docs/frontmatter/ layout: pattern -title: Filterer Pattern +title: Filterer folder: filterer permalink: /patterns/filterer/ description: Design pattern that helps container-like objects to return filtered version of themselves.# short meta description that shows in Google search results @@ -11,15 +11,173 @@ tags: --- ## Name / classification -Filterer Pattern +Filterer ## Intent The intent of this design pattern is to to introduce a functional interface that will add a functionality for container-like objects to easily return filtered versions of themselves. ## Explanation -The container-like object needs to have a method that returns an instance of `Filterer`. This helper interface gives +Real world example + +> We are designing a threat(malware) detection system. We can have different types of threats and systems. We have a requirement that +> system should be aware of threats that are present in it. In the design we have to take into consideration that new Threat types can be +> added later. Also there is a requirement that a system can filter itself based on the threats that it possesses (system acts as container-like object for threats). +> + +In plain words + +> We need to be able to filter different types of systems(container-like objects) based on properties of Threats that they contain. +> Adding new properties for Threats should be easy (we still need the ability to filter by those new properties). + +**Programmatic Example** + +To model the threat detection example presented above we introduce `Threat` and `ThreatAwareSystem` interfaces. + +```java +public interface Threat { + String name(); + int id(); + ThreatType type(); +} + +public interface ThreatAwareSystem { + String systemId(); + List threats(); + Filterer filtered(); + +} +``` +Notice the `filtered` method that returns instance of `Filterer` interface which is defined as : +```java +@FunctionalInterface +public interface Filterer { + G by(Predicate predicate); +} +``` +it is used to fulfill the requirement for system to be able to filter itself based on threat properties. +The container-like object (`ThreatAwareSystem` in our case) needs to have a method that returns an instance of `Filterer`. This helper interface gives ability to covariantly specify a lower bound of contravariant `Predicate` in the subinterfaces of interfaces representing the container-like objects. +In our example we will be able to pass a predicate that takes `? extends Threat` object and return `? extends ThreatAwareSystem` +from `Filtered::by` method. A simple implementation of `ThreadAwareSystem` : +```java +public class SimpleThreatAwareSystem implements ThreatAwareSystem { + + private final String systemId; + private final ImmutableList issues; + + public SimpleThreatAwareSystem(final String systemId, final List issues) { + this.systemId = systemId; + this.issues = ImmutableList.copyOf(issues); + } + + @Override + public String systemId() { + return systemId; + } + + @Override + public List threats() { + return new ArrayList<>(issues); + } + + @Override + public Filterer filtered() { + return this::filteredGroup; + } + + private ThreatAwareSystem filteredGroup(Predicate predicate) { + return new SimpleThreatAwareSystem(this.systemId, filteredItems(predicate)); + } + + private List filteredItems(Predicate predicate) { + return this.issues.stream() + .filter(predicate) + .collect(Collectors.toList()); + } +} +``` +the `filtered` method is overridden to filter the threats list by given predicate. + +Now if we introduce new subtype of `Thread` interface that adds probability with which given thread can appear : +```java +public interface ProbableThreat extends Threat { + double probability(); +} +``` +we can also introduce a new interface that represents a system that is aware of threats with their probabilities : +````java +public interface ProbabilisticThreatAwareSystem extends ThreatAwareSystem { + @Override + List threats(); + + @Override + Filterer filtered(); +} +```` +Notice how we override the `filtered` method in `ProbabilisticThreatAwareSystem` and specify different return covariant type +by specifing different generic types. Our interfaces are clean and not cluttered by default implementations. We +we will be able to filter `ProbabilisticThreatAwareSystem` by `ProbableThreat` properties : +```java +public class SimpleProbabilisticThreatAwareSystem implements ProbabilisticThreatAwareSystem { + + private final String systemId; + private final ImmutableList threats; + + public SimpleProbabilisticThreatAwareSystem(final String systemId, final List threats) { + this.systemId = systemId; + this.threats = ImmutableList.copyOf(threats); + } + + @Override + public String systemId() { + return systemId; + } + + @Override + public List threats() { + return threats; + } + + @Override + public Filterer filtered() { + return this::filteredGroup; + } + + private ProbabilisticThreatAwareSystem filteredGroup(final Predicate predicate) { + return new SimpleProbabilisticThreatAwareSystem(this.systemId, filteredItems(predicate)); + } + + private List filteredItems(final Predicate predicate) { + return this.threats.stream() + .filter(predicate) + .collect(Collectors.toList()); + } +} +``` + +Now if we want filter `ThreatAwareSystem` by threat type we can do : +```java +Threat rootkit = new SimpleThreat(ThreatType.ROOTKIT, 1, "Simple-Rootkit"); +Threat trojan = new SimpleThreat(ThreatType.TROJAN, 2, "Simple-Trojan"); +List threats = List.of(rootkit, trojan); + +ThreatAwareSystem threatAwareSystem = new SimpleThreatAwareSystem("System-1", threats); + +ThreatAwareSystem rootkitThreatAwareSystem = threatAwareSystem.filtered() + .by(threat -> threat.type() == ThreatType.ROOTKIT); +``` +or if we want to filter `ProbabilisticThreatAwareSystem` : +```java +ProbableThreat malwareTroyan = new SimpleProbableThreat("Troyan-ArcBomb", 1, ThreatType.TROJAN, 0.99); +ProbableThreat rootkit = new SimpleProbableThreat("Rootkit-System", 2, ThreatType.ROOTKIT, 0.8); +List probableThreats = List.of(malwareTroyan, rootkit); + +ProbabilisticThreatAwareSystem simpleProbabilisticThreatAwareSystem =new SimpleProbabilisticThreatAwareSystem("System-1", probableThreats); + +ProbabilisticThreatAwareSystem filtered = simpleProbabilisticThreatAwareSystem.filtered() + .by(probableThreat -> Double.compare(probableThreat.probability(), 0.99) == 0); +``` ## Class diagram ![Filterer](./etc/filterer.png "Filterer") @@ -34,11 +192,11 @@ It enables you to easily extend filtering ability of container-like objects as b ## Known uses One of the uses is present on the blog presented in this link. It presents how to use `Filterer` pattern to create text issue anaylyzer with support for test cases used for unit testing. -## Consequences (the good and the bad, add criticism here) -Good : +## Consequences +Pros : * you can easily introduce new subtypes for container-like objects and subtypes for objects that are contained within them and still be able to filter easily be new properties of those new subtypes. -Bad : +Cons : * covariant return types mixed with generics can be sometimes tricky ## Credits diff --git a/filterer/etc/filterer.png b/filterer/etc/filterer.png index f86764aa3..6a6eb059b 100644 Binary files a/filterer/etc/filterer.png and b/filterer/etc/filterer.png differ diff --git a/filterer/etc/filterer.urm.puml b/filterer/etc/filterer.urm.puml index 24060b6aa..c0bb0b54d 100644 --- a/filterer/etc/filterer.urm.puml +++ b/filterer/etc/filterer.urm.puml @@ -4,129 +4,93 @@ package com.iluwatar.filterer.domain { + by(Predicate) : G {abstract} } } -package com.iluwatar.filterer.issue { - interface Issue { - + endOffset() : int {abstract} - + startOffset() : int {abstract} - + type() : IssueType {abstract} +package com.iluwatar.filterer { + class App { + - LOGGER : Logger {static} + + App() + - filteringSimpleProbableThreats() {static} + - filteringSimpleThreats() {static} + + main(args : String[]) {static} } - interface IssueAwareText { - + filtered() : Filterer {abstract} - + issues() : List {abstract} - + text() : String {abstract} +} +package com.iluwatar.filterer.threat { + interface ProbabilisticThreatAwareSystem { + + filtered() : Filterer {abstract} + + threats() : List {abstract} } - class IssuePosition { - - endOffset : int - - startOffset : int - - IssuePosition(startOffset : int, endOffset : int) - ~ endOffset() : int - + equals(o : Object) : boolean - + hashCode() : int - + of(startOffset : int, endOffset : int) : IssuePosition {static} - ~ startOffset() : int - } - ~enum IssueType { - + GRAMMAR {static} - + SPELLING {static} - + valueOf(name : String) : IssueType {static} - + values() : IssueType[] {static} - } - interface IssueWiseText { - + filtered() : Filterer {abstract} - + issues() : List {abstract} - + text() : String {abstract} - } - interface ProbabilisticIssueAwareText { - + filtered() : Filterer {abstract} - + issues() : List {abstract} - } - interface ProbabilisticIssueWiseText { - + filtered() : Filterer {abstract} - + issues() : List {abstract} - } - interface ProbableIssue { + interface ProbableThreat { + probability() : double {abstract} } - class SimpleIssue { - - issuePosition : IssuePosition - - issueType : IssueType - ~ SimpleIssue(issuePosition : IssuePosition, issueType : IssueType) - + endOffset() : int + class SimpleProbabilisticThreatAwareSystem { + - systemId : String + - threats : ImmutableList + + SimpleProbabilisticThreatAwareSystem(systemId : String, threats : List) + equals(o : Object) : boolean + + filtered() : Filterer + - filteredGroup(predicate : Predicate) : ProbabilisticThreatAwareSystem + - filteredItems(predicate : Predicate) : List + hashCode() : int - + startOffset() : int - + type() : IssueType + + systemId() : String + + threats() : List + + toString() : String } - class SimpleIssueAwareText { - - issues : ImmutableList - - text : String - ~ SimpleIssueAwareText(text : String, issues : List) - + equals(o : Object) : boolean - + filtered() : Filterer - - filteredGroup(predicate : Predicate) : IssueAwareText - - filteredItems(predicate : Predicate) : ImmutableList - + hashCode() : int - + issues() : List - + text() : String - } - class SimpleIssueWiseText { - - issues : ImmutableList - - text : String - + SimpleIssueWiseText(text : String, issues : List) - + equals(o : Object) : boolean - + filtered() : Filterer - - filteredGroup(predicate : Predicate) : IssueWiseText - - filteredItems(predicate : Predicate) : ImmutableList - + hashCode() : int - + issues() : List - + text() : String - } - class SimpleProbabilisticIssueAwareText { - - issues : ImmutableList - - text : String - ~ SimpleProbabilisticIssueAwareText(text : String, issues : List) - + equals(o : Object) : boolean - + filtered() : Filterer - - filteredGroup(predicate : Predicate) : ProbabilisticIssueAwareText - - filteredItems(predicate : Predicate) : ImmutableList - + hashCode() : int - + issues() : List - + text() : String - } - class SimpleProbabilisticIssueWiseText { - - issues : ImmutableList - - text : String - + SimpleProbabilisticIssueWiseText(text : String, issues : List) - + equals(o : Object) : boolean - + filtered() : Filterer - - filteredGroup(predicate : Predicate) : ProbabilisticIssueWiseText - - filteredItems(predicate : Predicate) : ImmutableList - + hashCode() : int - + issues() : List - + text() : String - } - class SimpleProbableIssue { + class SimpleProbableThreat { - probability : double - ~ SimpleProbableIssue(issuePosition : IssuePosition, issueType : IssueType, probability : double) + + SimpleProbableThreat(name : String, id : int, threatType : ThreatType, probability : double) + equals(o : Object) : boolean + hashCode() : int + probability() : double + + toString() : String + } + class SimpleThreat { + - id : int + - name : String + - threatType : ThreatType + + SimpleThreat(threatType : ThreatType, id : int, name : String) + + id() : int + + name() : String + + toString() : String + + type() : ThreatType + } + class SimpleThreatAwareSystem { + - issues : ImmutableList + - systemId : String + + SimpleThreatAwareSystem(systemId : String, issues : List) + + equals(o : Object) : boolean + + filtered() : Filterer + - filteredGroup(predicate : Predicate) : ThreatAwareSystem + - filteredItems(predicate : Predicate) : List + + hashCode() : int + + systemId() : String + + threats() : List + + toString() : String + } + interface Threat { + + id() : int {abstract} + + name() : String {abstract} + + type() : ThreatType {abstract} + } + interface ThreatAwareSystem { + + filtered() : Filterer {abstract} + + systemId() : String {abstract} + + threats() : List {abstract} + } + enum ThreatType { + + ROOTKIT {static} + + TROJAN {static} + + WORM {static} + + valueOf(name : String) : ThreatType {static} + + values() : ThreatType[] {static} } } -SimpleIssueWiseText --> "-issues" Issue -SimpleProbabilisticIssueAwareText --> "-issues" ProbableIssue -SimpleIssue --> "-issueType" IssueType -SimpleIssueAwareText --> "-issues" Issue -SimpleProbabilisticIssueWiseText --> "-issues" ProbableIssue -SimpleIssue --> "-issuePosition" IssuePosition -ProbabilisticIssueAwareText --|> IssueAwareText -ProbabilisticIssueWiseText --|> IssueWiseText -ProbableIssue --|> Issue -SimpleIssue ..|> Issue -SimpleIssueAwareText ..|> IssueAwareText -SimpleIssueWiseText ..|> IssueWiseText -SimpleProbabilisticIssueAwareText ..|> ProbabilisticIssueAwareText -SimpleProbabilisticIssueWiseText ..|> ProbabilisticIssueWiseText -SimpleProbableIssue ..|> ProbableIssue -SimpleProbableIssue --|> SimpleIssue +SimpleThreatAwareSystem --> "-issues" Threat +SimpleThreat --> "-threatType" ThreatType +SimpleProbabilisticThreatAwareSystem --> "-threats" ProbableThreat +ProbabilisticThreatAwareSystem --|> ThreatAwareSystem +ProbableThreat --|> Threat +SimpleProbabilisticThreatAwareSystem ..|> ProbabilisticThreatAwareSystem +SimpleProbableThreat ..|> ProbableThreat +SimpleProbableThreat --|> SimpleThreat +SimpleThreat ..|> Threat +SimpleThreatAwareSystem ..|> ThreatAwareSystem @enduml \ No newline at end of file diff --git a/filterer/pom.xml b/filterer/pom.xml index 24dae571e..4477332ae 100644 --- a/filterer/pom.xml +++ b/filterer/pom.xml @@ -39,37 +39,34 @@ com.google.guava guava - 29.0-jre org.junit.jupiter junit-jupiter-api - 5.6.2 test org.junit.jupiter junit-jupiter-engine - 5.6.2 - test - - - org.assertj - assertj-core - 3.16.1 test - - maven-surefire-plugin - 2.22.2 - - - maven-failsafe-plugin - 2.22.2 + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.filterer.App + + + + + diff --git a/filterer/src/main/java/com/iluwatar/filterer/App.java b/filterer/src/main/java/com/iluwatar/filterer/App.java new file mode 100644 index 000000000..97ed24837 --- /dev/null +++ b/filterer/src/main/java/com/iluwatar/filterer/App.java @@ -0,0 +1,111 @@ +/* + * The MIT License + * Copyright © 2014-2019 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.filterer; + +import com.iluwatar.filterer.threat.ProbabilisticThreatAwareSystem; +import com.iluwatar.filterer.threat.ProbableThreat; +import com.iluwatar.filterer.threat.SimpleProbabilisticThreatAwareSystem; +import com.iluwatar.filterer.threat.SimpleProbableThreat; +import com.iluwatar.filterer.threat.SimpleThreat; +import com.iluwatar.filterer.threat.SimpleThreatAwareSystem; +import com.iluwatar.filterer.threat.Threat; +import com.iluwatar.filterer.threat.ThreatAwareSystem; +import com.iluwatar.filterer.threat.ThreatType; + +import java.util.List; +import java.util.function.Predicate; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This demo class represent how {@link com.iluwatar.filterer.domain.Filterer} pattern is used to + * filter container-like objects to return filtered versions of themselves. The container like + * objects are systems that are aware of threats that they can be vulnerable to. We would like + * to have a way to create copy of different system objects but with filtered threats. + * The thing is to keep it simple if we add new subtype of {@link Threat} + * (for example {@link ProbableThreat}) - we still need to be able to filter by it's properties. + */ +public class App { + + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + + public static void main(String[] args) { + filteringSimpleThreats(); + filteringSimpleProbableThreats(); + } + + /** + * Demonstrates how to filter {@link com.iluwatar.filterer.threat.ProbabilisticThreatAwareSystem} + * based on probability property. The @{@link com.iluwatar.filterer.domain.Filterer#by(Predicate)} + * method is able to use {@link com.iluwatar.filterer.threat.ProbableThreat} + * as predicate argument. + */ + private static void filteringSimpleProbableThreats() { + LOGGER.info(" ### Filtering ProbabilisticThreatAwareSystem by probability ###"); + + ProbableThreat trojanArcBomb = + new SimpleProbableThreat("Trojan-ArcBomb", 1, ThreatType.TROJAN, 0.99); + ProbableThreat rootkit = + new SimpleProbableThreat("Rootkit-Kernel", 2, ThreatType.ROOTKIT, 0.8); + + List probableThreats = List.of(trojanArcBomb, rootkit); + + ProbabilisticThreatAwareSystem probabilisticThreatAwareSystem = + new SimpleProbabilisticThreatAwareSystem("System-1", probableThreats); + + LOGGER.info("Filtering ProbabilisticThreatAwareSystem. Initial : " + + probabilisticThreatAwareSystem); + + //Filtering using filterer + ProbabilisticThreatAwareSystem filtered = probabilisticThreatAwareSystem.filtered() + .by(probableThreat -> Double.compare(probableThreat.probability(), 0.99) == 0); + + LOGGER.info("Filtered by probability = 0.99 : " + filtered); + } + + /** + * Demonstrates how to filter {@link ThreatAwareSystem} based on startingOffset property + * of {@link SimpleThreat}. The @{@link com.iluwatar.filterer.domain.Filterer#by(Predicate)} + * method is able to use {@link Threat} as predicate argument. + */ + private static void filteringSimpleThreats() { + LOGGER.info("### Filtering ThreatAwareSystem by ThreatType ###"); + + Threat rootkit = new SimpleThreat(ThreatType.ROOTKIT, 1, "Simple-Rootkit"); + Threat trojan = new SimpleThreat(ThreatType.TROJAN, 2, "Simple-Trojan"); + List threats = List.of(rootkit, trojan); + + ThreatAwareSystem threatAwareSystem = new SimpleThreatAwareSystem("System-1", threats); + + LOGGER.info("Filtering ThreatAwareSystem. Initial : " + threatAwareSystem); + + //Filtering using Filterer + ThreatAwareSystem rootkitThreatAwareSystem = threatAwareSystem.filtered() + .by(threat -> threat.type() == ThreatType.ROOTKIT); + + LOGGER.info("Filtered by threatType = ROOTKIT : " + rootkitThreatAwareSystem); + } + +} diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/IssuePosition.java b/filterer/src/main/java/com/iluwatar/filterer/issue/IssuePosition.java deleted file mode 100644 index a771c1a82..000000000 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/IssuePosition.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * The MIT License - * Copyright © 2014-2019 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.filterer.issue; - -import java.util.Objects; - -/** - * Represents position of an issue. Takes starting and ending offset of issue in given text. - */ -public final class IssuePosition { - - private final int startOffset; - private final int endOffset; - - /** - * Factory method for constructing `IssuePosition` instances. - * @param startOffset starting offset of where the issue begins. - * @param endOffset ending offset of where the issue ends. - * @return new IssuePosition instance. - */ - public static IssuePosition of(final int startOffset, final int endOffset) { - return new IssuePosition(startOffset, endOffset); - } - - private IssuePosition(int startOffset, int endOffset) { - this.startOffset = startOffset; - this.endOffset = endOffset; - } - - int startOffset() { - return startOffset; - } - - int endOffset() { - return endOffset; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - IssuePosition that = (IssuePosition) o; - return startOffset == that.startOffset - && endOffset == that.endOffset; - } - - @Override - public int hashCode() { - return Objects.hash(startOffset, endOffset); - } -} diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/ProbabilisticIssueAwareText.java b/filterer/src/main/java/com/iluwatar/filterer/threat/ProbabilisticThreatAwareSystem.java similarity index 79% rename from filterer/src/main/java/com/iluwatar/filterer/issue/ProbabilisticIssueAwareText.java rename to filterer/src/main/java/com/iluwatar/filterer/threat/ProbabilisticThreatAwareSystem.java index da15bdd99..3a2959828 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/ProbabilisticIssueAwareText.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/ProbabilisticThreatAwareSystem.java @@ -21,29 +21,29 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; import com.iluwatar.filterer.domain.Filterer; import java.util.List; /** - * Represents text that is aware of it's issues with given probability of their occurrence. + * Represents system that is aware of it's threats with given probability of their occurrence. */ -public interface ProbabilisticIssueAwareText extends IssueAwareText { +public interface ProbabilisticThreatAwareSystem extends ThreatAwareSystem { /** * {@inheritDoc} * @return */ @Override - List issues(); + List threats(); /** * {@inheritDoc} * @return */ @Override - Filterer filtered(); + Filterer filtered(); } diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/ProbableIssue.java b/filterer/src/main/java/com/iluwatar/filterer/threat/ProbableThreat.java similarity index 81% rename from filterer/src/main/java/com/iluwatar/filterer/issue/ProbableIssue.java rename to filterer/src/main/java/com/iluwatar/filterer/threat/ProbableThreat.java index ccb047fa4..11e61dbf6 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/ProbableIssue.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/ProbableThreat.java @@ -21,15 +21,15 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; /** - * Represents issue that is an issue with given probability. + * Represents threat that might be a threat with given probability. */ -public interface ProbableIssue extends Issue { +public interface ProbableThreat extends Threat { /** - * Returns probability of occurrence of given issue. - * @return probability of occurrence of given issue. + * Returns probability of occurrence of given threat. + * @return probability of occurrence of given threat. */ double probability(); } \ No newline at end of file diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareText.java b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystem.java similarity index 54% rename from filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareText.java rename to filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystem.java index e1b4afc82..37fae6a74 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareText.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystem.java @@ -21,7 +21,7 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; import com.google.common.collect.ImmutableList; import com.iluwatar.filterer.domain.Filterer; @@ -29,56 +29,60 @@ import com.iluwatar.filterer.domain.Filterer; import java.util.List; import java.util.Objects; import java.util.function.Predicate; +import java.util.stream.Collectors; /** * {@inheritDoc} */ -public class SimpleProbabilisticIssueAwareText implements ProbabilisticIssueAwareText { +public class SimpleProbabilisticThreatAwareSystem implements ProbabilisticThreatAwareSystem { - private final String text; - private final ImmutableList issues; + private final String systemId; + private final ImmutableList threats; - SimpleProbabilisticIssueAwareText(final String text, final List issues) { - this.text = text; - this.issues = ImmutableList.copyOf(issues); + public SimpleProbabilisticThreatAwareSystem( + final String systemId, + final List threats + ) { + this.systemId = systemId; + this.threats = ImmutableList.copyOf(threats); } /** * {@inheritDoc} */ @Override - public String text() { - return text; + public String systemId() { + return systemId; } /** * {@inheritDoc} */ @Override - public List issues() { - return issues; + public List threats() { + return threats; } /** * {@inheritDoc} */ @Override - public Filterer filtered() { + public Filterer filtered() { return this::filteredGroup; } - private ProbabilisticIssueAwareText filteredGroup( - final Predicate predicate + private ProbabilisticThreatAwareSystem filteredGroup( + final Predicate predicate ) { - return new SimpleProbabilisticIssueAwareText(this.text, filteredItems(predicate)); + return new SimpleProbabilisticThreatAwareSystem(this.systemId, filteredItems(predicate)); } - private ImmutableList filteredItems( - final Predicate predicate + private List filteredItems( + final Predicate predicate ) { - return this.issues.stream() + return this.threats.stream() .filter(predicate) - .collect(ImmutableList.toImmutableList()); + .collect(Collectors.toList()); } @Override @@ -89,13 +93,21 @@ public class SimpleProbabilisticIssueAwareText implements ProbabilisticIssueAwar if (o == null || getClass() != o.getClass()) { return false; } - SimpleProbabilisticIssueAwareText that = (SimpleProbabilisticIssueAwareText) o; - return text.equals(that.text) - && issues.equals(that.issues); + SimpleProbabilisticThreatAwareSystem that = (SimpleProbabilisticThreatAwareSystem) o; + return systemId.equals(that.systemId) + && threats.equals(that.threats); } @Override public int hashCode() { - return Objects.hash(text, issues); + return Objects.hash(systemId, threats); + } + + @Override + public String toString() { + return "SimpleProbabilisticThreatAwareSystem{" + + "systemId='" + systemId + '\'' + + ", threats=" + threats + + '}'; } } diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbableIssue.java b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbableThreat.java similarity index 74% rename from filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbableIssue.java rename to filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbableThreat.java index 2b7672256..27efc740a 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleProbableIssue.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleProbableThreat.java @@ -21,22 +21,23 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; import java.util.Objects; /** * {@inheritDoc} */ -public class SimpleProbableIssue extends SimpleIssue implements ProbableIssue { +public class SimpleProbableThreat extends SimpleThreat implements ProbableThreat { private final double probability; - SimpleProbableIssue(final IssuePosition issuePosition, - final IssueType issueType, - final double probability + public SimpleProbableThreat(final String name, + final int id, + final ThreatType threatType, + final double probability ) { - super(issuePosition, issueType); + super(threatType, id, name); this.probability = probability; } @@ -59,7 +60,7 @@ public class SimpleProbableIssue extends SimpleIssue implements ProbableIssue { if (!super.equals(o)) { return false; } - SimpleProbableIssue that = (SimpleProbableIssue) o; + SimpleProbableThreat that = (SimpleProbableThreat) o; return Double.compare(that.probability, probability) == 0; } @@ -67,4 +68,12 @@ public class SimpleProbableIssue extends SimpleIssue implements ProbableIssue { public int hashCode() { return Objects.hash(super.hashCode(), probability); } + + @Override + public String toString() { + return "SimpleProbableThreat{" + + "probability=" + probability + + "} " + + super.toString(); + } } diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssue.java b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreat.java similarity index 59% rename from filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssue.java rename to filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreat.java index fde5b8d8e..fe7f155d4 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssue.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreat.java @@ -21,42 +21,54 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; import java.util.Objects; -public class SimpleIssue implements Issue { +/** + * Represents a simple threat. + */ +public class SimpleThreat implements Threat { - private final IssuePosition issuePosition; - private final IssueType issueType; + private final ThreatType threatType; + private final int id; + private final String name; - SimpleIssue(final IssuePosition issuePosition, IssueType issueType) { - this.issuePosition = issuePosition; - this.issueType = issueType; + /** + * Constructor. + * + * @param threatType {@link ThreatType}. + * @param id threat id. + * @param name threat name. + */ + public SimpleThreat(final ThreatType threatType, final int id, String name) { + this.threatType = threatType; + this.id = id; + this.name = name; } /** * {@inheritDoc} */ @Override - public int startOffset() { - return issuePosition.startOffset(); + public String name() { + return name; } /** * {@inheritDoc} */ @Override - public int endOffset() { - return issuePosition.endOffset(); + public int id() { + return id; } /** * {@inheritDoc} */ @Override - public IssueType type() { - return issueType; + public ThreatType type() { + return threatType; } @Override @@ -67,13 +79,23 @@ public class SimpleIssue implements Issue { if (o == null || getClass() != o.getClass()) { return false; } - SimpleIssue that = (SimpleIssue) o; - return issuePosition.equals(that.issuePosition) - && issueType == that.issueType; + SimpleThreat that = (SimpleThreat) o; + return id == that.id + && threatType == that.threatType + && Objects.equals(name, that.name); } @Override public int hashCode() { - return Objects.hash(issuePosition, issueType); + return Objects.hash(threatType, id, name); + } + + @Override + public String toString() { + return "SimpleThreat{" + + "threatType=" + threatType + + ", id=" + id + + ", name='" + name + '\'' + + '}'; } } diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssueAwareText.java b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystem.java similarity index 63% rename from filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssueAwareText.java rename to filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystem.java index c654a3aaa..49707cf50 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/SimpleIssueAwareText.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystem.java @@ -21,7 +21,7 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; import com.google.common.collect.ImmutableList; import com.iluwatar.filterer.domain.Filterer; @@ -30,17 +30,18 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.function.Predicate; +import java.util.stream.Collectors; /** * {@inheritDoc} */ -public class SimpleIssueAwareText implements IssueAwareText { +public class SimpleThreatAwareSystem implements ThreatAwareSystem { - private final String text; - private final ImmutableList issues; + private final String systemId; + private final ImmutableList issues; - SimpleIssueAwareText(final String text, final List issues) { - this.text = text; + public SimpleThreatAwareSystem(final String systemId, final List issues) { + this.systemId = systemId; this.issues = ImmutableList.copyOf(issues); } @@ -48,15 +49,15 @@ public class SimpleIssueAwareText implements IssueAwareText { * {@inheritDoc} */ @Override - public String text() { - return text; + public String systemId() { + return systemId; } /** * {@inheritDoc} */ @Override - public List issues() { + public List threats() { return new ArrayList<>(issues); } @@ -64,18 +65,18 @@ public class SimpleIssueAwareText implements IssueAwareText { * {@inheritDoc} */ @Override - public Filterer filtered() { + public Filterer filtered() { return this::filteredGroup; } - private IssueAwareText filteredGroup(Predicate predicate) { - return new SimpleIssueAwareText(this.text, filteredItems(predicate)); + private ThreatAwareSystem filteredGroup(Predicate predicate) { + return new SimpleThreatAwareSystem(this.systemId, filteredItems(predicate)); } - private ImmutableList filteredItems(Predicate predicate) { + private List filteredItems(Predicate predicate) { return this.issues.stream() .filter(predicate) - .collect(ImmutableList.toImmutableList()); + .collect(Collectors.toList()); } @Override @@ -86,13 +87,21 @@ public class SimpleIssueAwareText implements IssueAwareText { if (o == null || getClass() != o.getClass()) { return false; } - SimpleIssueAwareText that = (SimpleIssueAwareText) o; - return text.equals(that.text) + SimpleThreatAwareSystem that = (SimpleThreatAwareSystem) o; + return systemId.equals(that.systemId) && issues.equals(that.issues); } @Override public int hashCode() { - return Objects.hash(text, issues); + return Objects.hash(systemId, issues); + } + + @Override + public String toString() { + return "SimpleThreatAwareSystem{" + + "systemId='" + systemId + + '\'' + ", issues=" + issues + + '}'; } } diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/Issue.java b/filterer/src/main/java/com/iluwatar/filterer/threat/Threat.java similarity index 71% rename from filterer/src/main/java/com/iluwatar/filterer/issue/Issue.java rename to filterer/src/main/java/com/iluwatar/filterer/threat/Threat.java index 957ade6e5..515b59332 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/Issue.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/Threat.java @@ -21,29 +21,29 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; /** - * Represents an issue that can be detected in given text. + * Represents a threat that can be detected in given system. */ -public interface Issue { +public interface Threat { /** - * Returns starting position where the issue begins. + * Returns name of the threat. * - * @return value representing starting position of the issue. + * @return value representing name of the threat. */ - int startOffset(); + String name(); /** - * Returns ending position where the issue ends. + * Returns unique id of the threat. * - * @return value representing ending position of the issue. + * @return value representing threat id. */ - int endOffset(); + int id(); /** - * Returns issue type. - * @return {@link IssueType} + * Returns threat type. + * @return {@link ThreatType} */ - IssueType type(); + ThreatType type(); } diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/IssueAwareText.java b/filterer/src/main/java/com/iluwatar/filterer/threat/ThreatAwareSystem.java similarity index 78% rename from filterer/src/main/java/com/iluwatar/filterer/issue/IssueAwareText.java rename to filterer/src/main/java/com/iluwatar/filterer/threat/ThreatAwareSystem.java index 8141ae849..b889d537d 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/IssueAwareText.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/ThreatAwareSystem.java @@ -21,35 +21,35 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; import com.iluwatar.filterer.domain.Filterer; import java.util.List; /** - * Represents text that is aware of issues that are present in it. + * Represents system that is aware of threats that are present in it. */ -public interface IssueAwareText { +public interface ThreatAwareSystem { /** - * Returns the analyzed text. + * Returns the system id. * - * @return the analyzed text. + * @return system id. */ - String text(); + String systemId(); /** - * Returns list of issues for this text. - * @return list of issues for this text. + * Returns list of threats for this system. + * @return list of threats for this system. */ - List issues(); + List threats(); /** * Returns the instance of {@link Filterer} helper interface that allows to covariantly * specify lower bound for predicate that we want to filter by. * @return an instance of {@link Filterer} helper interface. */ - Filterer filtered(); + Filterer filtered(); } diff --git a/filterer/src/main/java/com/iluwatar/filterer/issue/IssueType.java b/filterer/src/main/java/com/iluwatar/filterer/threat/ThreatType.java similarity index 92% rename from filterer/src/main/java/com/iluwatar/filterer/issue/IssueType.java rename to filterer/src/main/java/com/iluwatar/filterer/threat/ThreatType.java index ee2c12ce5..5f9a152a8 100644 --- a/filterer/src/main/java/com/iluwatar/filterer/issue/IssueType.java +++ b/filterer/src/main/java/com/iluwatar/filterer/threat/ThreatType.java @@ -21,6 +21,6 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; -enum IssueType { GRAMMAR, SPELLING } +public enum ThreatType { TROJAN, WORM, ROOTKIT } diff --git a/filterer/src/test/java/com/iluwatar/filterer/AppTest.java b/filterer/src/test/java/com/iluwatar/filterer/AppTest.java new file mode 100644 index 000000000..551ebcc18 --- /dev/null +++ b/filterer/src/test/java/com/iluwatar/filterer/AppTest.java @@ -0,0 +1,33 @@ +/* + * The MIT License + * Copyright © 2014-2019 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.filterer; + +import org.junit.jupiter.api.Test; + +class AppTest { + @Test + void shouldLaunchApp() { + App.main(new String[]{}); + } +} \ No newline at end of file diff --git a/filterer/src/test/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareTextTest.java b/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystemTest.java similarity index 60% rename from filterer/src/test/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareTextTest.java rename to filterer/src/test/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystemTest.java index 142415111..592fabe88 100644 --- a/filterer/src/test/java/com/iluwatar/filterer/issue/SimpleProbabilisticIssueAwareTextTest.java +++ b/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleProbabilisticThreatAwareSystemTest.java @@ -21,32 +21,31 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; import org.junit.jupiter.api.Test; import java.util.List; -import static org.assertj.core.api.Assertions.assertThat; - -class SimpleProbabilisticIssueAwareTextTest { +import static org.junit.jupiter.api.Assertions.assertEquals; +class SimpleProbabilisticThreatAwareSystemTest { @Test void shouldFilterByProbability() { //given - ProbableIssue spellingIssue = new SimpleProbableIssue(IssuePosition.of(4, 5), IssueType.SPELLING, 100); - ProbableIssue grammarIssue = new SimpleProbableIssue(IssuePosition.of(8, 12), IssueType.GRAMMAR, 99); - List issues = List.of(spellingIssue, grammarIssue); + ProbableThreat trojan = new SimpleProbableThreat("Troyan-ArcBomb", 1, ThreatType.TROJAN, 0.99); + ProbableThreat rootkit = new SimpleProbableThreat("Rootkit-System", 2, ThreatType.ROOTKIT, 0.8); + List probableThreats = List.of(trojan, rootkit); - SimpleProbabilisticIssueAwareText simpleIssueWiseText = new SimpleProbabilisticIssueAwareText("I mihgt gone there", issues); + ProbabilisticThreatAwareSystem simpleProbabilisticThreatAwareSystem = + new SimpleProbabilisticThreatAwareSystem("System-1", probableThreats); //when - ProbabilisticIssueAwareText filtered = simpleIssueWiseText.filtered() - .by(issue1 -> Double.compare(issue1.probability(), 99) == 0); + ProbabilisticThreatAwareSystem filtered = simpleProbabilisticThreatAwareSystem.filtered() + .by(probableThreat -> Double.compare(probableThreat.probability(), 0.99) == 0); //then - assertThat(filtered.issues()).hasSize(1); - assertThat(filtered.issues()).element(0).isEqualTo(grammarIssue); + assertEquals(filtered.threats().size(), 1); + assertEquals(filtered.threats().get(0), trojan); } - } \ No newline at end of file diff --git a/filterer/src/test/java/com/iluwatar/filterer/issue/SimpleIssueAwareTextTest.java b/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystemTest.java similarity index 62% rename from filterer/src/test/java/com/iluwatar/filterer/issue/SimpleIssueAwareTextTest.java rename to filterer/src/test/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystemTest.java index 1278128ae..91fb62718 100644 --- a/filterer/src/test/java/com/iluwatar/filterer/issue/SimpleIssueAwareTextTest.java +++ b/filterer/src/test/java/com/iluwatar/filterer/threat/SimpleThreatAwareSystemTest.java @@ -21,32 +21,30 @@ * THE SOFTWARE. */ -package com.iluwatar.filterer.issue; +package com.iluwatar.filterer.threat; import org.junit.jupiter.api.Test; import java.util.List; -import static org.assertj.core.api.Assertions.assertThat; - -class SimpleIssueAwareTextTest { +import static org.junit.jupiter.api.Assertions.*; +class SimpleThreatAwareSystemTest { @Test - void shouldFilterByStartOffset() { + void shouldFilterByThreatType() { //given - SimpleIssue spellingIssue = new SimpleIssue(IssuePosition.of(4, 5), IssueType.SPELLING); - SimpleIssue grammarIssue = new SimpleIssue(IssuePosition.of(8, 12), IssueType.GRAMMAR); - List issues = List.of(spellingIssue, grammarIssue); + Threat rootkit = new SimpleThreat(ThreatType.ROOTKIT, 1, "Simple-Rootkit"); + Threat trojan = new SimpleThreat(ThreatType.TROJAN, 2, "Simple-Trojan"); + List threats = List.of(rootkit, trojan); - SimpleIssueAwareText simpleIssueWiseText = new SimpleIssueAwareText("I mihgt gone there", issues); + ThreatAwareSystem threatAwareSystem = new SimpleThreatAwareSystem("System-1", threats); //when - IssueAwareText filtered = simpleIssueWiseText.filtered() - .by(issue1 -> issue1.startOffset() == 4); + ThreatAwareSystem rootkitThreatAwareSystem = threatAwareSystem.filtered() + .by(threat -> threat.type() == ThreatType.ROOTKIT); //then - assertThat(filtered.issues()).hasSize(1); - assertThat(filtered.issues()).element(0).isEqualTo(spellingIssue); + assertEquals(rootkitThreatAwareSystem.threats().size(), 1); + assertEquals(rootkitThreatAwareSystem.threats().get(0), rootkit); } - -} +} \ No newline at end of file