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;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
public enum BuildingState {
|
||||
EMPTY,
|
||||
ONE_THIRD,
|
||||
TWO_THIRD,
|
||||
FULL
|
||||
EMPTY("vide"),
|
||||
ONE_THIRD("un-tiers"),
|
||||
TWO_THIRD("deux-tiers"),
|
||||
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;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
public enum ComponentType {
|
||||
METAL,
|
||||
MOTOR,
|
||||
PLANE,
|
||||
WING
|
||||
METAL("metal"),
|
||||
MOTOR("moteur"),
|
||||
PLANE("avion"),
|
||||
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);
|
||||
}
|
||||
|
||||
// TODO WN: Move logic outside model
|
||||
@Override
|
||||
public void processInput(Component input) {
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package model;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue