-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add abstraction for a CoffeeNet view model
Multiple parts of CoffeeNet contribute UI/UX components to the final application. This abstraction allows to write these in a technology-agnostic way.
- Loading branch information
Showing
4 changed files
with
218 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 109 additions & 0 deletions
109
...net-platform-domain/src/main/java/rocks/coffeenet/platform/domain/web/CoffeeNetModel.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package rocks.coffeenet.platform.domain.web; | ||
|
||
import com.fasterxml.jackson.annotation.JsonAnyGetter; | ||
|
||
import java.util.AbstractMap; | ||
import java.util.Collections; | ||
import java.util.LinkedHashMap; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.Set; | ||
|
||
|
||
/** | ||
* This view model makes common attributes available to the view layer in web applications. It is made available under | ||
* the name {@link CoffeeNetModel#MODEL_NAME}. | ||
* | ||
* <p>Each attribute element can be singular or a hierarchical object like a POJO or nested Map.</p> | ||
* | ||
* @author Florian 'punycode' Krupicka - [email protected] | ||
*/ | ||
public class CoffeeNetModel extends AbstractMap<String, Object> { | ||
|
||
public static final String MODEL_NAME = "coffeenet"; | ||
|
||
private final Map<String, Object> attributes; | ||
|
||
private CoffeeNetModel(Builder builder) { | ||
|
||
this.attributes = Collections.unmodifiableMap(builder.content); | ||
} | ||
|
||
@Override | ||
public Set<Entry<String, Object>> entrySet() { | ||
|
||
return attributes.entrySet(); | ||
} | ||
|
||
|
||
@JsonAnyGetter | ||
Map<String, Object> getAttributes() { | ||
|
||
return attributes; | ||
} | ||
|
||
|
||
@Override | ||
public boolean equals(Object o) { | ||
|
||
if (this == o) { | ||
return true; | ||
} | ||
|
||
if (o == null || getClass() != o.getClass() || !super.equals(o)) { | ||
return false; | ||
} | ||
|
||
return Objects.equals(attributes, ((CoffeeNetModel) o).attributes); | ||
} | ||
|
||
|
||
@Override | ||
public int hashCode() { | ||
|
||
return Objects.hash(super.hashCode(), attributes); | ||
} | ||
|
||
/** | ||
* Builder for creating immutable {@link CoffeeNetModel} instances. | ||
*/ | ||
public static class Builder { | ||
|
||
private final Map<String, Object> content; | ||
|
||
public Builder() { | ||
|
||
this.content = new LinkedHashMap<>(); | ||
} | ||
|
||
/** | ||
* Contribute a view model property using given {@code key} and {@code value}. | ||
*/ | ||
public Builder withDetail(String key, Object value) { | ||
|
||
this.content.put(key, value); | ||
|
||
return this; | ||
} | ||
|
||
|
||
/** | ||
* Contribute multiple view model properties given the contents of {@code details}. | ||
*/ | ||
public Builder withDetails(Map<String, Object> details) { | ||
|
||
this.content.putAll(details); | ||
|
||
return this; | ||
} | ||
|
||
|
||
/** | ||
* Create a new {@link CoffeeNetModel} instance based on the state of this builder. | ||
*/ | ||
public CoffeeNetModel build() { | ||
|
||
return new CoffeeNetModel(this); | ||
} | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
...m-domain/src/main/java/rocks/coffeenet/platform/domain/web/CoffeeNetModelContributor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package rocks.coffeenet.platform.domain.web; | ||
|
||
/** | ||
* Contributes additional properties to the global COLA view model. | ||
* | ||
* @author Florian 'punycode' Krupicka - [email protected] | ||
*/ | ||
@FunctionalInterface | ||
public interface CoffeeNetModelContributor { | ||
|
||
/** | ||
* Contribute parameters. | ||
* | ||
* @param builder | ||
*/ | ||
void contribute(CoffeeNetModel.Builder builder); | ||
} |
86 changes: 86 additions & 0 deletions
86
...ain/src/test/java/rocks/coffeenet/platform/domain/web/CoffeeNetModelContributorTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package rocks.coffeenet.platform.domain.web; | ||
|
||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import java.util.Collections; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.assertj.core.api.Assertions.entry; | ||
|
||
|
||
/** | ||
* @author Florian 'punycode' Krupicka - [email protected] | ||
*/ | ||
class CoffeeNetModelContributorTests { | ||
|
||
private CoffeeNetModel.Builder builder; | ||
|
||
@BeforeEach | ||
void setup() { | ||
|
||
builder = new CoffeeNetModel.Builder(); | ||
} | ||
|
||
|
||
@Test | ||
@DisplayName("should add singular detail from contributer") | ||
void singularDetail() { | ||
|
||
CoffeeNetModelContributor c = (b) -> b.withDetail("single", "value"); | ||
|
||
c.contribute(builder); | ||
|
||
CoffeeNetModel model = builder.build(); | ||
assertThat(model).containsExactly(entry("single", "value")); | ||
} | ||
|
||
|
||
@Test | ||
@DisplayName("should add complex detail from contributer") | ||
void complexDetail() { | ||
|
||
Map<String, Object> complex = Collections.singletonMap("key", "value"); | ||
CoffeeNetModelContributor c = (b) -> b.withDetail("complex", complex); | ||
|
||
c.contribute(builder); | ||
|
||
CoffeeNetModel model = builder.build(); | ||
assertThat(model).contains(entry("complex", complex)); | ||
} | ||
|
||
|
||
@Test | ||
@DisplayName("should add details from multiple contributers") | ||
void multipleContributors() { | ||
|
||
CoffeeNetModelContributor c1 = (b) -> b.withDetail("key1", "value1"); | ||
CoffeeNetModelContributor c2 = (b) -> b.withDetail("key2", "value2"); | ||
|
||
c1.contribute(builder); | ||
c2.contribute(builder); | ||
|
||
CoffeeNetModel model = builder.build(); | ||
assertThat(model).contains(entry("key2", "value2"), entry("key1", "value1")); | ||
} | ||
|
||
|
||
@Test | ||
@DisplayName("should add multiple details from contributer") | ||
void multipleDetails() { | ||
|
||
HashMap<String, Object> map = new HashMap<>(); | ||
map.put("key1", "value1"); | ||
map.put("key2", "value2"); | ||
|
||
CoffeeNetModelContributor c = (b) -> b.withDetails(map); | ||
|
||
c.contribute(builder); | ||
|
||
CoffeeNetModel model = builder.build(); | ||
assertThat(model).containsExactly(entry("key1", "value1"), entry("key2", "value2")); | ||
} | ||
} |