Add configuration parser

This commit is contained in:
FyloZ 2022-05-29 11:00:06 -04:00
parent 67de8513ea
commit a2ed695a4a
Signed by: william
GPG Key ID: 835378AE9AF4AE97
12 changed files with 395 additions and 9 deletions

12
src/TestMain.java Normal file
View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
} }

View File

@ -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);
}
} }

View File

@ -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) {
} }

View File

@ -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);
} }