cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.DefaultSystemGraph.java Source code

Java tutorial

Introduction

Here is the source code for cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.DefaultSystemGraph.java

Source

/**
 * Copyright Vclav Brodec 2014.
 * 
 * This file is part of Botn?ek.
 * 
 * Botn?ek is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Botn?ek 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Botn?ek.  If not, see <http://www.gnu.org/licenses/>.
 */
package cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Map;
import java.util.Set;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;

import cz.cuni.mff.ms.brodecva.botnicek.ide.aiml.types.NormalWord;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.arcs.model.Arc;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.arcs.model.RecurentArc;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.networks.model.Network;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.nodes.model.EnterNode;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.nodes.model.IsolatedNode;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.nodes.model.Node;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.nodes.model.RealignmentProcessor;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.updates.DefaultUpdateBuilderFactory;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.updates.Update;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.updates.UpdateBuilder;
import cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.updates.UpdateBuilderFactory;
import cz.cuni.mff.ms.brodecva.botnicek.ide.utils.concepts.Callback;
import cz.cuni.mff.ms.brodecva.botnicek.ide.utils.concepts.Function;
import cz.cuni.mff.ms.brodecva.botnicek.ide.utils.data.Presence;
import cz.cuni.mff.ms.brodecva.botnicek.ide.utils.data.graphs.DefaultLabeledDirectedGraph;
import cz.cuni.mff.ms.brodecva.botnicek.ide.utils.data.graphs.Direction;
import cz.cuni.mff.ms.brodecva.botnicek.ide.utils.data.graphs.LabeledDirectedGraph;
import cz.cuni.mff.ms.brodecva.botnicek.ide.utils.resources.ExceptionLocalizer;

/**
 * Implementace {@link SystemGraph}.
 * 
 * @author Vclav Brodec
 * @version 1.0
 */
public final class DefaultSystemGraph implements SystemGraph, Serializable {

    private static final long serialVersionUID = 1L;

    private static void addArcRemovalUpdates(final UpdateBuilder updateBuilder, final Arc parameter) {
        if (parameter instanceof RecurentArc) {
            final RecurentArc reference = (RecurentArc) parameter;

            updateBuilder.addRemovedReference(reference);
        }

        updateBuilder.addRemovedEdge(parameter);
    }

    private static void addRealignmentUpdates(final UpdateBuilder updateBuilder,
            final RealignmentProcessor processor, final Node input, final Node removed,
            final Map<EnterNode, Set<RecurentArc>> references, final Set<EnterNode> initials) {
        final Node realigned = processor.realign(input);
        if (realigned.equals(input)) {
            return;
        }

        checkForDependingArcs(removed, references, input);

        if (initials.contains(input)) {
            updateBuilder.addRemovedInitial((EnterNode) input);
        }

        if (realigned instanceof EnterNode) {
            updateBuilder.addNewInitial((EnterNode) realigned);
        }

        updateBuilder.addSwitched(input, realigned);
    }

    /**
     * Vytvo graf.
     * 
     * @return przdn graf
     */
    public static DefaultSystemGraph create() {
        return of(DefaultLabeledDirectedGraph.<Node, NormalWord, Arc, NormalWord>create(),
                DefaultUpdateBuilderFactory.create());
    }

    private static Set<EnterNode> getInitialsCopy(final Set<? extends EnterNode> initialNodes) {
        return ImmutableSet.copyOf(initialNodes);
    }

    private static Map<EnterNode, Set<RecurentArc>> getReferencesCopy(
            final Map<? extends EnterNode, ? extends Set<? extends RecurentArc>> references) {
        final ImmutableMap.Builder<EnterNode, Set<RecurentArc>> copyBuilder = ImmutableMap.builder();

        for (final Map.Entry<? extends EnterNode, ? extends Set<? extends RecurentArc>> entry : references
                .entrySet()) {
            final EnterNode key = entry.getKey();
            Preconditions.checkNotNull(key);

            final Set<? extends RecurentArc> value = entry.getValue();
            Preconditions.checkNotNull(value);

            copyBuilder.put(key, ImmutableSet.copyOf(value));
        }

        return copyBuilder.build();
    }

    private static void checkForDependingArcs(final Arc removed, final Map<EnterNode, Set<RecurentArc>> references,
            final Node from, final Node newFrom) throws IllegalArgumentException {
        final Set<RecurentArc> referring = references.get(from);

        if (Presence.isAbsent(referring) || newFrom.equals(from)) {
            return;
        }

        final Set<RecurentArc> referringWithoutRemoved = Sets.difference(referring, ImmutableSet.of(removed));

        final boolean refersOnlyToItself = referringWithoutRemoved.isEmpty();
        if (refersOnlyToItself) {
            return;
        }

        final Network fromNetwork = from.getNetwork();
        final RecurentArc firstReferring = referringWithoutRemoved.iterator().next();
        final Network firstReferringNetwork = firstReferring.getNetwork();

        throw new IllegalArgumentException(ExceptionLocalizer.print("ArcRemovalForbidden", from.getName(),
                removed.getName(), fromNetwork.getName().getText(), firstReferring.getName(),
                firstReferringNetwork.getName().getText()));
    }

    private static void checkForDependingArcs(final Node removed, final Map<EnterNode, Set<RecurentArc>> references,
            final Node input) {
        final Set<RecurentArc> referring = references.get(input);
        if (Presence.isAbsent(referring)) {
            return;
        }

        final Network networkOfRemoved = removed.getNetwork();

        final RecurentArc firstReferring = referring.iterator().next();
        final Network networkOfFirst = firstReferring.getNetwork();

        throw new IllegalArgumentException(ExceptionLocalizer.print("NodeRemovalForbidden", input.getName(),
                removed.getName(), networkOfRemoved.getName().getText(), firstReferring.getName(),
                networkOfFirst.getName().getText()));
    }

    /**
     * Dekoruje zkladn graf.
     * 
     * @param baseGraph
     *            zkladn graf
     * @param updateBuilderFactory
     *            tovrna na stavitele aktualizac
     * 
     * @return obohacen zkladn graf
     */
    public static DefaultSystemGraph of(final LabeledDirectedGraph<Node, NormalWord, Arc, NormalWord> baseGraph,
            final UpdateBuilderFactory updateBuilderFactory) {
        Preconditions.checkNotNull(baseGraph);
        Preconditions.checkNotNull(updateBuilderFactory);

        return new DefaultSystemGraph(baseGraph, updateBuilderFactory);
    }

    private final LabeledDirectedGraph<Node, NormalWord, Arc, NormalWord> baseGraph;

    private final UpdateBuilderFactory updateBuilderFactory;

    private DefaultSystemGraph(final LabeledDirectedGraph<Node, NormalWord, Arc, NormalWord> baseGraph,
            final UpdateBuilderFactory updateBuilderFactory) {
        this.baseGraph = baseGraph;
        this.updateBuilderFactory = updateBuilderFactory;
    }

    private void abortOnDependingArcs(final Arc removed, final Map<EnterNode, Set<RecurentArc>> references,
            final Node from, final Node newFrom, final Node to) throws IllegalArgumentException {
        try {
            checkForDependingArcs(removed, references, from, newFrom);
        } catch (final IllegalArgumentException e) {
            this.baseGraph.add(removed, removed.getName(), from, to);

            throw e;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.SystemGraph#
     * add(cz.cuni.mff.ms.brodecva.botnicek.ide.design.nodes.model.IsolatedNode)
     */
    @Override
    public void add(final IsolatedNode node) {
        Preconditions.checkNotNull(node);

        this.baseGraph.add(node, node.getName());
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.SystemGraph#
     * addAndRealign(cz.cuni.mff.ms.brodecva.botnicek.ide.design.arcs.model.Arc,
     * cz.cuni.mff.ms.brodecva.botnicek.ide.design.nodes.model.Node,
     * cz.cuni.mff.ms.brodecva.botnicek.ide.design.nodes.model.Node,
     * cz.cuni.mff.
     * ms.brodecva.botnicek.ide.design.nodes.model.RealignmentProcessor,
     * java.util.Set)
     */
    @Override
    public Update addAndRealign(final Arc added, final Node from, final Node to,
            final RealignmentProcessor processor, final Set<? extends EnterNode> initials) {
        Preconditions.checkNotNull(added);
        Preconditions.checkNotNull(from);
        Preconditions.checkNotNull(to);
        Preconditions.checkNotNull(processor);
        Preconditions.checkNotNull(initials);

        final Set<EnterNode> initialsCopy = getInitialsCopy(initials);

        this.baseGraph.add(added, added.getName(), from, to);

        final Node newFrom = processor.realign(from);
        final Node newTo = processor.realign(to);

        replaceVertex(from, newFrom);
        replaceVertex(to, newTo);

        final UpdateBuilder updateBuilder = this.updateBuilderFactory.produce();

        if (!from.equals(newFrom) && (newFrom instanceof EnterNode)) {
            updateBuilder.addNewInitial((EnterNode) newFrom);
        }

        if (!to.equals(newTo) && initialsCopy.contains(to)) {
            updateBuilder.addRemovedInitial((EnterNode) to);
        }

        updateBuilder.addSwitched(from, newFrom);
        updateBuilder.addSwitched(to, newTo);

        return updateBuilder.build();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.SystemGraph#
     * adjoins(cz.cuni.mff.ms.brodecva.botnicek.ide.design.nodes.model.Node,
     * cz.cuni.mff.ms.brodecva.botnicek.ide.design.nodes.model.Node,
     * cz.cuni.mff.ms.brodecva.botnicek.ide.utils.data.graphs.Direction)
     */
    @Override
    public boolean adjoins(final Node first, final Node second, final Direction direction) {
        Preconditions.checkNotNull(first);
        Preconditions.checkNotNull(second);
        Preconditions.checkNotNull(direction);

        final Set<Arc> connections = connections(first, direction);

        for (final Arc connection : connections) {
            if (connection.isAttached(second, direction)) {
                return true;
            }
        }

        return false;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.SystemGraph#
     * attached(cz.cuni.mff.ms.brodecva.botnicek.ide.design.arcs.model.Arc,
     * cz.cuni.mff.ms.brodecva.botnicek.ide.utils.data.graphs.Direction)
     */
    @Override
    public Node attached(final Arc arc, final Direction direction) {
        Preconditions.checkNotNull(arc);
        Preconditions.checkNotNull(direction);

        switch (direction) {
        case IN:
            return this.baseGraph.from(arc);
        case OUT:
            return this.baseGraph.to(arc);
        default:
            throw new AssertionError();
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.SystemGraph#
     * connections(cz.cuni.mff.ms.brodecva.botnicek.ide.design.nodes.model.Node,
     * cz.cuni.mff.ms.brodecva.botnicek.ide.utils.data.graphs.Direction)
     */
    @Override
    public Set<Arc> connections(final Node vertex, final Direction direction) {
        Preconditions.checkNotNull(vertex);
        Preconditions.checkNotNull(direction);

        switch (direction) {
        case IN:
            return this.baseGraph.ins(vertex);
        case OUT:
            return this.baseGraph.outs(vertex);
        default:
            throw new AssertionError();
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cz.cuni.mff.ms.brodecva.botnicek.ide.utils.data.graphs.DirectedGraph#
     * containsEdge(java.lang.Object)
     */
    @Override
    public boolean containsEdge(final Arc edge) {
        Preconditions.checkNotNull(edge);

        return this.baseGraph.containsEdge(edge);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cz.cuni.mff.ms.brodecva.botnicek.ide.utils.data.graphs.DirectedGraph#
     * containsVertex(java.lang.Object)
     */
    @Override
    public boolean containsVertex(final Node vertex) {
        Preconditions.checkNotNull(vertex);

        return this.baseGraph.containsVertex(vertex);
    }

    private Update createArcRemovalUpdate(final Arc removed, final Set<EnterNode> initials, final Node from,
            final Node newFrom, final Node to, final Node newTo) {
        final UpdateBuilder updateBuilder = this.updateBuilderFactory.produce();

        updateBuilder.addSwitched(from, newFrom);
        updateBuilder.addSwitched(to, newTo);

        if (removed instanceof RecurentArc) {
            final RecurentArc reference = (RecurentArc) removed;

            updateBuilder.addRemovedReference(reference);
        }
        if (!from.equals(newFrom)) {
            if (initials.contains(from)) {
                updateBuilder.addRemovedInitial((EnterNode) from);
            }
        }
        if (!to.equals(newTo)) {
            if (newTo instanceof EnterNode) {
                updateBuilder.addNewInitial((EnterNode) newTo);
            }
        }

        return updateBuilder.build();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.SystemGraph#
     * getEdge(cz.cuni.mff.ms.brodecva.botnicek.ide.aiml.types.NormalWord)
     */
    @Override
    public Arc getEdge(final NormalWord name) {
        Preconditions.checkNotNull(name);

        return this.baseGraph.getEdge(name);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.SystemGraph#
     * getVertex(cz.cuni.mff.ms.brodecva.botnicek.ide.aiml.types.NormalWord)
     */
    @Override
    public Node getVertex(final NormalWord name) {
        Preconditions.checkNotNull(name);

        return this.baseGraph.getVertex(name);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.SystemGraph#
     * purge(java.util.Set)
     */
    @Override
    public void purge(final Set<? extends Node> purged) {
        Preconditions.checkNotNull(purged);

        final Set<Node> purgedCopy = ImmutableSet.copyOf(purged);
        for (final Node node : purgedCopy) {
            this.baseGraph.removeVertex(node);
        }
    }

    private void readObject(final ObjectInputStream objectInputStream) throws ClassNotFoundException, IOException {
        objectInputStream.defaultReadObject();

        Preconditions.checkNotNull(this.baseGraph);
        Preconditions.checkNotNull(this.updateBuilderFactory);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.SystemGraph#
     * removeAndRealign
     * (cz.cuni.mff.ms.brodecva.botnicek.ide.design.arcs.model.Arc,
     * cz.cuni.mff.ms
     * .brodecva.botnicek.ide.design.nodes.model.RealignmentProcessor,
     * java.util.Map, java.util.Set)
     */
    @Override
    public Update removeAndRealign(final Arc removed, final RealignmentProcessor processor,
            final Map<? extends EnterNode, ? extends Set<? extends RecurentArc>> references,
            final Set<? extends EnterNode> initials) throws IllegalArgumentException {
        Preconditions.checkNotNull(removed);
        Preconditions.checkNotNull(processor);
        Preconditions.checkNotNull(references);
        Preconditions.checkNotNull(initials);

        final Map<EnterNode, Set<RecurentArc>> referencesCopy = getReferencesCopy(references);
        final Set<EnterNode> initialsCopy = getInitialsCopy(initials);

        final Node from = removed.getFrom();
        final Node to = removed.getTo();

        this.baseGraph.removeEdge(removed);

        final Node newFrom = processor.realign(from);
        final Node newTo = processor.realign(to);

        abortOnDependingArcs(removed, referencesCopy, from, newFrom, to);

        replaceVertex(from, newFrom);
        replaceVertex(to, newTo);

        return createArcRemovalUpdate(removed, initialsCopy, from, newFrom, to, newTo);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cz.cuni.mff.ms.brodecva.botnicek.ide.design.system.model.SystemGraph#
     * removeAndRealign
     * (cz.cuni.mff.ms.brodecva.botnicek.ide.design.nodes.model.Node,
     * cz.cuni.mff
     * .ms.brodecva.botnicek.ide.design.nodes.model.RealignmentProcessor,
     * java.util.Map, java.util.Set)
     */
    @Override
    public Update removeAndRealign(final Node removed, final RealignmentProcessor processor,
            final Map<? extends EnterNode, ? extends Set<? extends RecurentArc>> references,
            final Set<? extends EnterNode> initialNodes) throws IllegalArgumentException {
        Preconditions.checkNotNull(removed);
        Preconditions.checkNotNull(references);
        Preconditions.checkNotNull(initialNodes);

        final Map<EnterNode, Set<RecurentArc>> referencesCopy = getReferencesCopy(references);
        final Set<EnterNode> initialsCopy = getInitialsCopy(initialNodes);

        final UpdateBuilder updateBuilder = this.updateBuilderFactory.produce();

        this.baseGraph.extractVertex(removed, new Function<Node, Node>() {
            @Override
            public Node apply(final Node input) {
                return processor.realign(input);
            }
        }, new Callback<Node>() {
            @Override
            public void call(final Node input) {
                addRealignmentUpdates(updateBuilder, processor, input, removed, referencesCopy, initialsCopy);
            }
        }, new Callback<Arc>() {
            @Override
            public void call(final Arc parameter) {
                addArcRemovalUpdates(updateBuilder, parameter);
            }
        });

        return updateBuilder.build();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cz.cuni.mff.ms.brodecva.botnicek.ide.utils.data.graphs.DirectedGraph#
     * replaceEdge(java.lang.Object, java.lang.Object)
     */
    @Override
    public void replaceEdge(final Arc old, final Arc fresh) {
        Preconditions.checkNotNull(fresh);
        Preconditions.checkNotNull(old);

        this.baseGraph.replaceEdge(old, fresh, fresh.getName());
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * cz.cuni.mff.ms.brodecva.botnicek.ide.utils.data.graphs.DirectedGraph#
     * replaceVertex(java.lang.Object, java.lang.Object)
     */
    @Override
    public void replaceVertex(final Node old, final Node fresh) {
        Preconditions.checkNotNull(fresh);
        Preconditions.checkNotNull(old);

        this.baseGraph.replaceVertex(old, fresh, fresh.getName());
    }

    private void writeObject(final ObjectOutputStream objectOutputStream) throws IOException {
        objectOutputStream.defaultWriteObject();
    }
}