Add configuration parser
This commit is contained in:
parent
67de8513ea
commit
a2ed695a4a
|
@ -0,0 +1,12 @@
|
||||||
|
import configuration.ConfigurationParser;
|
||||||
|
import configuration.ConfigurationParsingException;
|
||||||
|
import configuration.XmlConfigurationParser;
|
||||||
|
|
||||||
|
public class TestMain {
|
||||||
|
public static void main(String[] args) throws ConfigurationParsingException {
|
||||||
|
String configurationFilePath = "/home/william/Dev/Projects/Uni/Log121/TP01/squelette/src/ressources/configuration.xml";
|
||||||
|
|
||||||
|
ConfigurationParser parser = new XmlConfigurationParser();
|
||||||
|
parser.parseConfiguration(configurationFilePath);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package configuration;
|
||||||
|
|
||||||
|
public interface ConfigurationParser {
|
||||||
|
/**
|
||||||
|
* Analyse et lit une configuration de simulation depuis un fichier au chemin donné.
|
||||||
|
*
|
||||||
|
* @param path Le chemin vers le fichier de configuration.
|
||||||
|
* @return La configuration de simulation correspondant au contenu du fichier.
|
||||||
|
*/
|
||||||
|
SimulationConfiguration parseConfiguration(String path) throws ConfigurationParsingException;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package configuration;
|
||||||
|
|
||||||
|
public class ConfigurationParsingException extends Exception {
|
||||||
|
public ConfigurationParsingException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationParsingException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationParsingException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationParsingException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigurationParsingException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package configuration;
|
||||||
|
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Spliterator;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class IterableNodeList implements Iterable<Element> {
|
||||||
|
private final NodeList nodes;
|
||||||
|
|
||||||
|
public IterableNodeList(NodeList nodes) {
|
||||||
|
this.nodes = nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Element> iterator() {
|
||||||
|
return new NodeListElementIterator(nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEach(Consumer<? super Element> action) {
|
||||||
|
Iterable.super.forEach(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Spliterator<Element> spliterator() {
|
||||||
|
return Iterable.super.spliterator();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package configuration;
|
||||||
|
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
public class NodeListElementIterator implements Iterator<Element> {
|
||||||
|
private final NodeList nodes;
|
||||||
|
private int position = 0;
|
||||||
|
|
||||||
|
public NodeListElementIterator(NodeList nodes) {
|
||||||
|
this.nodes = nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
if (position >= nodes.getLength()) return false;
|
||||||
|
|
||||||
|
// Check if there is a remaining element node
|
||||||
|
for (int i = position; i < nodes.getLength(); i++) {
|
||||||
|
Node node = nodes.item(i);
|
||||||
|
|
||||||
|
if (node.getNodeType() == Node.ELEMENT_NODE) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Element next() {
|
||||||
|
if (position >= nodes.getLength()) return null;
|
||||||
|
|
||||||
|
Node node = nodes.item(position);
|
||||||
|
position++;
|
||||||
|
|
||||||
|
if (node.getNodeType() == Node.ELEMENT_NODE) return (Element) node;
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package configuration;
|
||||||
|
|
||||||
|
import model.metadata.BuildingMetadata;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class SimulationConfiguration {
|
||||||
|
private final Map<String, BuildingMetadata> metadata;
|
||||||
|
private final SimulationData simulationData;
|
||||||
|
|
||||||
|
public SimulationConfiguration(Map<String, BuildingMetadata> metadata, SimulationData simulationData) {
|
||||||
|
this.metadata = metadata;
|
||||||
|
this.simulationData = simulationData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, BuildingMetadata> getMetadata() {
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimulationData getSimulationData() {
|
||||||
|
return simulationData;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package configuration;
|
||||||
|
|
||||||
|
import model.Building;
|
||||||
|
import model.Route;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public class SimulationData {
|
||||||
|
private final Collection<Building> buildings;
|
||||||
|
private final Collection<Route> routes;
|
||||||
|
|
||||||
|
public SimulationData(Collection<Building> buildings, Collection<Route> routes) {
|
||||||
|
this.buildings = buildings;
|
||||||
|
this.routes = routes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Building> getBuildings() {
|
||||||
|
return buildings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Route> getRoutes() {
|
||||||
|
return routes;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,190 @@
|
||||||
|
package configuration;
|
||||||
|
|
||||||
|
import model.*;
|
||||||
|
import model.metadata.*;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class XmlConfigurationParser implements ConfigurationParser {
|
||||||
|
public static final String TAG_METADATA = "metadonnees";
|
||||||
|
public static final String TAG_SIMULATION_DATA = "simulation";
|
||||||
|
public static final String TAG_BUILDING = "usine";
|
||||||
|
public static final String TAG_ROUTES = "chemins";
|
||||||
|
public static final String TAG_ICONS = "icones";
|
||||||
|
public static final String TAG_INPUT = "entree";
|
||||||
|
public static final String TAG_OUTPUT = "sortie";
|
||||||
|
public static final String TAG_PRODUCTION_INTERVAL = "interval-production";
|
||||||
|
public static final String ATTRIBUTE_TYPE = "type";
|
||||||
|
public static final String ATTRIBUTE_PATH = "path";
|
||||||
|
public static final String ATTRIBUTE_QUANTITY = "quantite";
|
||||||
|
public static final String ATTRIBUTE_CAPACITY = "capacite";
|
||||||
|
public static final String ATTRIBUTE_ID = "id";
|
||||||
|
public static final String ATTRIBUTE_X = "x";
|
||||||
|
public static final String ATTRIBUTE_Y = "y";
|
||||||
|
public static final String ATTRIBUTE_FROM = "de";
|
||||||
|
public static final String ATTRIBUTE_TO = "vers";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimulationConfiguration parseConfiguration(String path) throws ConfigurationParsingException {
|
||||||
|
Document document = parseDocument(path);
|
||||||
|
|
||||||
|
Map<String, BuildingMetadata> buildingsMetadata = parseBuildingsMetadata(document);
|
||||||
|
SimulationData simulationData = parseSimulationData(document);
|
||||||
|
|
||||||
|
return new SimulationConfiguration(buildingsMetadata, simulationData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Document parseDocument(String path) throws ConfigurationParsingException {
|
||||||
|
try {
|
||||||
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||||
|
|
||||||
|
Document document = builder.parse(path);
|
||||||
|
document.getDocumentElement().normalize();
|
||||||
|
|
||||||
|
return document;
|
||||||
|
} catch (ParserConfigurationException | IOException | SAXException e) {
|
||||||
|
throw new ConfigurationParsingException("La lecture du fichier a échoué", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, BuildingMetadata> parseBuildingsMetadata(Document document) {
|
||||||
|
Node metadataNode = document.getElementsByTagName(TAG_METADATA).item(0);
|
||||||
|
Map<String, BuildingMetadata> metadata = new HashMap<>();
|
||||||
|
|
||||||
|
for (Element elem : new IterableNodeList(metadataNode.getChildNodes())) {
|
||||||
|
String buildingType = elem.getAttribute(ATTRIBUTE_TYPE);
|
||||||
|
|
||||||
|
metadata.put(buildingType, parseBuildingMetadata(elem));
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BuildingMetadata parseBuildingMetadata(Element buildingElement) {
|
||||||
|
String type = buildingElement.getAttribute(ATTRIBUTE_TYPE);
|
||||||
|
|
||||||
|
return type.equals("entrepot") ?
|
||||||
|
parseWarehouseMetadata(buildingElement, type) :
|
||||||
|
parseFactoryMetadata(buildingElement, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BuildingMetadata parseFactoryMetadata(Element factoryElement, String type) {
|
||||||
|
Map<BuildingState, String> iconsPaths = null;
|
||||||
|
Collection<FactoryInput> inputs = new ArrayList<>();
|
||||||
|
FactoryOutput output = null;
|
||||||
|
int productionInterval = -1;
|
||||||
|
|
||||||
|
for (Element elem : new IterableNodeList(factoryElement.getChildNodes())) {
|
||||||
|
switch (elem.getNodeName()) {
|
||||||
|
case TAG_ICONS -> iconsPaths = parseBuildingIcons(elem);
|
||||||
|
case TAG_INPUT -> {
|
||||||
|
FactoryInput input = parseFactoryInput(elem);
|
||||||
|
inputs.add(input);
|
||||||
|
}
|
||||||
|
case TAG_OUTPUT -> output = parseFactoryOutput(elem);
|
||||||
|
case TAG_PRODUCTION_INTERVAL -> productionInterval = Integer.parseInt(elem.getTextContent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FactoryMetadata(type, iconsPaths, productionInterval, inputs, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BuildingMetadata parseWarehouseMetadata(Element warehouseElement, String type) {
|
||||||
|
Map<BuildingState, String> iconsPaths = null;
|
||||||
|
WarehouseInput input = null;
|
||||||
|
|
||||||
|
for (Element elem : new IterableNodeList(warehouseElement.getChildNodes())) {
|
||||||
|
switch (elem.getNodeName()) {
|
||||||
|
case TAG_ICONS -> iconsPaths = parseBuildingIcons(elem);
|
||||||
|
case TAG_INPUT -> input = parseWarehouseInput(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new WarehouseMetadata(type, iconsPaths, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<BuildingState, String> parseBuildingIcons(Element iconsElement) {
|
||||||
|
Map<BuildingState, String> iconsPaths = new HashMap<>();
|
||||||
|
|
||||||
|
for (Element elem : new IterableNodeList(iconsElement.getChildNodes())) {
|
||||||
|
BuildingState state = BuildingState.getFromTypeName(elem.getAttribute(ATTRIBUTE_TYPE));
|
||||||
|
String path = elem.getAttribute(ATTRIBUTE_PATH);
|
||||||
|
|
||||||
|
iconsPaths.put(state, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return iconsPaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
private FactoryInput parseFactoryInput(Element inputElement) {
|
||||||
|
ComponentType type = ComponentType.getForTypeName(inputElement.getAttribute(ATTRIBUTE_TYPE));
|
||||||
|
int quantity = Integer.parseInt(inputElement.getAttribute(ATTRIBUTE_QUANTITY));
|
||||||
|
|
||||||
|
return new FactoryInput(type, quantity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private WarehouseInput parseWarehouseInput(Element inputElement) {
|
||||||
|
ComponentType type = ComponentType.getForTypeName(inputElement.getAttribute(ATTRIBUTE_TYPE));
|
||||||
|
int capacity = Integer.parseInt(inputElement.getAttribute(ATTRIBUTE_CAPACITY));
|
||||||
|
|
||||||
|
return new WarehouseInput(type, capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FactoryOutput parseFactoryOutput(Element outputElement) {
|
||||||
|
ComponentType type = ComponentType.getForTypeName(outputElement.getAttribute(ATTRIBUTE_TYPE));
|
||||||
|
|
||||||
|
return new FactoryOutput(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SimulationData parseSimulationData(Document document) {
|
||||||
|
Node dataNode = document.getElementsByTagName(TAG_SIMULATION_DATA).item(0);
|
||||||
|
|
||||||
|
Collection<Building> buildings = new ArrayList<>();
|
||||||
|
Collection<Route> routes = null;
|
||||||
|
|
||||||
|
for (Element elem : new IterableNodeList(dataNode.getChildNodes())) {
|
||||||
|
switch (elem.getNodeName()) {
|
||||||
|
case TAG_BUILDING -> buildings.add(parseBuilding(elem));
|
||||||
|
case TAG_ROUTES -> routes = parseRoutes(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SimulationData(buildings, routes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Building parseBuilding(Element buildingElement) {
|
||||||
|
String type = buildingElement.getAttribute(ATTRIBUTE_TYPE);
|
||||||
|
int id = Integer.parseInt(buildingElement.getAttribute(ATTRIBUTE_ID));
|
||||||
|
int x = Integer.parseInt(buildingElement.getAttribute(ATTRIBUTE_X));
|
||||||
|
int y = Integer.parseInt(buildingElement.getAttribute(ATTRIBUTE_Y));
|
||||||
|
|
||||||
|
return type.equals("entrepot") ?
|
||||||
|
new Warehouse(id, type, x, y) :
|
||||||
|
new Factory(id, type, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<Route> parseRoutes(Element routesElement) {
|
||||||
|
Collection<Route> routes = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Element elem : new IterableNodeList(routesElement.getChildNodes())) {
|
||||||
|
int from = Integer.parseInt(elem.getAttribute(ATTRIBUTE_TO));
|
||||||
|
int to = Integer.parseInt(elem.getAttribute(ATTRIBUTE_FROM));
|
||||||
|
|
||||||
|
routes.add(new Route(from, to));
|
||||||
|
}
|
||||||
|
|
||||||
|
return routes;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,24 @@
|
||||||
package model;
|
package model;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public enum BuildingState {
|
public enum BuildingState {
|
||||||
EMPTY,
|
EMPTY("vide"),
|
||||||
ONE_THIRD,
|
ONE_THIRD("un-tiers"),
|
||||||
TWO_THIRD,
|
TWO_THIRD("deux-tiers"),
|
||||||
FULL
|
FULL("plein");
|
||||||
|
|
||||||
|
private final String typeName;
|
||||||
|
|
||||||
|
BuildingState(String typeName) {
|
||||||
|
this.typeName = typeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BuildingState getFromTypeName(String typeName) {
|
||||||
|
return Arrays.stream(BuildingState.values())
|
||||||
|
.filter(t -> Objects.equals(t.typeName, typeName))
|
||||||
|
.findFirst().orElse(null);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,23 @@
|
||||||
package model;
|
package model;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public enum ComponentType {
|
public enum ComponentType {
|
||||||
METAL,
|
METAL("metal"),
|
||||||
MOTOR,
|
MOTOR("moteur"),
|
||||||
PLANE,
|
PLANE("avion"),
|
||||||
WING
|
WING("aile");
|
||||||
|
|
||||||
|
private final String typeName;
|
||||||
|
|
||||||
|
ComponentType(String typeName) {
|
||||||
|
this.typeName = typeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ComponentType getForTypeName(String typeName) {
|
||||||
|
return Arrays.stream(ComponentType.values())
|
||||||
|
.filter(t -> Objects.equals(t.typeName, typeName))
|
||||||
|
.findFirst().orElse(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ public class Factory extends Building {
|
||||||
super(id, type, x, y);
|
super(id, type, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO WN: Move logic outside model
|
||||||
@Override
|
@Override
|
||||||
public void processInput(Component input) {
|
public void processInput(Component input) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package model;
|
package model;
|
||||||
|
|
||||||
public class Warehouse extends Building {
|
public class Warehouse extends Building {
|
||||||
protected Warehouse(int id, String type, int x, int y) {
|
public Warehouse(int id, String type, int x, int y) {
|
||||||
super(id, type, x, y);
|
super(id, type, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue