Checkable.java 7.72 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*-
 *  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;

import java.io.Serializable;
Matthias Betz's avatar
Matthias Betz committed
22
import java.util.HashMap;
23
24
25
26
27
28
29
30
31
32
33
import java.util.List;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import de.hft.stuttgart.citydoctor2.datastructure.GmlId;

/**
 * Interface to indicate that this object can be checked by Checks.
 * 
34
 * @author Matthias Betz
35
36
37
38
39
40
 *
 */
public abstract class Checkable implements Serializable {

	private static final long serialVersionUID = -1707871839265057882L;

Matthias Betz's avatar
Matthias Betz committed
41
	private static final Logger logger = LogManager.getLogger(Checkable.class);
42

Matthias Betz's avatar
Matthias Betz committed
43
	private Map<CheckId, CheckResult> checkResults = new HashMap<>();
44
	private boolean isValidated = false;
45

46
47
48
	protected void setValidated(boolean validated) {
		isValidated = validated;
	}
49

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
	public boolean isValidated() {
		return isValidated;
	}

	/**
	 * This object will be visited by the given check. Indirect implementers have to
	 * call <code>super.visit()</code> to ensure that every layer of classes is
	 * correctly checked. This method should call the visit method of each Checkable
	 * object contained in the implementing class.<br>
	 * <b>Note:</b> every object should only be visited once, therefore a clear
	 * structure has to be constructed in order to know which object is contained
	 * where. For example a Polygon has vertices as references but the actual
	 * storage location is in Geometry. Therefore only in Geometry the call to visit
	 * vertices is made.
	 * 
	 * @param c the check from which the check method is called with the Checkable
	 *          instance as parameter.
	 */
68
69
70
71
72
73
	public void accept(Check c) {
		if (c.canExecute(this)) {
			c.check(this);
		}
		setValidated(true);
	}
74
75
76
77
78
79
80
81

	/**
	 * The GML-ID of the checkable. This is necessary so specific features can be
	 * excluded via the ID.
	 * 
	 * @return the GML-ID
	 */
	public abstract GmlId getGmlId();
82
83
84
85
86
	
	public boolean hasGmlId() {
		return false;
	}

87

88
89
90
91
92
93
94
95
96
97
98
99
100
	/**
	 * This should be called before executing a check if low memory consumption
	 * method has been enabled. This should create edges and additional meta
	 * information necessary to perform checks.
	 */
	public abstract void prepareForChecking();

	/**
	 * This should be called after checking has been done. This should remove any
	 * created meta information like edges to free up additional memory space
	 */
	public abstract void clearMetaInformation();

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
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
	/**
	 * This method checks if the object or any object contained within this
	 * checkable has an error. It counts as an error if the result status if the
	 * given check is <code>DEPENDENCIES_NOT_MET<code>.
	 * 
	 * @param checkIdentifier the name of the check for which an error is searched
	 * @return true if an error has been found with the given check
	 */
	public boolean containsError(CheckId checkIdentifier) {
		CheckResult cs = getCheckResult(checkIdentifier);
		if (cs == null) {
			return false;
		}
		ResultStatus rs = cs.getResultStatus();
		return rs == ResultStatus.ERROR || rs == ResultStatus.DEPENDENCIES_NOT_MET;
	}

	/**
	 * Returns the check result for the given CheckId
	 * 
	 * @param id the id
	 * @return the check result or null if none was found
	 */
	public CheckResult getCheckResult(CheckId id) {
		return checkResults.get(id);
	}

	/**
	 * Returns the check result for the given Check.
	 * 
	 * @param c the check
	 * @return the check result or null if none was found
	 */
	public CheckResult getCheckResult(Check c) {
		return getCheckResult(c.getCheckId());
	}

	/**
	 * 
	 * @return all check results for this checkable.
	 */
	public Map<CheckId, CheckResult> getAllCheckResults() {
		return checkResults;
	}

	/**
	 * Checks whether this checkable has a DependencyNotMetError for the given
	 * CheckId.
	 * 
	 * @param id the CheckId for which the error is searched.
	 * @return true if it contains such an error, false if not or no CheckResult is
	 *         available for the given id.
	 */
	public boolean hasDependencyNotMetError(CheckId id) {
		CheckResult cr = checkResults.get(id);
		if (cr == null) {
			return false;
		}
		return cr.getResultStatus() == ResultStatus.DEPENDENCIES_NOT_MET;
	}

	/**
	 * Checks whether this checkable has an error. Dependency errors are not
	 * considered for this function. This will only check this checkable and not
	 * traverse any checkables contained in this instance.
	 * 
	 * @return true if it has an error, otherwise false
	 */
	public boolean hasAnyError() {
		for (CheckResult cr : checkResults.values()) {
			if (cr.getResultStatus() == ResultStatus.ERROR) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Checks whether any check results have been reported for this checkable
	 * 
	 * @return true if any checks have reported results, false otherwise
	 */
	public boolean hasCheckResults() {
		return !checkResults.isEmpty();
	}

	/**
	 * Adds the result of a check to this checkable.
	 * 
	 * @param cr the check result
	 */
	public void addCheckResult(CheckResult cr) {
		checkResults.put(cr.getCheckIdentifier(), cr);
Matthias Betz's avatar
Matthias Betz committed
194
		if (cr.getResultStatus() == ResultStatus.ERROR && logger.isDebugEnabled()) {
195
			logger.debug("{} has found an error of type {}", cr.getCheckIdentifier(), cr.getError().getErrorId());
Matthias Betz's avatar
Matthias Betz committed
196
		} else if (cr.getResultStatus() == ResultStatus.WARNING && logger.isDebugEnabled()) {
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
			logger.debug("{} has found a warning of type {}", cr.getCheckIdentifier(), cr.getError().getErrorId());
		}
	}

	/**
	 * Clears all errors from this checkable
	 */
	public void clearCheckResults() {
		setValidated(false);
		checkResults.clear();
	}

	/**
	 * Removes all errors from this instance and all contained checkables.
	 */
	public abstract void clearAllContainedCheckResults();

	/**
	 * 
	 * @return false if the checkable or all checkables contained in this one don't
	 *         have any error.
	 */
	public boolean containsAnyError() {
		for (CheckResult cr : checkResults.values()) {
			if (cr.getResultStatus() == ResultStatus.ERROR
					|| cr.getResultStatus() == ResultStatus.DEPENDENCIES_NOT_MET) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Collects all errors from this checkable and all contained checkables and adds
	 * them to the given list. DEPENDENCY_NOT_MET errors are excluded from this.
	 * 
	 * @param errors the collection in which the errors are added.
	 */
	public void collectContainedErrors(List<CheckError> errors) {
		for (CheckResult cr : checkResults.values()) {
			if (cr.getResultStatus() == ResultStatus.ERROR) {
				errors.add(cr.getError());
			}
		}
	}

	/**
	 * As which class is this object being tested. This is used when there are
	 * different implementations for the same object type. For example a polygon can
	 * be a link to another polygon as well as the polygon which contains the actual
	 * data. Checks declare which objects they check, which would be Polygon in this
	 * example. Now there are two kinds of polygons but both are treated as
	 * polygons.
	 * 
	 * @return the class for which the object should be treated as.
	 */
	public Class<? extends Checkable> getCheckClass() {
		return getClass();
	}

}