Skip to content

Commit

Permalink
refactor(server): moved ServerContext creation to factory
Browse files Browse the repository at this point in the history
Refs: #43
  • Loading branch information
nergal-perm committed Jul 24, 2024
1 parent 81cbe76 commit 6c2892e
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 114 deletions.
154 changes: 154 additions & 0 deletions src/main/java/ru/ewc/checklogic/FullServerContext.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/*
* MIT License
*
* Copyright (c) 2024 Decision-Driven Development
*
* 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 ru.ewc.checklogic;

import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.SneakyThrows;
import ru.ewc.decisions.api.ComputationContext;
import ru.ewc.decisions.api.DecitaException;
import ru.ewc.state.State;

/**
* I am a unique instance of a decision table computation.
*
* @since 0.1.0
*/
@SuppressWarnings("PMD.ProhibitPublicStaticMethods")
public final class FullServerContext implements ServerContext {
/**
* The stored state of the system, persisted between requests.
*/
private final State state;

/**
* The URI of the tables folder, used to recreate the computation context for each request.
*/
private final URI tables;

/**
* The URI of the commands folder, used to recreate the computation context for each request.
*/
private final URI commands;

/**
* The context of the computation.
*/
private ComputationContext context;

/**
* The cached request parameters.
*/
private final Map<String, String> parameters;

FullServerContext(final State initial, final URI tables, final URI commands) {
this.state = initial;
this.tables = tables;
this.commands = commands;
this.context = new ComputationContext(initial, tables, commands);
this.parameters = new HashMap<>(2);
}

@Override
public void perform(final String command) {
this.perform(command, Map.of());
}

@Override
public void perform(final String command, final Map<String, String> args) {
args.forEach(
(key, value) -> {
if (!value.isEmpty()) {
final String[] split = key.split("::");
this.context.setValueFor(split[0], split[1], value);
}
});
this.context.perform(command);
this.context = new ComputationContext(this.state, this.tables, this.commands);
}

@Override
public Map<String, String> stateFor(final String table, final Map<String, String> entities) {
final Map<String, String> actual = HashMap.newHashMap(entities.size());
for (final String fragment : entities.keySet()) {
actual.put(fragment, this.context.valueFor(table, fragment));
}
return actual;
}

@Override
public Map<String, Map<String, Object>> storedState() {
return this.context.storedState();
}

@Override
public String valueFor(final String locator, final String fragment) {
String value;
try {
value = this.context.valueFor(locator, fragment);
} catch (final DecitaException exception) {
value = "";
}
return value;
}

@Override
public Map<String, List<String>> commandData() {
return this.context.commandData();
}

@Override
public boolean isAvailable(final String command, final String field) {
return "true".equalsIgnoreCase(this.context.decisionFor(command).get(field));
}

@Override
public void update(final List<String> values) {
this.state.locators().put(this.cached("request"), InMemoryStorage.from(values));
this.context = new ComputationContext(this.state, this.tables, this.commands);
}

@Override
public String cached(final String parameter) {
return this.parameters.getOrDefault(parameter, "");
}

@Override
public void cache(final String parameter, final String value) {
this.parameters.put(parameter, value);
}

@SneakyThrows
static ServerContext contextForFolder(final String root) {
final ServerContext result = new ServerContextFactory(root).instance(
LogicChecker.stateFromAppConfig(FileUtils.applicationConfig(root))
);
result.cache("available", "available");
result.cache("request", "request");
return result;
}
}
2 changes: 1 addition & 1 deletion src/main/java/ru/ewc/checklogic/LogicChecker.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public static void main(final String[] args) {
throw new IllegalArgumentException("Please provide the path to the resources");
}
final String root = args[0];
new WebServer(ServerContext.contextForFolder(root), root).start();
new WebServer(FullServerContext.contextForFolder(root), root).start();
}

@SneakyThrows
Expand Down
121 changes: 14 additions & 107 deletions src/main/java/ru/ewc/checklogic/ServerContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,128 +21,35 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package ru.ewc.checklogic;

import java.net.URI;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.SneakyThrows;
import ru.ewc.decisions.api.ComputationContext;
import ru.ewc.decisions.api.DecitaException;
import ru.ewc.state.State;

/**
* I am a unique instance of a decision table computation.
* I am the context for the server. I provide the server with the necessary information to perform
* the commands, to store the state of the system and to make decisions based on the state.
*
* @since 0.1.0
* @since 0.3.2
*/
@SuppressWarnings("PMD.ProhibitPublicStaticMethods")
public final class ServerContext {
/**
* The stored state of the system, persisted between requests.
*/
private final State state;

/**
* The URI of the tables folder, used to recreate the computation context for each request.
*/
private final URI tables;

/**
* The URI of the commands folder, used to recreate the computation context for each request.
*/
private final URI commands;

/**
* The context of the computation.
*/
private ComputationContext context;

/**
* The cached request parameters.
*/
private final Map<String, String> parameters;

public ServerContext(final State initial, final URI tables, final URI commands) {
this.state = initial;
this.tables = tables;
this.commands = commands;
this.context = new ComputationContext(initial, tables, commands);
this.parameters = new HashMap<>(2);
}

public void perform(final String command) {
this.perform(command, Map.of());
}

public void perform(final String command, final Map<String, String> args) {
args.forEach(
(key, value) -> {
if (!value.isEmpty()) {
final String[] split = key.split("::");
this.context.setValueFor(split[0], split[1], value);
}
});
this.context.perform(command);
this.context = new ComputationContext(this.state, this.tables, this.commands);
}
public interface ServerContext {
void perform(String command);

public Map<String, String> stateFor(final String table, final Map<String, String> entities) {
final Map<String, String> actual = HashMap.newHashMap(entities.size());
for (final String fragment : entities.keySet()) {
actual.put(fragment, this.context.valueFor(table, fragment));
}
return actual;
}
void perform(String command, Map<String, String> args);

public Map<String, Map<String, Object>> storedState() {
return this.context.storedState();
}
Map<String, String> stateFor(String table, Map<String, String> entities);

public String valueFor(final String locator, final String fragment) {
String value;
try {
value = this.context.valueFor(locator, fragment);
} catch (final DecitaException exception) {
value = "";
}
return value;
}
Map<String, Map<String, Object>> storedState();

public Map<String, List<String>> commandData() {
return this.context.commandData();
}
String valueFor(String locator, String fragment);

public boolean isAvailable(final String command, final String field) {
return "true".equalsIgnoreCase(this.context.decisionFor(command).get(field));
}
Map<String, List<String>> commandData();

public void update(final List<String> values) {
this.state.locators().put(this.cached("request"), InMemoryStorage.from(values));
this.context = new ComputationContext(this.state, this.tables, this.commands);
}
boolean isAvailable(String command, String field);

public String cached(final String parameter) {
return this.parameters.getOrDefault(parameter, "");
}
void update(List<String> values);

public void cache(final String parameter, final String value) {
this.parameters.put(parameter, value);
}
String cached(String parameter);

@SneakyThrows
// @todo #33 Move server context creation to a factory
static ServerContext contextForFolder(final String root) {
final ServerContext result = new ServerContext(
LogicChecker.stateFromAppConfig(FileUtils.applicationConfig(root)),
Path.of(root, "tables").toUri(),
Path.of(root, "commands").toUri()
);
result.cache("available", "available");
result.cache("request", "request");
return result;
}
void cache(String parameter, String value);
}
58 changes: 58 additions & 0 deletions src/main/java/ru/ewc/checklogic/ServerContextFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* MIT License
*
* Copyright (c) 2024 Decision-Driven Development
*
* 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 ru.ewc.checklogic;

import java.nio.file.Path;
import ru.ewc.state.State;

/**
* I am a factory for creating server contexts.
*
* @since 0.3.2
*/
public class ServerContextFactory {
/**
* The root path for the external business logic resources.
*/
private final String root;

public ServerContextFactory(final String root) {
this.root = root;
}

/**
* Creates a new server context.
*
* @param initial The initial state of the system.
* @return A new server context.
*/
// @todo #33 Decide on what type of ServerContext to create
public ServerContext instance(final State initial) {
return new FullServerContext(
initial,
Path.of(this.root, "tables").toUri(),
Path.of(this.root, "commands").toUri()
);
}
}
2 changes: 1 addition & 1 deletion src/main/java/ru/ewc/checklogic/server/CommandPage.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public Response executeCommand(final Request request) {
Response response;
try {
this.computation.perform(command, args);
response = Response.htmlOk("OK", Map.of("HX-Redirect", "/"));
response = Response.htmlOk("OK", Map.of("HX-Redirect", "/state"));
} catch (final DecitaException exception) {
response = Response.htmlOk(
this.error.renderTemplate(
Expand Down
Loading

2 comments on commit 6c2892e

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 6c2892e Jul 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 33-8cc5359b disappeared from src/main/java/ru/ewc/checklogic/ServerContext.java), that's why I closed #43. Please, remember that the puzzle was not necessarily removed in this particular commit. Maybe it happened earlier, but we discovered this fact only now.

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on 6c2892e Jul 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Puzzle 33-2ef7a1de discovered in src/main/java/ru/ewc/checklogic/ServerContextFactory.java) and submitted as #46. Please, remember that the puzzle was not necessarily added in this particular commit. Maybe it was added earlier, but we discovered it only now.

Please sign in to comment.