/*- * Copyright 2020 Beuth Hochschule für Technik Berlin, Hochschule für Technik Stuttgart * * This file is part of CityDoctor2. * * CityDoctor2 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. * * CityDoctor2 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 CityDoctor2. If not, see . */ package de.hft.stuttgart.citydoctor2.check; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import de.hft.stuttgart.citydoctor2.check.error.DependenciesNotMetError; import de.hft.stuttgart.citydoctor2.datastructure.AbstractBuilding; import de.hft.stuttgart.citydoctor2.datastructure.BoundarySurface; import de.hft.stuttgart.citydoctor2.datastructure.BridgeObject; import de.hft.stuttgart.citydoctor2.datastructure.Building; import de.hft.stuttgart.citydoctor2.datastructure.BuildingInstallation; import de.hft.stuttgart.citydoctor2.datastructure.BuildingPart; import de.hft.stuttgart.citydoctor2.datastructure.CityObject; import de.hft.stuttgart.citydoctor2.datastructure.Geometry; import de.hft.stuttgart.citydoctor2.datastructure.LandObject; import de.hft.stuttgart.citydoctor2.datastructure.LinearRing; import de.hft.stuttgart.citydoctor2.datastructure.Opening; import de.hft.stuttgart.citydoctor2.datastructure.Polygon; import de.hft.stuttgart.citydoctor2.datastructure.TransportationObject; import de.hft.stuttgart.citydoctor2.datastructure.Vegetation; import de.hft.stuttgart.citydoctor2.datastructure.WaterObject; import de.hft.stuttgart.citydoctor2.parser.ParserConfiguration; /** * The general check class containing the methods which will be called by check * engine. To create a new check override one or more check(...) methods and * implement the {@link Check#getApplicableToClasses()} method by returning a * list of classes you wish to check.
* CheckResult objects can be attached to every Checkable. If the check has * parameters override the {@link Check#init(Map, ParserConfiguration)} method * to get the value of a parameter if a user has specified one in the validation * plan. It will be contained in the Map as a string. If you have parameters you * will need to override the {@link Check#getDefaultParameter()} method as well * to declare which parameters you have, which name and default value they have. * The name will be the key for the Map in the init method previously * mentioned.
* If your check has dependencies you can declare them in the * {@link Check#getDependencies()} method. Be sure not to create cyclic * dependencies as that would result in undefined behavior. * * @author Matthias Betz * */ public abstract class Check { private List> applicableToClasses = new ArrayList<>(2); @SuppressWarnings("unchecked") protected Check() { Method[] declaredMethods = getClass().getDeclaredMethods(); for (Method m : declaredMethods) { if ("check".equals(m.getName())) { Class[] parameterTypes = m.getParameterTypes(); if (parameterTypes.length == 1 && Checkable.class.isAssignableFrom(parameterTypes[0])) { applicableToClasses.add((Class) parameterTypes[0]); } } } } /** * Returns all classes for which the check needs to be executed * * @return a list of classes which the check applies to */ public List> getApplicableToClasses() { return applicableToClasses; } /** * A list of dependencies which the check depends on. Each of those dependencies * needs to be executed and must have reported no error before this check can be * executed. * * @return a list of CheckIds which the check depends on. */ public List getDependencies() { return Collections.emptyList(); } /** * Getter for the check id. * * @return the check id. */ public abstract CheckId getCheckId(); /** * Getter for the check type. * * @return the check type */ public abstract CheckType getType(); /** * Checks whether the check can be executed on this checkable, meaning the * checkable or its content can not have any error of any check dependent on * this check.
* If the check cannot be executed a CheckResult will be created with the * ResultStatus = DEPENDENCIES_NOT_MET. * * @param c the checkable * @param crc container for all check results * @return true if the check can be executed, false if the checkable itself or * one of its containing checkables have an error. */ public boolean canExecute(Checkable c) { // ignore objects where this check doesn't apply to if (!canBeApplied(c)) { return false; } // check that object doesn't have errors for dependencies of this check for (CheckId dependencyCheck : getDependencies()) { boolean hasError = c.containsError(dependencyCheck); if (hasError) { // check whether a result was already inserted if (!c.hasDependencyNotMetError(getCheckId())) { // insert dependency error CheckError err = new DependenciesNotMetError(dependencyCheck); CheckResult cr = new CheckResult(getCheckId(), ResultStatus.DEPENDENCIES_NOT_MET, err); c.addCheckResult(cr); } return false; } } return true; } private boolean canBeApplied(Checkable c) { for (Class checkableClass : getApplicableToClasses()) { if (checkableClass.isAssignableFrom(c.getCheckClass())) { return true; } } return false; } /** * check anything * * @param checkable a checkable */ public void check(Checkable checkable) { } /** * check buildings and building parts * * @param ab building or building part */ public void check(AbstractBuilding ab) { } /** * check boundary surfaces * * @param bs a boundary surface */ public void check(BoundarySurface bs) { } /** * check bridges * * @param bo a bridge */ public void check(BridgeObject bo) { } /** * check only buildings * * @param b a building */ public void check(Building b) { } /** * check building installations * * @param bi a building installation */ public void check(BuildingInstallation bi) { } /** * check only building parts * * @param bp a building part */ public void check(BuildingPart bp) { } /** * check all city objects * * @param co a city object */ public void check(CityObject co) { } /** * check land use objects * * @param lo a land use object */ public void check(LandObject lo) { } /** * check openings * * @param o an opening */ public void check(Opening o) { } /** * check transportation objects * * @param to a transportation object */ public void check(TransportationObject to) { } /** * check vegetation objects * * @param veg a vegetation object */ public void check(Vegetation veg) { } /** * check water objects * * @param wo a water object */ public void check(WaterObject wo) { } /** * check geometries * * @param geom a geometry */ public void check(Geometry geom) { } /** * check polygons * * @param poly a polygon */ public void check(Polygon poly) { } /** * check linear rings * * @param ring a linear ring */ public void check(LinearRing ring) { } /** * The initialization method of this check. It will be called before any check * method will be executed. Override this if you want to have configurable * parameters. * * @param params the parameter map containing the parameters for the check in * String form. The key should be the same String provided by the * {@link Check#getDefaultParameter()} method * @param config sometimes there are global parameters which can be used by * checks. Those are be stored in this container */ public void init(Map params, ParserConfiguration config) { } /** * This methods gives checks the possibility to declare default parameters, used * primarily in the GUI. * * @return a list of default parameters, not null */ public List getDefaultParameter() { return Collections.emptyList(); } @Override public String toString() { return "Check [id=" + getCheckId() + "]"; } /** * Create a new instance of this check. This is needed to keep the checks * dynamic * * @return a new instance of this check */ public abstract Check createNewInstance(); }