com.github.aptd.simulation.datamodel.CXMLReader.java Source code

Java tutorial

Introduction

Here is the source code for com.github.aptd.simulation.datamodel.CXMLReader.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.datamodel;

import com.github.aptd.simulation.core.experiment.IExperiment;
import com.github.aptd.simulation.core.experiment.local.CExperiment;
import com.github.aptd.simulation.core.messaging.local.CMessenger;
import com.github.aptd.simulation.core.statistic.IStatistic;
import com.github.aptd.simulation.core.time.ITime;
import com.github.aptd.simulation.core.time.local.CJumpTime;
import com.github.aptd.simulation.core.time.local.CStepTime;
import com.github.aptd.simulation.datamodel.xml.AgentRef;
import com.github.aptd.simulation.datamodel.xml.Asimov;
import com.github.aptd.simulation.datamodel.xml.Iagent;
import com.github.aptd.simulation.datamodel.xml.Iagents;
import com.github.aptd.simulation.datamodel.xml.Network;
import com.github.aptd.simulation.datamodel.xml.PlatformType;
import com.github.aptd.simulation.datamodel.xml.StationLayout;
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.graph.network.IStation;
import com.github.aptd.simulation.elements.passenger.IPassenger;
import com.github.aptd.simulation.elements.passenger.IPassengerSource;
import com.github.aptd.simulation.elements.train.CTrain;
import com.github.aptd.simulation.elements.train.IDoor;
import com.github.aptd.simulation.elements.train.ITrain;
import com.github.aptd.simulation.error.CNotFoundException;
import com.github.aptd.simulation.error.CRuntimeException;
import com.github.aptd.simulation.error.CSemanticException;
import com.github.aptd.simulation.factory.IFactory;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.math3.distribution.RealDistribution;
import org.apache.commons.math3.distribution.UniformRealDistribution;
import org.lightjason.agentspeak.action.IAction;
import org.lightjason.agentspeak.common.CCommon;
import org.railml.schemas._2016.EArrivalDepartureTimes;
import org.railml.schemas._2016.EFormation;
import org.railml.schemas._2016.EOcp;
import org.railml.schemas._2016.EOcpTT;
import org.railml.schemas._2016.ETrack;
import org.railml.schemas._2016.ETrainPart;
import org.railml.schemas._2016.EVehicle;
import org.railml.schemas._2016.TDoors;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import java.io.FileInputStream;
import java.math.BigInteger;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoField;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * data-model XML reader
 *
 * @bug incomplete
 */
public final class CXMLReader implements IDataModel {
    private static final QName PLATFORM_REF_ATTRIBUTE = new QName(
            "https://raw.githubusercontent.com/APTD/Simulation/master/src/main/xsd", "platformRef");
    /**
     * jaxb context
     */
    private final JAXBContext m_context;

    /**
     * ctor
     */
    public CXMLReader() {
        try {
            m_context = JAXBContext.newInstance(Asimov.class, AgentRef.class, StationLayout.class);
        } catch (final JAXBException l_exception) {
            throw new CRuntimeException(l_exception);
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public final IExperiment get(final IFactory p_factory, final String p_datamodel, final long p_simulationsteps,
            final boolean p_parallel, final String p_timemodel,
            final Supplier<RealDistribution> p_platformchangedurationdistributionsupplier,
            final int p_numberofpassengers, final double p_lightbarrierminfreetime, final double p_delayseconds) {
        try (final FileInputStream l_stream = new FileInputStream(p_datamodel)) {
            final Asimov l_model = (Asimov) m_context.createUnmarshaller().unmarshal(l_stream);

            // time definition

            final Instant l_starttime = ZonedDateTime.now(ZoneId.systemDefault())
                    .with(ChronoField.CLOCK_HOUR_OF_DAY, 8).with(ChronoField.MINUTE_OF_HOUR, 45)
                    .with(ChronoField.SECOND_OF_MINUTE, 0).with(ChronoField.NANO_OF_SECOND, 0)
                    .with(ChronoField.DAY_OF_MONTH, 3).with(ChronoField.MONTH_OF_YEAR, 10)
                    .with(ChronoField.YEAR, 2017).toInstant();

            final ITime l_time = "jump".equals(p_timemodel) ? new CJumpTime(l_starttime, p_simulationsteps)
                    : new CStepTime(l_starttime, Duration.ofSeconds(1), p_simulationsteps);

            final CMessenger l_messenger = new CMessenger();

            final Set<IAction> l_actionsfrompackage = CCommon.actionsFromPackage().collect(Collectors.toSet());

            // asl agent definition
            final Map<String, String> l_agentdefs = agents(l_model.getAi());

            // macro (train-network) and microscopic model
            final Map<String, IPlatform<?>> l_platform = platform(l_model.getNetwork(), l_agentdefs, p_factory,
                    l_time);
            final Map<String, IStation<?>> l_station = station(l_model.getNetwork(), l_agentdefs, p_factory, l_time,
                    l_platform);
            final Pair<Map<String, ITrain<?>>, Map<String, IDoor<?>>> l_train = train(l_model.getNetwork(),
                    l_agentdefs, p_factory, l_time, p_lightbarrierminfreetime);

            final Map<String, IElement<?>> l_agents = new HashMap<>();
            l_agents.putAll(l_platform);
            l_agents.putAll(l_station);
            l_agents.putAll(l_train.getLeft());
            l_agents.putAll(l_train.getRight());

            final CExperiment l_experiment = new CExperiment(p_simulationsteps, p_parallel, IStatistic.EMPTY,
                    l_agents, l_time, l_messenger);

            // @todo create passengersources and their passenger generators according to scenario definition

            final IElement.IGenerator<IPassenger<?>> l_passengergenerator = passengergenerator(p_factory,
                    "+!activate <-\n    state/transition\n.", l_actionsfrompackage, l_time);

            l_experiment.addAgent("passengersource_test",
                    passengersourcegenerator(p_factory, "+!activate <-\n    state/transition\n.",
                            l_actionsfrompackage, l_time).generatesingle(new UniformRealDistribution(0.0, 1.0),
                                    l_time.current().toEpochMilli(), p_numberofpassengers, l_passengergenerator,
                                    l_experiment, l_agents.get("toy-node-1"),
                                    p_platformchangedurationdistributionsupplier.get()));

            l_messenger.experiment(l_experiment);

            // experiment (executable model)
            return l_experiment;

        } catch (final Exception l_execption) {
            throw new CRuntimeException(l_execption);
        }
    }

    /**
     * creates the agent structure
     *
     * @param p_ai AI component
     * @return unmodifyable agent map
     */
    private static Map<String, String> agents(final Iagents p_ai) {
        return Collections.<String, String>unmodifiableMap(p_ai.getAgents().getInstance().getAgent()
                .parallelStream().collect(Collectors.toMap(Iagent::getId, i -> i.getConfiguration().getAsl())));
    }

    /**
     * create the station list
     *
     * @param p_network network component
     * @param p_agents map with agent asl scripts
     * @param p_factory factory
     * @param p_time time reference
     * @param p_platforms map with already generated platforms
     * @return unmodifyable map with stations
     */
    private static Map<String, IStation<?>> station(final Network p_network, final Map<String, String> p_agents,
            final IFactory p_factory, final ITime p_time, final Map<String, IPlatform<?>> p_platforms) {
        final Map<String, IElement.IGenerator<IStation<?>>> l_generators = new ConcurrentHashMap<>();
        final Set<IAction> l_actions = CCommon.actionsFromPackage().collect(Collectors.toSet());
        final ListMultimap<String, IPlatform<?>> l_platformbystationid = Multimaps.index(p_platforms.values(),
                IPlatform::stationid);
        return Collections.<String, IStation<?>>unmodifiableMap(p_network
                .getInfrastructure().getOperationControlPoints().getOcp().parallelStream().filter(
                        i -> hasagentname(i.getAny()))
                .map(i -> agentname(i, i.getAny()))
                .map(i -> l_generators
                        .computeIfAbsent(i.getRight(),
                                a -> stationgenerator(p_factory, p_agents.get(i.getRight()), l_actions, p_time))
                        .generatesingle(i.getLeft().getId(), i.getLeft().getGeoCoord().getCoord().get(0),
                                i.getLeft().getGeoCoord().getCoord().get(1),
                                l_platformbystationid.get(i.getLeft().getId())))
                .collect(Collectors.toMap(IElement::id, i -> i)));
    }

    /**
     * creates a station agent generator
     *
     * @param p_factory factory
     * @param p_asl asl script as String
     * @param p_actions actions
     * @return station generator
     */
    private static IElement.IGenerator<IStation<?>> stationgenerator(final IFactory p_factory, final String p_asl,
            final Set<IAction> p_actions, final ITime p_time) {
        try {
            return p_factory.station(IOUtils.toInputStream(p_asl, "UTF-8"), p_actions, p_time);
        } catch (final Exception l_exception) {
            throw new CSemanticException(l_exception);
        }
    }

    /**
     * create the platforms of all stations
     *
     * @param p_network network component
     * @param p_agents map with agent asl scripts
     * @param p_factory factory
     * @param p_time time reference
     * @return unmodifyable map with platforms
     */
    private static Map<String, IPlatform<?>> platform(final Network p_network, final Map<String, String> p_agents,
            final IFactory p_factory, final ITime p_time) {
        final Map<String, IElement.IGenerator<IPlatform<?>>> l_generators = new ConcurrentHashMap<>();
        final Set<IAction> l_actions = CCommon.actionsFromPackage().collect(Collectors.toSet());
        return Collections.<String, IPlatform<?>>unmodifiableMap(p_network.getInfrastructure()
                .getOperationControlPoints().getOcp().parallelStream()
                .flatMap(ocp -> ocp.getAny().stream().filter(a -> a instanceof StationLayout).findAny()
                        .map(a -> ((StationLayout) a).getPlatform().stream()
                                .map(p -> new ImmutablePair<EOcp, PlatformType>(ocp, p)))
                        .orElse(Stream.of()))
                .filter(i -> i.getRight().getAgentRef() != null)
                .map(i -> l_generators
                        .computeIfAbsent(i.getRight().getAgentRef().getAgent(),
                                a -> platformgenerator(p_factory,
                                        p_agents.get(i.getRight().getAgentRef().getAgent()), l_actions, p_time))
                        .generatesingle(i.getLeft().getId() + "-track-" + i.getRight().getNumber(),
                                i.getLeft().getId()))
                .collect(Collectors.toMap(IElement::id, i -> i)));
    }

    /**
     * creates a platform agent generator
     *
     * @param p_factory factory
     * @param p_asl asl script as String
     * @param p_actions actions
     * @return platform generator
     */
    private static IElement.IGenerator<IPlatform<?>> platformgenerator(final IFactory p_factory, final String p_asl,
            final Set<IAction> p_actions, final ITime p_time) {
        try {
            return p_factory.platform(IOUtils.toInputStream(p_asl, "UTF-8"), p_actions, p_time);
        } catch (final Exception l_exception) {
            throw new CSemanticException(l_exception);
        }
    }

    /**
     * create the train list
     *
     * @param p_network network component
     * @param p_agents map with agent asl scripts
     * @param p_factory factory
     * @return unmodifiable map with trains
     */
    private static Pair<Map<String, ITrain<?>>, Map<String, IDoor<?>>> train(final Network p_network,
            final Map<String, String> p_agents, final IFactory p_factory, final ITime p_time,
            final double p_minfreetimetoclose) {
        final String l_dooragent = IStatefulElement.getDefaultAsl("door");
        final Map<String, IElement.IGenerator<ITrain<?>>> l_generators = new ConcurrentHashMap<>();
        final Set<IAction> l_actions = CCommon.actionsFromPackage().collect(Collectors.toSet());
        final IElement.IGenerator<IDoor<?>> l_doorgenerator = doorgenerator(p_factory, l_dooragent, l_actions,
                p_time);
        final Map<String, AtomicLong> l_doorcount = Collections.synchronizedMap(new HashMap<>());
        final Map<String, IDoor<?>> l_doors = Collections.synchronizedMap(new HashMap<>());
        return new ImmutablePair<>(
                Collections.<String, ITrain<?>>unmodifiableMap(
                        p_network.getTimetable().getTrains().getTrain().parallelStream()
                                .filter(i -> hasagentname(i.getAny3())).map(i -> agentname(i, i.getAny3()))
                                .map(i -> l_generators
                                        .computeIfAbsent(i.getRight(),
                                                a -> traingenerator(p_factory, p_agents.get(i.getRight()),
                                                        l_actions, p_time))
                                        .generatesingle(i.getLeft().getId(),
                                                i.getLeft().getTrainPartSequence().stream().flatMap(ref -> {
                                                    // @todo support multiple train parts
                                                    final EOcpTT[] l_tts = ((ETrainPart) ref.getTrainPartRef()
                                                            .get(0).getRef()).getOcpsTT().getOcpTT()
                                                                    .toArray(new EOcpTT[0]);
                                                    final CTrain.CTimetableEntry[] l_entries = new CTrain.CTimetableEntry[l_tts.length];
                                                    for (int j = 0; j < l_tts.length; j++) {
                                                        final EArrivalDepartureTimes l_times = l_tts[j].getTimes()
                                                                .stream()
                                                                .filter(t -> t.getScope()
                                                                        .equalsIgnoreCase("published"))
                                                                .findAny().orElseThrow(() -> new CSemanticException(
                                                                        "missing published times"));
                                                        l_entries[j] = new CTrain.CTimetableEntry(
                                                                j < 1 ? 0.0
                                                                        : ((ETrack) l_tts[j - 1].getSectionTT()
                                                                                .getTrackRef().get(0).getRef())
                                                                                        .getTrackTopology()
                                                                                        .getTrackEnd().getPos()
                                                                                        .doubleValue(),
                                                                ((EOcp) l_tts[j].getOcpRef()).getId(),
                                                                l_tts[j].getStopDescription().getOtherAttributes()
                                                                        .getOrDefault(PLATFORM_REF_ATTRIBUTE, null),
                                                                l_times.getArrival() == null ? null
                                                                        : l_times.getArrival().toGregorianCalendar()
                                                                                .toZonedDateTime()
                                                                                .with(LocalDate.from(p_time
                                                                                        .current()
                                                                                        .atZone(ZoneId
                                                                                                .systemDefault())))
                                                                                .toInstant(),
                                                                l_times.getDeparture() == null ? null
                                                                        : l_times.getDeparture()
                                                                                .toGregorianCalendar()
                                                                                .toZonedDateTime()
                                                                                .with(LocalDate.from(p_time
                                                                                        .current()
                                                                                        .atZone(ZoneId
                                                                                                .systemDefault())))
                                                                                .toInstant());
                                                    }
                                                    return Arrays.stream(l_entries);
                                                }), i.getLeft().getTrainPartSequence().stream()
                                                        // @todo support multiple train parts
                                                        .map(s -> (ETrainPart) s.getTrainPartRef().get(0).getRef())
                                                        .map(p -> (EFormation) p.getFormationTT().getFormationRef())
                                                        .flatMap(f -> f.getTrainOrder().getVehicleRef().stream())
                                                        .map(r -> new ImmutablePair<BigInteger, TDoors>(
                                                                r.getVehicleCount(),
                                                                ((EVehicle) r.getVehicleRef()).getWagon()
                                                                        .getPassenger().getDoors()))
                                                        .flatMap(v -> IntStream
                                                                .range(0,
                                                                        v.getLeft().intValue() * v.getRight()
                                                                                .getNumber().intValue())
                                                                .mapToObj(j -> l_doors.computeIfAbsent("door-"
                                                                        + i.getLeft().getId() + "-"
                                                                        + l_doorcount
                                                                                .computeIfAbsent(i.getLeft()
                                                                                        .getId(),
                                                                                        id -> new AtomicLong(1L))
                                                                                .getAndIncrement(),
                                                                        id -> l_doorgenerator.generatesingle(id,
                                                                                i.getLeft().getId(),
                                                                                v.getRight().getEntranceWidth()
                                                                                        .doubleValue()
                                                                                        / v.getRight().getNumber()
                                                                                                .longValue(),
                                                                                p_minfreetimetoclose))))
                                                        .collect(Collectors.toList())))
                                .collect(Collectors.toMap(IElement::id, i -> i))),
                l_doors);
    }

    /**
     * creates a train agent generator
     *
     * @param p_factory factory
     * @param p_asl asl script as String
     * @param p_actions actions
     * @return train generator
     */
    private static IElement.IGenerator<ITrain<?>> traingenerator(final IFactory p_factory, final String p_asl,
            final Set<IAction> p_actions, final ITime p_time) {
        try {
            return p_factory.train(IOUtils.toInputStream(p_asl, "UTF-8"), p_actions, p_time);
        } catch (final Exception l_exception) {
            throw new CSemanticException(l_exception);
        }
    }

    /**
     * creates a train door agent generator
     *
     * @param p_factory factory
     * @param p_asl asl script as String
     * @param p_actions actions
     * @return train door generator
     */
    private static IElement.IGenerator<IDoor<?>> doorgenerator(final IFactory p_factory, final String p_asl,
            final Set<IAction> p_actions, final ITime p_time) {
        try {
            return p_factory.door(IOUtils.toInputStream(p_asl, "UTF-8"), p_actions, p_time);
        } catch (final Exception l_exception) {
            throw new CSemanticException(l_exception);
        }
    }

    /**
     * creates a PassengerSource agent generator
     *
     * @param p_factory factory
     * @param p_asl asl script as String
     * @param p_actions actions
     * @return PassengerSource generator
     */
    private static IElement.IGenerator<IPassengerSource<?>> passengersourcegenerator(final IFactory p_factory,
            final String p_asl, final Set<IAction> p_actions, final ITime p_time) {
        try {
            return p_factory.passengersource(IOUtils.toInputStream(p_asl, "UTF-8"), p_actions, p_time);
        } catch (final Exception l_exception) {
            throw new CSemanticException(l_exception);
        }
    }

    /**
     * creates a Passenger agent generator
     *
     * @param p_factory factory
     * @param p_asl asl script as String
     * @param p_actions actions
     * @return Passenger generator
     */
    private static IElement.IGenerator<IPassenger<?>> passengergenerator(final IFactory p_factory,
            final String p_asl, final Set<IAction> p_actions, final ITime p_time) {
        try {
            return p_factory.passenger(IOUtils.toInputStream(p_asl, "UTF-8"), p_actions, p_time);
        } catch (final Exception l_exception) {
            throw new CSemanticException(l_exception);
        }
    }

    /**
     * get an agent-reference name
     *
     * @param p_value value of the agent-reference
     * @param p_list object list
     * @return agent-reference name
     * @throws CNotFoundException is thrown on not found
     */
    @SuppressWarnings("unchecked")
    private static <T> Pair<T, String> agentname(final T p_value, final List<Object> p_list) {
        return new ImmutablePair<T, String>(p_value,
                p_list.parallelStream().filter(a -> a instanceof AgentRef).findAny().map(a -> (AgentRef) a)
                        .map(AgentRef::getAgent).orElseThrow(() -> new CNotFoundException(
                                CCommon.languagestring(CXMLReader.class, "agentreferencenotfound"))));
    }

    /**
     * filter an object list
     *
     * @param p_list object list
     * @return agent-reference exist
     */
    private static boolean hasagentname(final List<Object> p_list) {
        return p_list.parallelStream().anyMatch(a -> a instanceof AgentRef);
    }

}