com.github.aptd.simulation.elements.graph.network.local.CPlatform.java Source code

Java tutorial

Introduction

Here is the source code for com.github.aptd.simulation.elements.graph.network.local.CPlatform.java

Source

/*
 * @cond LICENSE
 * ######################################################################################
 * # LGPL License                                                                       #
 * #                                                                                    #
 * # This file is part of the Asimov - Agentbased Passenger Train Delay                 #
 * # This program is free software: you can redistribute it and/or modify               #
 * # it under the terms of the GNU Lesser 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 Lesser General Public License for more details.                                #
 * #                                                                                    #
 * # You should have received a copy of the GNU Lesser General Public License           #
 * # along with this program. If not, see http://www.gnu.org/licenses/                  #
 * ######################################################################################
 * @endcond
 */

package com.github.aptd.simulation.elements.graph.network.local;

import com.fasterxml.jackson.core.JsonGenerator;
import com.github.aptd.simulation.core.messaging.EMessageType;
import com.github.aptd.simulation.core.messaging.IMessage;
import com.github.aptd.simulation.core.messaging.local.CMessage;
import com.github.aptd.simulation.core.time.ITime;
import com.github.aptd.simulation.elements.IElement;
import com.github.aptd.simulation.elements.IStatefulElement;
import com.github.aptd.simulation.elements.graph.network.IPlatform;
import com.github.aptd.simulation.elements.passenger.IPassenger;
import com.github.aptd.simulation.elements.train.IDoor;
import com.github.aptd.simulation.elements.train.ITrain;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.lightjason.agentspeak.action.IAction;
import org.lightjason.agentspeak.configuration.IAgentConfiguration;
import org.lightjason.agentspeak.language.ILiteral;

import java.io.IOException;
import java.io.InputStream;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;

/**
 * platform class
 */
public final class CPlatform extends IStatefulElement<IPlatform<?>> implements IPlatform<IPlatform<?>> {

    /**
     * serial id
     */
    private static final long serialVersionUID = -7374587357204465585L;
    /**
     * literal functor
     */
    private static final String FUNCTOR = "platform";
    /**
     * ID of the station this platform belongs to
     */
    private final String m_stationid;
    /**
     * set of passengers at the platform (subscribers to notifcations of arriving trains)
     */
    private final Set<IPassenger<?>> m_passengers = Collections.synchronizedSet(new HashSet<>());
    /**
     * reference to the train currently standing at the platform
     */
    private ITrain<?> m_train;
    private final List<IDoor<?>> m_doors = Collections.synchronizedList(new LinkedList<>());

    /**
     * ctor
     *
     * @param p_configuration agent configuration
     * @param p_id ...
     * @param p_stationid ID of the station
     * @param p_time time reference
     */
    private CPlatform(final IAgentConfiguration<IPlatform<?>> p_configuration, final String p_id,
            final String p_stationid, final ITime p_time) {
        super(p_configuration, FUNCTOR, p_id, p_time);
        m_stationid = p_stationid;
    }

    @Override
    protected Instant determinenextstatechange() {
        // a platform has no processes going on
        return Instant.MAX;
    }

    @Override
    protected boolean updatestate() {
        if (m_input.isEmpty())
            return false;

        final List<IMessage> l_arrivingtrains = m_input.get(EMessageType.TRAIN_TO_PLATFORM_ARRIVING);
        final List<IMessage> l_departingtrains = m_input.get(EMessageType.TRAIN_TO_PLATFORM_DEPARTING);
        final List<IMessage> l_subscribingpassengers = m_input.get(EMessageType.PASSENGER_TO_PLATFORM_SUBSCRIBE);
        final List<IMessage> l_unsubscribingpassengers = m_input
                .get(EMessageType.PASSENGER_TO_PLATFORM_UNSUBSCRIBE);

        if (l_departingtrains.size() > 1)
            throw new RuntimeException(
                    m_id + " has multiple trains departing simultaneously at " + m_time.current());
        if (l_departingtrains.size() == 1) {
            if (m_train != l_departingtrains.get(0).sender())
                throw new RuntimeException(m_id + " has a train departing that's not there at " + m_time.current());
            m_passengers.stream().forEach(p -> output(
                    new CMessage(this, p.id(), EMessageType.PLATFORM_TO_PASSENGER_TRAINDEPARTED, m_train.id())));
            m_train = null;
            m_doors.clear();
        }

        l_subscribingpassengers.stream().forEach(msg -> {
            m_passengers.add((IPassenger) msg.sender());
            if (m_train != null)
                output(new CMessage(this, msg.sender().id(), EMessageType.PLATFORM_TO_PASSENGER_TRAINARRIVED,
                        m_train.id(), m_doors.toArray()));
        });
        l_unsubscribingpassengers.stream().forEach(msg -> m_passengers.remove(msg.sender()));

        if (l_arrivingtrains.size() > 1)
            throw new RuntimeException(
                    m_id + " has multiple trains arriving simultaneously at " + m_time.current());
        if (l_arrivingtrains.size() == 1) {
            if (m_train != null)
                throw new RuntimeException(
                        m_id + " has a second train arriving without the first departing at " + m_time.current());
            m_train = (ITrain) l_arrivingtrains.get(0).sender();
            Arrays.stream(l_arrivingtrains.get(0).content()).map(o -> (IDoor<?>) o)
                    .sorted(Comparator.comparing(IDoor::id)).forEachOrdered(m_doors::add);
            m_passengers.stream().forEach(p -> output(new CMessage(this, p.id(),
                    EMessageType.PLATFORM_TO_PASSENGER_TRAINARRIVED, m_train.id(), m_doors.toArray())));
        }
        return true;
    }

    @Override
    protected boolean updatecontinuous(final Duration p_elapsed) {
        // a platform has no continuous state
        return false;
    }

    @Override
    protected void writeState(final JsonGenerator p_generator) throws IOException {
        p_generator.writeStringField("train", m_train == null ? null : m_train.id());
        p_generator.writeArrayFieldStart("doors");
        for (final IDoor<?> l_door : m_doors)
            p_generator.writeString(l_door.id());
        p_generator.writeEndArray();
        p_generator.writeArrayFieldStart("passengers");
        for (final IPassenger<?> l_passenger : m_passengers)
            p_generator.writeString(l_passenger.id());
        p_generator.writeEndArray();
    }

    @Override
    protected Stream<ILiteral> individualliteral(final Stream<IElement<?>> p_object) {
        return Stream.of();
    }

    @Override
    public String stationid() {
        return m_stationid;
    }

    // ---------------------------------------------------------------------------------------------------------------------------------------------------------

    /**
     * generator
     */
    public static final class CGenerator extends IBaseGenerator<IPlatform<?>> {

        /**
         * ctor
         *
         * @param p_stream stream
         * @param p_actions action
         * @param p_time time reference
         * @throws Exception on any error
         */
        public CGenerator(final InputStream p_stream, final Set<IAction> p_actions, final ITime p_time)
                throws Exception {
            super(p_stream, p_actions, CPlatform.class, p_time);
        }

        @Override
        protected Pair<IPlatform<?>, Stream<String>> generate(final Object... p_data) {
            return new ImmutablePair<>(
                    new CPlatform(m_configuration, p_data[0].toString(), p_data[1].toString(), m_time),
                    Stream.of(FUNCTOR));
        }
    }

}