Check.java 8.75 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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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
Matthias Betz's avatar
Matthias Betz committed
49
50
51
52
53
54
55
56
57
58
 * 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
59
60
61
62
63
64
65
66
 * {@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
67
	private List<Class<Checkable>> applicableToClasses = new ArrayList<>(2);
68

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

	/**
	 * 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
87
88
89
	public List<Class<Checkable>> getApplicableToClasses() {
		return applicableToClasses;
	}
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106

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

	/**
	 * Getter for the check id.
	 * 
	 * @return the check id.
	 */
Matthias Betz's avatar
Matthias Betz committed
107
	public abstract CheckId getCheckId();
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

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

150
151
152
153
154
155
156
157
	private boolean canBeApplied(Checkable c) {
		for (Class<Checkable> checkableClass : getApplicableToClasses()) {
			if (checkableClass.isAssignableFrom(c.getCheckClass())) {
				return true;
			}
		}
		return false;
	}
158
159
160
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

	/**
	 * 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
330
		return "Check [id=" + getCheckId() + "]";
331
332
333
334
335
336
337
338
339
340
341
	}

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

}