Check.java 8.84 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*-
 *  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 <https://www.gnu.org/licenses/>.
 */
package de.hft.stuttgart.citydoctor2.check;

Matthias Betz's avatar
Matthias Betz committed
21
22
import java.lang.reflect.Method;
import java.util.ArrayList;
23
24
25
import java.util.Collections;
import java.util.List;
import java.util.Map;
26
import java.util.Set;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

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
Matthias Betz's avatar
Matthias Betz committed
50
51
52
53
54
55
56
57
58
59
 * list of classes you wish to check.<br>
 * 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.<br>
 * If your check has dependencies you can declare them in the
60
61
62
63
64
65
66
67
 * {@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 {

Matthias Betz's avatar
Matthias Betz committed
68
	private List<Class<Checkable>> applicableToClasses = new ArrayList<>(2);
69

Matthias Betz's avatar
Matthias Betz committed
70
	@SuppressWarnings("unchecked")
Matthias Betz's avatar
Matthias Betz committed
71
	protected Check() {
Matthias Betz's avatar
Matthias Betz committed
72
73
74
75
76
77
78
79
80
		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<Checkable>) parameterTypes[0]);
				}
			}
		}
81
82
83
84
85
86
87
	}

	/**
	 * Returns all classes for which the check needs to be executed
	 * 
	 * @return a list of classes which the check applies to
	 */
Matthias Betz's avatar
Matthias Betz committed
88
89
90
	public List<Class<Checkable>> getApplicableToClasses() {
		return applicableToClasses;
	}
91
92
93
94
95
96
97
98
99
100
101

	/**
	 * 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<CheckId> getDependencies() {
		return Collections.emptyList();
	}
102
103
	
	public abstract Set<Requirement> appliesToRequirements();
104
105
106
107
108
109

	/**
	 * Getter for the check id.
	 * 
	 * @return the check id.
	 */
Matthias Betz's avatar
Matthias Betz committed
110
	public abstract CheckId getCheckId();
111
112
113
114
115
116

	/**
	 * Getter for the check type.
	 * 
	 * @return the check type
	 */
117
	public abstract RequirementType getType();
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

	/**
	 * 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. <br>
	 * 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
133
		if (!canBeApplied(c)) {
134
135
136
137
138
139
140
			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
Matthias Betz's avatar
Matthias Betz committed
141
				if (!c.hasDependencyNotMetError(getCheckId())) {
142
143
					// insert dependency error
					CheckError err = new DependenciesNotMetError(dependencyCheck);
Matthias Betz's avatar
Matthias Betz committed
144
					CheckResult cr = new CheckResult(getCheckId(), ResultStatus.DEPENDENCIES_NOT_MET, err);
145
146
147
148
149
150
151
					c.addCheckResult(cr);
				}
				return false;
			}
		}
		return true;
	}
Matthias Betz's avatar
Matthias Betz committed
152

153
154
155
156
157
158
159
160
	private boolean canBeApplied(Checkable c) {
		for (Class<Checkable> checkableClass : getApplicableToClasses()) {
			if (checkableClass.isAssignableFrom(c.getCheckClass())) {
				return true;
			}
		}
		return false;
	}
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332

	/**
	 * 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<String, String> 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<DefaultParameter> getDefaultParameter() {
		return Collections.emptyList();
	}

	@Override
	public String toString() {
Matthias Betz's avatar
Matthias Betz committed
333
		return "Check [id=" + getCheckId() + "]";
334
335
336
337
338
339
340
341
342
343
344
	}

	/**
	 * 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();

}