Added fixes after review. Changed example pattern application to threat detection domain
This commit is contained in:
parent
905b5dc6d8
commit
61a819aab8
@ -1,6 +1,6 @@
|
|||||||
--- # this is so called 'Yaml Front Matter', read up on it here: http://jekyllrb.com/docs/frontmatter/
|
--- # this is so called 'Yaml Front Matter', read up on it here: http://jekyllrb.com/docs/frontmatter/
|
||||||
layout: pattern
|
layout: pattern
|
||||||
title: Filterer Pattern
|
title: Filterer
|
||||||
folder: filterer
|
folder: filterer
|
||||||
permalink: /patterns/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
|
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
|
## Name / classification
|
||||||
Filterer Pattern
|
Filterer
|
||||||
|
|
||||||
## Intent
|
## 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.
|
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
|
## 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<? extends Threat> threats();
|
||||||
|
Filterer<? extends ThreatAwareSystem, ? extends Threat> filtered();
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Notice the `filtered` method that returns instance of `Filterer` interface which is defined as :
|
||||||
|
```java
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Filterer<G, E> {
|
||||||
|
G by(Predicate<? super E> 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.
|
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<Threat> issues;
|
||||||
|
|
||||||
|
public SimpleThreatAwareSystem(final String systemId, final List<Threat> issues) {
|
||||||
|
this.systemId = systemId;
|
||||||
|
this.issues = ImmutableList.copyOf(issues);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String systemId() {
|
||||||
|
return systemId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<? extends Threat> threats() {
|
||||||
|
return new ArrayList<>(issues);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Filterer<? extends ThreatAwareSystem, ? extends Threat> filtered() {
|
||||||
|
return this::filteredGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ThreatAwareSystem filteredGroup(Predicate<? super Threat> predicate) {
|
||||||
|
return new SimpleThreatAwareSystem(this.systemId, filteredItems(predicate));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Threat> filteredItems(Predicate<? super Threat> 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<? extends ProbableThreat> threats();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Filterer<? extends ProbabilisticThreatAwareSystem, ? extends ProbableThreat> 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<ProbableThreat> threats;
|
||||||
|
|
||||||
|
public SimpleProbabilisticThreatAwareSystem(final String systemId, final List<ProbableThreat> threats) {
|
||||||
|
this.systemId = systemId;
|
||||||
|
this.threats = ImmutableList.copyOf(threats);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String systemId() {
|
||||||
|
return systemId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<? extends ProbableThreat> threats() {
|
||||||
|
return threats;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Filterer<? extends ProbabilisticThreatAwareSystem, ? extends ProbableThreat> filtered() {
|
||||||
|
return this::filteredGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProbabilisticThreatAwareSystem filteredGroup(final Predicate<? super ProbableThreat> predicate) {
|
||||||
|
return new SimpleProbabilisticThreatAwareSystem(this.systemId, filteredItems(predicate));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ProbableThreat> filteredItems(final Predicate<? super ProbableThreat> 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<Threat> 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<ProbableThreat> 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
|
## Class diagram
|
||||||

|

|
||||||
|
|
||||||
@ -34,11 +192,11 @@ It enables you to easily extend filtering ability of container-like objects as b
|
|||||||
## Known uses
|
## 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.
|
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)
|
## Consequences
|
||||||
Good :
|
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.
|
* 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
|
* covariant return types mixed with generics can be sometimes tricky
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 128 KiB |
@ -4,129 +4,93 @@ package com.iluwatar.filterer.domain {
|
|||||||
+ by(Predicate<? super E>) : G {abstract}
|
+ by(Predicate<? super E>) : G {abstract}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
package com.iluwatar.filterer.issue {
|
package com.iluwatar.filterer {
|
||||||
interface Issue {
|
class App {
|
||||||
+ endOffset() : int {abstract}
|
- LOGGER : Logger {static}
|
||||||
+ startOffset() : int {abstract}
|
+ App()
|
||||||
+ type() : IssueType {abstract}
|
- filteringSimpleProbableThreats() {static}
|
||||||
|
- filteringSimpleThreats() {static}
|
||||||
|
+ main(args : String[]) {static}
|
||||||
}
|
}
|
||||||
interface IssueAwareText {
|
}
|
||||||
+ filtered() : Filterer<? extends IssueAwareText, ? extends Issue> {abstract}
|
package com.iluwatar.filterer.threat {
|
||||||
+ issues() : List<? extends Issue> {abstract}
|
interface ProbabilisticThreatAwareSystem {
|
||||||
+ text() : String {abstract}
|
+ filtered() : Filterer<? extends ProbabilisticThreatAwareSystem, ? extends ProbableThreat> {abstract}
|
||||||
|
+ threats() : List<? extends ProbableThreat> {abstract}
|
||||||
}
|
}
|
||||||
class IssuePosition {
|
interface ProbableThreat {
|
||||||
- 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<? extends IssueWiseText, ? extends Issue> {abstract}
|
|
||||||
+ issues() : List<? extends Issue> {abstract}
|
|
||||||
+ text() : String {abstract}
|
|
||||||
}
|
|
||||||
interface ProbabilisticIssueAwareText {
|
|
||||||
+ filtered() : Filterer<? extends ProbabilisticIssueAwareText, ? extends ProbableIssue> {abstract}
|
|
||||||
+ issues() : List<? extends ProbableIssue> {abstract}
|
|
||||||
}
|
|
||||||
interface ProbabilisticIssueWiseText {
|
|
||||||
+ filtered() : Filterer<? extends ProbabilisticIssueWiseText, ? extends ProbableIssue> {abstract}
|
|
||||||
+ issues() : List<? extends ProbableIssue> {abstract}
|
|
||||||
}
|
|
||||||
interface ProbableIssue {
|
|
||||||
+ probability() : double {abstract}
|
+ probability() : double {abstract}
|
||||||
}
|
}
|
||||||
class SimpleIssue {
|
class SimpleProbabilisticThreatAwareSystem {
|
||||||
- issuePosition : IssuePosition
|
- systemId : String
|
||||||
- issueType : IssueType
|
- threats : ImmutableList<ProbableThreat>
|
||||||
~ SimpleIssue(issuePosition : IssuePosition, issueType : IssueType)
|
+ SimpleProbabilisticThreatAwareSystem(systemId : String, threats : List<ProbableThreat>)
|
||||||
+ endOffset() : int
|
|
||||||
+ equals(o : Object) : boolean
|
+ equals(o : Object) : boolean
|
||||||
|
+ filtered() : Filterer<? extends ProbabilisticThreatAwareSystem, ? extends ProbableThreat>
|
||||||
|
- filteredGroup(predicate : Predicate<? super ProbableThreat>) : ProbabilisticThreatAwareSystem
|
||||||
|
- filteredItems(predicate : Predicate<? super ProbableThreat>) : List<ProbableThreat>
|
||||||
+ hashCode() : int
|
+ hashCode() : int
|
||||||
+ startOffset() : int
|
+ systemId() : String
|
||||||
+ type() : IssueType
|
+ threats() : List<? extends ProbableThreat>
|
||||||
|
+ toString() : String
|
||||||
}
|
}
|
||||||
class SimpleIssueAwareText {
|
class SimpleProbableThreat {
|
||||||
- issues : ImmutableList<Issue>
|
|
||||||
- text : String
|
|
||||||
~ SimpleIssueAwareText(text : String, issues : List<Issue>)
|
|
||||||
+ equals(o : Object) : boolean
|
|
||||||
+ filtered() : Filterer<? extends IssueAwareText, ? extends Issue>
|
|
||||||
- filteredGroup(predicate : Predicate<? super Issue>) : IssueAwareText
|
|
||||||
- filteredItems(predicate : Predicate<? super Issue>) : ImmutableList<Issue>
|
|
||||||
+ hashCode() : int
|
|
||||||
+ issues() : List<? extends Issue>
|
|
||||||
+ text() : String
|
|
||||||
}
|
|
||||||
class SimpleIssueWiseText {
|
|
||||||
- issues : ImmutableList<Issue>
|
|
||||||
- text : String
|
|
||||||
+ SimpleIssueWiseText(text : String, issues : List<Issue>)
|
|
||||||
+ equals(o : Object) : boolean
|
|
||||||
+ filtered() : Filterer<? extends IssueWiseText, ? extends Issue>
|
|
||||||
- filteredGroup(predicate : Predicate<? super Issue>) : IssueWiseText
|
|
||||||
- filteredItems(predicate : Predicate<? super Issue>) : ImmutableList<Issue>
|
|
||||||
+ hashCode() : int
|
|
||||||
+ issues() : List<? extends Issue>
|
|
||||||
+ text() : String
|
|
||||||
}
|
|
||||||
class SimpleProbabilisticIssueAwareText {
|
|
||||||
- issues : ImmutableList<ProbableIssue>
|
|
||||||
- text : String
|
|
||||||
~ SimpleProbabilisticIssueAwareText(text : String, issues : List<ProbableIssue>)
|
|
||||||
+ equals(o : Object) : boolean
|
|
||||||
+ filtered() : Filterer<? extends ProbabilisticIssueAwareText, ? extends ProbableIssue>
|
|
||||||
- filteredGroup(predicate : Predicate<? super ProbableIssue>) : ProbabilisticIssueAwareText
|
|
||||||
- filteredItems(predicate : Predicate<? super ProbableIssue>) : ImmutableList<ProbableIssue>
|
|
||||||
+ hashCode() : int
|
|
||||||
+ issues() : List<? extends ProbableIssue>
|
|
||||||
+ text() : String
|
|
||||||
}
|
|
||||||
class SimpleProbabilisticIssueWiseText {
|
|
||||||
- issues : ImmutableList<ProbableIssue>
|
|
||||||
- text : String
|
|
||||||
+ SimpleProbabilisticIssueWiseText(text : String, issues : List<ProbableIssue>)
|
|
||||||
+ equals(o : Object) : boolean
|
|
||||||
+ filtered() : Filterer<? extends ProbabilisticIssueWiseText, ? extends ProbableIssue>
|
|
||||||
- filteredGroup(predicate : Predicate<? super ProbableIssue>) : ProbabilisticIssueWiseText
|
|
||||||
- filteredItems(predicate : Predicate<? super ProbableIssue>) : ImmutableList<ProbableIssue>
|
|
||||||
+ hashCode() : int
|
|
||||||
+ issues() : List<? extends ProbableIssue>
|
|
||||||
+ text() : String
|
|
||||||
}
|
|
||||||
class SimpleProbableIssue {
|
|
||||||
- probability : double
|
- probability : double
|
||||||
~ SimpleProbableIssue(issuePosition : IssuePosition, issueType : IssueType, probability : double)
|
+ SimpleProbableThreat(name : String, id : int, threatType : ThreatType, probability : double)
|
||||||
+ equals(o : Object) : boolean
|
+ equals(o : Object) : boolean
|
||||||
+ hashCode() : int
|
+ hashCode() : int
|
||||||
+ probability() : double
|
+ 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<Threat>
|
||||||
|
- systemId : String
|
||||||
|
+ SimpleThreatAwareSystem(systemId : String, issues : List<Threat>)
|
||||||
|
+ equals(o : Object) : boolean
|
||||||
|
+ filtered() : Filterer<? extends ThreatAwareSystem, ? extends Threat>
|
||||||
|
- filteredGroup(predicate : Predicate<? super Threat>) : ThreatAwareSystem
|
||||||
|
- filteredItems(predicate : Predicate<? super Threat>) : List<Threat>
|
||||||
|
+ hashCode() : int
|
||||||
|
+ systemId() : String
|
||||||
|
+ threats() : List<? extends Threat>
|
||||||
|
+ toString() : String
|
||||||
|
}
|
||||||
|
interface Threat {
|
||||||
|
+ id() : int {abstract}
|
||||||
|
+ name() : String {abstract}
|
||||||
|
+ type() : ThreatType {abstract}
|
||||||
|
}
|
||||||
|
interface ThreatAwareSystem {
|
||||||
|
+ filtered() : Filterer<? extends ThreatAwareSystem, ? extends Threat> {abstract}
|
||||||
|
+ systemId() : String {abstract}
|
||||||
|
+ threats() : List<? extends Threat> {abstract}
|
||||||
|
}
|
||||||
|
enum ThreatType {
|
||||||
|
+ ROOTKIT {static}
|
||||||
|
+ TROJAN {static}
|
||||||
|
+ WORM {static}
|
||||||
|
+ valueOf(name : String) : ThreatType {static}
|
||||||
|
+ values() : ThreatType[] {static}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SimpleIssueWiseText --> "-issues" Issue
|
SimpleThreatAwareSystem --> "-issues" Threat
|
||||||
SimpleProbabilisticIssueAwareText --> "-issues" ProbableIssue
|
SimpleThreat --> "-threatType" ThreatType
|
||||||
SimpleIssue --> "-issueType" IssueType
|
SimpleProbabilisticThreatAwareSystem --> "-threats" ProbableThreat
|
||||||
SimpleIssueAwareText --> "-issues" Issue
|
ProbabilisticThreatAwareSystem --|> ThreatAwareSystem
|
||||||
SimpleProbabilisticIssueWiseText --> "-issues" ProbableIssue
|
ProbableThreat --|> Threat
|
||||||
SimpleIssue --> "-issuePosition" IssuePosition
|
SimpleProbabilisticThreatAwareSystem ..|> ProbabilisticThreatAwareSystem
|
||||||
ProbabilisticIssueAwareText --|> IssueAwareText
|
SimpleProbableThreat ..|> ProbableThreat
|
||||||
ProbabilisticIssueWiseText --|> IssueWiseText
|
SimpleProbableThreat --|> SimpleThreat
|
||||||
ProbableIssue --|> Issue
|
SimpleThreat ..|> Threat
|
||||||
SimpleIssue ..|> Issue
|
SimpleThreatAwareSystem ..|> ThreatAwareSystem
|
||||||
SimpleIssueAwareText ..|> IssueAwareText
|
|
||||||
SimpleIssueWiseText ..|> IssueWiseText
|
|
||||||
SimpleProbabilisticIssueAwareText ..|> ProbabilisticIssueAwareText
|
|
||||||
SimpleProbabilisticIssueWiseText ..|> ProbabilisticIssueWiseText
|
|
||||||
SimpleProbableIssue ..|> ProbableIssue
|
|
||||||
SimpleProbableIssue --|> SimpleIssue
|
|
||||||
@enduml
|
@enduml
|
@ -39,37 +39,34 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.guava</groupId>
|
<groupId>com.google.guava</groupId>
|
||||||
<artifactId>guava</artifactId>
|
<artifactId>guava</artifactId>
|
||||||
<version>29.0-jre</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit-jupiter-api</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
<version>5.6.2</version>
|
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit-jupiter-engine</artifactId>
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<version>5.6.2</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.assertj</groupId>
|
|
||||||
<artifactId>assertj-core</artifactId>
|
|
||||||
<version>3.16.1</version>
|
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<version>2.22.2</version>
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
</plugin>
|
<executions>
|
||||||
<plugin>
|
<execution>
|
||||||
<artifactId>maven-failsafe-plugin</artifactId>
|
<configuration>
|
||||||
<version>2.22.2</version>
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>com.iluwatar.filterer.App</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
111
filterer/src/main/java/com/iluwatar/filterer/App.java
Normal file
111
filterer/src/main/java/com/iluwatar/filterer/App.java
Normal file
@ -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<ProbableThreat> 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<Threat> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -21,29 +21,29 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.filterer.issue;
|
package com.iluwatar.filterer.threat;
|
||||||
|
|
||||||
import com.iluwatar.filterer.domain.Filterer;
|
import com.iluwatar.filterer.domain.Filterer;
|
||||||
|
|
||||||
import java.util.List;
|
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}
|
* {@inheritDoc}
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
List<? extends ProbableIssue> issues();
|
List<? extends ProbableThreat> threats();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
Filterer<? extends ProbabilisticIssueAwareText, ? extends ProbableIssue> filtered();
|
Filterer<? extends ProbabilisticThreatAwareSystem, ? extends ProbableThreat> filtered();
|
||||||
}
|
}
|
||||||
|
|
@ -21,15 +21,15 @@
|
|||||||
* THE SOFTWARE.
|
* 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.
|
* Returns probability of occurrence of given threat.
|
||||||
* @return probability of occurrence of given issue.
|
* @return probability of occurrence of given threat.
|
||||||
*/
|
*/
|
||||||
double probability();
|
double probability();
|
||||||
}
|
}
|
@ -21,7 +21,7 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.filterer.issue;
|
package com.iluwatar.filterer.threat;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.iluwatar.filterer.domain.Filterer;
|
import com.iluwatar.filterer.domain.Filterer;
|
||||||
@ -29,56 +29,60 @@ import com.iluwatar.filterer.domain.Filterer;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
public class SimpleProbabilisticIssueAwareText implements ProbabilisticIssueAwareText {
|
public class SimpleProbabilisticThreatAwareSystem implements ProbabilisticThreatAwareSystem {
|
||||||
|
|
||||||
private final String text;
|
private final String systemId;
|
||||||
private final ImmutableList<ProbableIssue> issues;
|
private final ImmutableList<ProbableThreat> threats;
|
||||||
|
|
||||||
SimpleProbabilisticIssueAwareText(final String text, final List<ProbableIssue> issues) {
|
public SimpleProbabilisticThreatAwareSystem(
|
||||||
this.text = text;
|
final String systemId,
|
||||||
this.issues = ImmutableList.copyOf(issues);
|
final List<ProbableThreat> threats
|
||||||
|
) {
|
||||||
|
this.systemId = systemId;
|
||||||
|
this.threats = ImmutableList.copyOf(threats);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String text() {
|
public String systemId() {
|
||||||
return text;
|
return systemId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<? extends ProbableIssue> issues() {
|
public List<? extends ProbableThreat> threats() {
|
||||||
return issues;
|
return threats;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Filterer<? extends ProbabilisticIssueAwareText, ? extends ProbableIssue> filtered() {
|
public Filterer<? extends ProbabilisticThreatAwareSystem, ? extends ProbableThreat> filtered() {
|
||||||
return this::filteredGroup;
|
return this::filteredGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ProbabilisticIssueAwareText filteredGroup(
|
private ProbabilisticThreatAwareSystem filteredGroup(
|
||||||
final Predicate<? super ProbableIssue> predicate
|
final Predicate<? super ProbableThreat> predicate
|
||||||
) {
|
) {
|
||||||
return new SimpleProbabilisticIssueAwareText(this.text, filteredItems(predicate));
|
return new SimpleProbabilisticThreatAwareSystem(this.systemId, filteredItems(predicate));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImmutableList<ProbableIssue> filteredItems(
|
private List<ProbableThreat> filteredItems(
|
||||||
final Predicate<? super ProbableIssue> predicate
|
final Predicate<? super ProbableThreat> predicate
|
||||||
) {
|
) {
|
||||||
return this.issues.stream()
|
return this.threats.stream()
|
||||||
.filter(predicate)
|
.filter(predicate)
|
||||||
.collect(ImmutableList.toImmutableList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -89,13 +93,21 @@ public class SimpleProbabilisticIssueAwareText implements ProbabilisticIssueAwar
|
|||||||
if (o == null || getClass() != o.getClass()) {
|
if (o == null || getClass() != o.getClass()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SimpleProbabilisticIssueAwareText that = (SimpleProbabilisticIssueAwareText) o;
|
SimpleProbabilisticThreatAwareSystem that = (SimpleProbabilisticThreatAwareSystem) o;
|
||||||
return text.equals(that.text)
|
return systemId.equals(that.systemId)
|
||||||
&& issues.equals(that.issues);
|
&& threats.equals(that.threats);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(text, issues);
|
return Objects.hash(systemId, threats);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SimpleProbabilisticThreatAwareSystem{"
|
||||||
|
+ "systemId='" + systemId + '\''
|
||||||
|
+ ", threats=" + threats
|
||||||
|
+ '}';
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -21,22 +21,23 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.filterer.issue;
|
package com.iluwatar.filterer.threat;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
public class SimpleProbableIssue extends SimpleIssue implements ProbableIssue {
|
public class SimpleProbableThreat extends SimpleThreat implements ProbableThreat {
|
||||||
|
|
||||||
private final double probability;
|
private final double probability;
|
||||||
|
|
||||||
SimpleProbableIssue(final IssuePosition issuePosition,
|
public SimpleProbableThreat(final String name,
|
||||||
final IssueType issueType,
|
final int id,
|
||||||
final double probability
|
final ThreatType threatType,
|
||||||
|
final double probability
|
||||||
) {
|
) {
|
||||||
super(issuePosition, issueType);
|
super(threatType, id, name);
|
||||||
this.probability = probability;
|
this.probability = probability;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +60,7 @@ public class SimpleProbableIssue extends SimpleIssue implements ProbableIssue {
|
|||||||
if (!super.equals(o)) {
|
if (!super.equals(o)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SimpleProbableIssue that = (SimpleProbableIssue) o;
|
SimpleProbableThreat that = (SimpleProbableThreat) o;
|
||||||
return Double.compare(that.probability, probability) == 0;
|
return Double.compare(that.probability, probability) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,4 +68,12 @@ public class SimpleProbableIssue extends SimpleIssue implements ProbableIssue {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(super.hashCode(), probability);
|
return Objects.hash(super.hashCode(), probability);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SimpleProbableThreat{"
|
||||||
|
+ "probability=" + probability
|
||||||
|
+ "} "
|
||||||
|
+ super.toString();
|
||||||
|
}
|
||||||
}
|
}
|
@ -21,42 +21,54 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.filterer.issue;
|
package com.iluwatar.filterer.threat;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class SimpleIssue implements Issue {
|
/**
|
||||||
|
* Represents a simple threat.
|
||||||
|
*/
|
||||||
|
public class SimpleThreat implements Threat {
|
||||||
|
|
||||||
private final IssuePosition issuePosition;
|
private final ThreatType threatType;
|
||||||
private final IssueType issueType;
|
private final int id;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
SimpleIssue(final IssuePosition issuePosition, IssueType issueType) {
|
/**
|
||||||
this.issuePosition = issuePosition;
|
* Constructor.
|
||||||
this.issueType = issueType;
|
*
|
||||||
|
* @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}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int startOffset() {
|
public String name() {
|
||||||
return issuePosition.startOffset();
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int endOffset() {
|
public int id() {
|
||||||
return issuePosition.endOffset();
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public IssueType type() {
|
public ThreatType type() {
|
||||||
return issueType;
|
return threatType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -67,13 +79,23 @@ public class SimpleIssue implements Issue {
|
|||||||
if (o == null || getClass() != o.getClass()) {
|
if (o == null || getClass() != o.getClass()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SimpleIssue that = (SimpleIssue) o;
|
SimpleThreat that = (SimpleThreat) o;
|
||||||
return issuePosition.equals(that.issuePosition)
|
return id == that.id
|
||||||
&& issueType == that.issueType;
|
&& threatType == that.threatType
|
||||||
|
&& Objects.equals(name, that.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
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 + '\''
|
||||||
|
+ '}';
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -21,7 +21,7 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.filterer.issue;
|
package com.iluwatar.filterer.threat;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.iluwatar.filterer.domain.Filterer;
|
import com.iluwatar.filterer.domain.Filterer;
|
||||||
@ -30,17 +30,18 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
public class SimpleIssueAwareText implements IssueAwareText {
|
public class SimpleThreatAwareSystem implements ThreatAwareSystem {
|
||||||
|
|
||||||
private final String text;
|
private final String systemId;
|
||||||
private final ImmutableList<Issue> issues;
|
private final ImmutableList<Threat> issues;
|
||||||
|
|
||||||
SimpleIssueAwareText(final String text, final List<Issue> issues) {
|
public SimpleThreatAwareSystem(final String systemId, final List<Threat> issues) {
|
||||||
this.text = text;
|
this.systemId = systemId;
|
||||||
this.issues = ImmutableList.copyOf(issues);
|
this.issues = ImmutableList.copyOf(issues);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,15 +49,15 @@ public class SimpleIssueAwareText implements IssueAwareText {
|
|||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String text() {
|
public String systemId() {
|
||||||
return text;
|
return systemId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<? extends Issue> issues() {
|
public List<? extends Threat> threats() {
|
||||||
return new ArrayList<>(issues);
|
return new ArrayList<>(issues);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,18 +65,18 @@ public class SimpleIssueAwareText implements IssueAwareText {
|
|||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Filterer<? extends IssueAwareText, ? extends Issue> filtered() {
|
public Filterer<? extends ThreatAwareSystem, ? extends Threat> filtered() {
|
||||||
return this::filteredGroup;
|
return this::filteredGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IssueAwareText filteredGroup(Predicate<? super Issue> predicate) {
|
private ThreatAwareSystem filteredGroup(Predicate<? super Threat> predicate) {
|
||||||
return new SimpleIssueAwareText(this.text, filteredItems(predicate));
|
return new SimpleThreatAwareSystem(this.systemId, filteredItems(predicate));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImmutableList<Issue> filteredItems(Predicate<? super Issue> predicate) {
|
private List<Threat> filteredItems(Predicate<? super Threat> predicate) {
|
||||||
return this.issues.stream()
|
return this.issues.stream()
|
||||||
.filter(predicate)
|
.filter(predicate)
|
||||||
.collect(ImmutableList.toImmutableList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -86,13 +87,21 @@ public class SimpleIssueAwareText implements IssueAwareText {
|
|||||||
if (o == null || getClass() != o.getClass()) {
|
if (o == null || getClass() != o.getClass()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
SimpleIssueAwareText that = (SimpleIssueAwareText) o;
|
SimpleThreatAwareSystem that = (SimpleThreatAwareSystem) o;
|
||||||
return text.equals(that.text)
|
return systemId.equals(that.systemId)
|
||||||
&& issues.equals(that.issues);
|
&& issues.equals(that.issues);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(text, issues);
|
return Objects.hash(systemId, issues);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "SimpleThreatAwareSystem{"
|
||||||
|
+ "systemId='" + systemId
|
||||||
|
+ '\'' + ", issues=" + issues
|
||||||
|
+ '}';
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -21,29 +21,29 @@
|
|||||||
* THE SOFTWARE.
|
* 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.
|
* Returns threat type.
|
||||||
* @return {@link IssueType}
|
* @return {@link ThreatType}
|
||||||
*/
|
*/
|
||||||
IssueType type();
|
ThreatType type();
|
||||||
}
|
}
|
@ -21,35 +21,35 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.filterer.issue;
|
package com.iluwatar.filterer.threat;
|
||||||
|
|
||||||
import com.iluwatar.filterer.domain.Filterer;
|
import com.iluwatar.filterer.domain.Filterer;
|
||||||
|
|
||||||
import java.util.List;
|
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.
|
* Returns list of threats for this system.
|
||||||
* @return list of issues for this text.
|
* @return list of threats for this system.
|
||||||
*/
|
*/
|
||||||
List<? extends Issue> issues();
|
List<? extends Threat> threats();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the instance of {@link Filterer} helper interface that allows to covariantly
|
* Returns the instance of {@link Filterer} helper interface that allows to covariantly
|
||||||
* specify lower bound for predicate that we want to filter by.
|
* specify lower bound for predicate that we want to filter by.
|
||||||
* @return an instance of {@link Filterer} helper interface.
|
* @return an instance of {@link Filterer} helper interface.
|
||||||
*/
|
*/
|
||||||
Filterer<? extends IssueAwareText, ? extends Issue> filtered();
|
Filterer<? extends ThreatAwareSystem, ? extends Threat> filtered();
|
||||||
|
|
||||||
}
|
}
|
@ -21,6 +21,6 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.filterer.issue;
|
package com.iluwatar.filterer.threat;
|
||||||
|
|
||||||
enum IssueType { GRAMMAR, SPELLING }
|
public enum ThreatType { TROJAN, WORM, ROOTKIT }
|
33
filterer/src/test/java/com/iluwatar/filterer/AppTest.java
Normal file
33
filterer/src/test/java/com/iluwatar/filterer/AppTest.java
Normal file
@ -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[]{});
|
||||||
|
}
|
||||||
|
}
|
@ -21,32 +21,31 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.filterer.issue;
|
package com.iluwatar.filterer.threat;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
class SimpleProbabilisticIssueAwareTextTest {
|
|
||||||
|
|
||||||
|
class SimpleProbabilisticThreatAwareSystemTest {
|
||||||
@Test
|
@Test
|
||||||
void shouldFilterByProbability() {
|
void shouldFilterByProbability() {
|
||||||
//given
|
//given
|
||||||
ProbableIssue spellingIssue = new SimpleProbableIssue(IssuePosition.of(4, 5), IssueType.SPELLING, 100);
|
ProbableThreat trojan = new SimpleProbableThreat("Troyan-ArcBomb", 1, ThreatType.TROJAN, 0.99);
|
||||||
ProbableIssue grammarIssue = new SimpleProbableIssue(IssuePosition.of(8, 12), IssueType.GRAMMAR, 99);
|
ProbableThreat rootkit = new SimpleProbableThreat("Rootkit-System", 2, ThreatType.ROOTKIT, 0.8);
|
||||||
List<ProbableIssue> issues = List.of(spellingIssue, grammarIssue);
|
List<ProbableThreat> probableThreats = List.of(trojan, rootkit);
|
||||||
|
|
||||||
SimpleProbabilisticIssueAwareText simpleIssueWiseText = new SimpleProbabilisticIssueAwareText("I mihgt gone there", issues);
|
ProbabilisticThreatAwareSystem simpleProbabilisticThreatAwareSystem =
|
||||||
|
new SimpleProbabilisticThreatAwareSystem("System-1", probableThreats);
|
||||||
|
|
||||||
//when
|
//when
|
||||||
ProbabilisticIssueAwareText filtered = simpleIssueWiseText.filtered()
|
ProbabilisticThreatAwareSystem filtered = simpleProbabilisticThreatAwareSystem.filtered()
|
||||||
.by(issue1 -> Double.compare(issue1.probability(), 99) == 0);
|
.by(probableThreat -> Double.compare(probableThreat.probability(), 0.99) == 0);
|
||||||
|
|
||||||
//then
|
//then
|
||||||
assertThat(filtered.issues()).hasSize(1);
|
assertEquals(filtered.threats().size(), 1);
|
||||||
assertThat(filtered.issues()).element(0).isEqualTo(grammarIssue);
|
assertEquals(filtered.threats().get(0), trojan);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -21,32 +21,30 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.iluwatar.filterer.issue;
|
package com.iluwatar.filterer.threat;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
class SimpleIssueAwareTextTest {
|
|
||||||
|
|
||||||
|
class SimpleThreatAwareSystemTest {
|
||||||
@Test
|
@Test
|
||||||
void shouldFilterByStartOffset() {
|
void shouldFilterByThreatType() {
|
||||||
//given
|
//given
|
||||||
SimpleIssue spellingIssue = new SimpleIssue(IssuePosition.of(4, 5), IssueType.SPELLING);
|
Threat rootkit = new SimpleThreat(ThreatType.ROOTKIT, 1, "Simple-Rootkit");
|
||||||
SimpleIssue grammarIssue = new SimpleIssue(IssuePosition.of(8, 12), IssueType.GRAMMAR);
|
Threat trojan = new SimpleThreat(ThreatType.TROJAN, 2, "Simple-Trojan");
|
||||||
List<Issue> issues = List.of(spellingIssue, grammarIssue);
|
List<Threat> threats = List.of(rootkit, trojan);
|
||||||
|
|
||||||
SimpleIssueAwareText simpleIssueWiseText = new SimpleIssueAwareText("I mihgt gone there", issues);
|
ThreatAwareSystem threatAwareSystem = new SimpleThreatAwareSystem("System-1", threats);
|
||||||
|
|
||||||
//when
|
//when
|
||||||
IssueAwareText filtered = simpleIssueWiseText.filtered()
|
ThreatAwareSystem rootkitThreatAwareSystem = threatAwareSystem.filtered()
|
||||||
.by(issue1 -> issue1.startOffset() == 4);
|
.by(threat -> threat.type() == ThreatType.ROOTKIT);
|
||||||
|
|
||||||
//then
|
//then
|
||||||
assertThat(filtered.issues()).hasSize(1);
|
assertEquals(rootkitThreatAwareSystem.threats().size(), 1);
|
||||||
assertThat(filtered.issues()).element(0).isEqualTo(spellingIssue);
|
assertEquals(rootkitThreatAwareSystem.threats().get(0), rootkit);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user