managers.nodes.CombinationGroupManager.java Source code

Java tutorial

Introduction

Here is the source code for managers.nodes.CombinationGroupManager.java

Source

// CombinationGroupManager.java --- Manager that handles operations involving CombinationGroup nodes.

// Copyright (C) 2013-2015  Tim Krones

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package managers.nodes;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import constants.NodeType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import models.nodes.CombinationGroup;
import models.nodes.OutputString;
import models.nodes.Slot;
import models.relationships.Has;
import play.libs.F.Callback;
import play.libs.F.Function;
import play.libs.F.Promise;
import play.libs.Json;

public class CombinationGroupManager extends ContentCollectionNodeManager {

    public CombinationGroupManager() {
        this.label = NodeType.COMBINATION_GROUP.toString();
    }

    // DELETE

    protected Promise<Boolean> empty(JsonNode properties, String location) {
        CombinationGroup group = new CombinationGroup(properties.get("uuid").asText());
        return super.empty(group, location);
    }

    @Override
    protected Promise<Boolean> disconnect(final JsonNode properties, List<JsonNode> stringsAndSlots,
            final String location) {
        Promise<Boolean> removed = Promise.pure(true);
        for (final JsonNode stringOrSlot : stringsAndSlots) {
            removed = removed.flatMap(new Function<Boolean, Promise<Boolean>>() {
                public Promise<Boolean> apply(Boolean removed) {
                    if (removed) {
                        String uuid = stringOrSlot.get("uuid").asText();
                        if (stringOrSlot.has("position")) {
                            Slot slot = new Slot(uuid);
                            return disconnect(properties, slot, location);
                        }
                        OutputString string = new OutputString(uuid);
                        return disconnect(properties, string, location);
                    }
                    return Promise.pure(false);
                }
            });
        }
        return removed;
    }

    // Connections to other nodes

    @Override
    protected Promise<Boolean> connect(JsonNode group, JsonNode stringOrSlot, String location) {
        if (stringOrSlot.has("position")) {
            Slot slot = new Slot(stringOrSlot.get("uuid").asText(), stringOrSlot.get("position").asInt());
            return connect(group, slot, location);
        }
        OutputString string = new OutputString(stringOrSlot.get("uuid").asText(),
                stringOrSlot.get("content").asText());
        return connect(group, string, location);
    }

    private Promise<Boolean> connect(final JsonNode group, final Slot slot, final String location) {
        Promise<Boolean> created = Slot.nodes.create(slot.getProperties(), location);
        Promise<Boolean> connected = created.flatMap(new Function<Boolean, Promise<Boolean>>() {
            public Promise<Boolean> apply(Boolean created) {
                if (created) {
                    CombinationGroup g = new CombinationGroup(group.get("uuid").asText());
                    return Has.relationships.create(g, slot, location);
                }
                return Promise.pure(false);
            }
        });
        return connected;
    }

    private Promise<Boolean> connect(final JsonNode group, final OutputString string, final String location) {
        Promise<Boolean> exists = OutputString.nodes.create(string.getProperties(), location);
        Promise<Boolean> connected = exists.flatMap(new Function<Boolean, Promise<Boolean>>() {
            public Promise<Boolean> apply(Boolean exists) {
                if (exists) {
                    final CombinationGroup g = new CombinationGroup(group.get("uuid").asText());
                    Promise<Boolean> connected = Has.relationships.exists(g, string);
                    return connected.flatMap(new Function<Boolean, Promise<Boolean>>() {
                        public Promise<Boolean> apply(Boolean connected) {
                            if (connected) {
                                return Promise.pure(false);
                            }
                            return Has.relationships.create(g, string, location);
                        }
                    });

                }
                return Promise.pure(false);
            }
        });
        return connected;
    }

    @Override
    protected Promise<Boolean> disconnect(JsonNode group, JsonNode stringOrSlot, String location) {
        String nodeType = "";
        if (stringOrSlot.has("nodeType")) {
            nodeType = stringOrSlot.get("nodeType").asText();
        }
        if (nodeType.equals("slot")) {
            Slot slot = new Slot(stringOrSlot.get("uuid").asText());
            return disconnect(group, slot, location);
        }
        OutputString string = new OutputString(stringOrSlot.get("uuid").asText());
        return disconnect(group, string, location);
    }

    private Promise<Boolean> disconnect(JsonNode group, final Slot slot, final String location) {
        CombinationGroup g = new CombinationGroup(group.get("uuid").asText());
        // 1. Disconnect group from slot
        Promise<Boolean> removed = Has.relationships.delete(g, slot, location);
        // 2. Delete slot
        removed = removed.flatMap(new Function<Boolean, Promise<Boolean>>() {
            public Promise<Boolean> apply(Boolean removed) {
                if (removed) {
                    return Slot.nodes.delete(slot.getProperties(), location);
                }
                return Promise.pure(false);
            }
        });
        return removed;
    }

    private Promise<Boolean> disconnect(JsonNode group, final OutputString string, String location) {
        CombinationGroup g = new CombinationGroup(group.get("uuid").asText());
        Promise<Boolean> disconnected = Has.relationships.delete(g, string, location);
        disconnected.onRedeem(new Callback<Boolean>() {
            public void invoke(Boolean disconnected) {
                if (disconnected) {
                    OutputString.nodes.delete(string.getProperties());
                }
            }
        });
        return disconnected;
    }

    // Custom functionality

    protected Promise<JsonNode> toJSON(final JsonNode properties) {
        CombinationGroup group = new CombinationGroup(properties.get("uuid").asText());
        Promise<List<JsonNode>> stringsAndSlots = Has.relationships.endNodes(group);
        Promise<JsonNode> json = stringsAndSlots.flatMap(new Function<List<JsonNode>, Promise<JsonNode>>() {
            public Promise<JsonNode> apply(List<JsonNode> stringsAndSlots) {
                final List<JsonNode> stringNodes = new ArrayList<JsonNode>();
                List<Promise<? extends JsonNode>> slots = new ArrayList<Promise<? extends JsonNode>>();
                for (JsonNode stringOrSlot : stringsAndSlots) {
                    if (stringOrSlot.has("position")) {
                        Promise<JsonNode> slot = Slot.nodes.toJSON(stringOrSlot);
                        slots.add(slot);
                    } else {
                        JsonNode string = OutputString.nodes.toJSON(stringOrSlot);
                        stringNodes.add(string);
                    }
                }
                Promise<List<JsonNode>> slotNodes = Promise.sequence(slots);
                Promise<JsonNode> json = slotNodes.map(new Function<List<JsonNode>, JsonNode>() {
                    public JsonNode apply(List<JsonNode> slotNodes) {
                        ArrayNode strings = JsonNodeFactory.instance.arrayNode();
                        strings.addAll(stringNodes);
                        ((ObjectNode) properties).put("outputStrings", strings);
                        ArrayNode slots = JsonNodeFactory.instance.arrayNode();
                        slots.addAll(slotNodes);
                        ObjectNode partsTable = Json.newObject();
                        partsTable.put("slots", slots);
                        ((ObjectNode) properties).put("partsTable", partsTable);
                        return properties;
                    }
                });
                return json;
            }
        });
        return json;
    }

    protected Promise<List<String>> find(JsonNode properties, final List<String> strings) {
        // 1. Get parts by slots
        Promise<List<List<String>>> stringsBySlots = getStringsBySlots(properties);
        // 2. Combine
        Promise<List<String>> fullStrings = stringsBySlots.map(new Function<List<List<String>>, List<String>>() {
            public List<String> apply(List<List<String>> stringsBySlots) {
                return cartesianProduct(stringsBySlots);
            }
        });
        // 3. Check for search strings
        Promise<List<String>> stringsNotFound = fullStrings.map(new Function<List<String>, List<String>>() {
            public List<String> apply(List<String> fullStrings) {
                List<String> stringsNotFound = new ArrayList<String>();
                for (String string : strings) {
                    boolean found = false;
                    for (String fullString : fullStrings) {
                        if (fullString.toLowerCase().contains(string.toLowerCase())) {
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        stringsNotFound.add(string);
                    }
                }
                return stringsNotFound;
            }
        });
        return stringsNotFound;
    }

    private Promise<List<List<String>>> getStringsBySlots(JsonNode properties) {
        Promise<List<JsonNode>> slots = slots(properties);
        Promise<List<List<JsonNode>>> partsBySlots = slots
                .flatMap(new Function<List<JsonNode>, Promise<List<List<JsonNode>>>>() {
                    public Promise<List<List<JsonNode>>> apply(List<JsonNode> slots) {
                        Collections.sort(slots, new Comparator<JsonNode>() {
                            public int compare(JsonNode s1, JsonNode s2) {
                                Integer pos1 = s1.get("position").asInt();
                                Integer pos2 = s2.get("position").asInt();
                                return pos1.compareTo(pos2);
                            }
                        });
                        List<Promise<? extends List<JsonNode>>> partsBySlots = new ArrayList<Promise<? extends List<JsonNode>>>();
                        for (JsonNode slot : slots) {
                            partsBySlots.add(Slot.nodes.parts(slot));
                        }
                        return Promise.sequence(partsBySlots);
                    }
                });
        Promise<List<List<String>>> stringsBySlots = partsBySlots
                .map(new Function<List<List<JsonNode>>, List<List<String>>>() {
                    public List<List<String>> apply(List<List<JsonNode>> partsBySlots) {
                        List<List<String>> stringsBySlots = new ArrayList<List<String>>();
                        for (List<JsonNode> partsBySlot : partsBySlots) {
                            List<String> stringsBySlot = new ArrayList<String>();
                            for (JsonNode part : partsBySlot) {
                                stringsBySlot.add(part.get("content").asText());
                            }
                            stringsBySlots.add(stringsBySlot);
                        }
                        return stringsBySlots;
                    }
                });
        return stringsBySlots;
    }

    private Promise<List<JsonNode>> slots(JsonNode properties) {
        CombinationGroup group = new CombinationGroup(properties.get("uuid").asText());
        return Has.relationships.endNodesByLabel(group, "Slot");
    }

    private List<String> cartesianProduct(List<List<String>> stringsBySlots) {
        if (stringsBySlots.isEmpty()) {
            return new ArrayList<String>();
        } else if (stringsBySlots.size() == 1) {
            return stringsBySlots.get(0);
        } else if (stringsBySlots.size() == 2) {
            return this.combineSlots(stringsBySlots.get(0), stringsBySlots.get(1));
        } else {
            List<String> intermediateResult = this.combineSlots(stringsBySlots.get(0), stringsBySlots.get(1));
            List<List<String>> remainingSlots = stringsBySlots.subList(2, stringsBySlots.size());
            remainingSlots.add(0, intermediateResult);
            return this.cartesianProduct(remainingSlots);
        }
    }

    private List<String> combineSlots(List<String> slot1, List<String> slot2) {
        if (slot1.isEmpty() && slot2.isEmpty()) {
            return new ArrayList<String>();
        }
        return this.combineSlots(slot1, slot2, new ArrayList<String>());
    }

    private List<String> combineSlots(List<String> slot1, List<String> slot2, List<String> result) {
        if (slot1.isEmpty()) {
            return result;
        }
        List<String> intermediateResult = this.combineStrings(slot1.get(0), slot2);
        result.addAll(intermediateResult);
        return this.combineSlots(slot1.subList(1, slot1.size()), slot2, result);
    }

    private List<String> combineStrings(String string, List<String> slot) {
        if (slot.isEmpty()) {
            List<String> result = new ArrayList<String>();
            result.add(string);
            return result;
        }
        return this.combineStrings(string, slot, new ArrayList<String>());
    }

    private List<String> combineStrings(String string, List<String> slot, List<String> result) {
        if (slot.isEmpty()) {
            return result;
        }
        String combinedString = string + " " + slot.get(0);
        result.add(combinedString);
        return this.combineStrings(string, slot.subList(1, slot.size()), result);
    }

}