1 /*
2 * Copyright 2013 University of Glasgow.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package broadwick.config;
17
18 import broadwick.config.generated.Models;
19 import broadwick.config.generated.Project;
20 import broadwick.model.Model;
21 import lombok.extern.slf4j.Slf4j;
22
23 /**
24 * Validator class for configuration files supplied to Broadwick, the framework for epidemiological modelling.
25 */
26 @Slf4j
27 public final class ConfigValidator {
28
29 /**
30 * Create an validator instance that is capable of checking the content of a configuration file.
31 * @param project the contents of the [read] configuration file. project.
32 */
33 public ConfigValidator(final Project project) {
34 this.project = project;
35 }
36
37 /**
38 * Validate the project.
39 * @return a ConfigValidationErrors object that contains all the errors (if any).
40 */
41 public ConfigValidationErrors validate() {
42 try {
43 validateModels();
44 } catch (Exception e) {
45 errors.addError("Could not validate the configuration file. " + e.getLocalizedMessage());
46 }
47
48 return errors;
49 }
50
51 /**
52 * Validate the Models section of the configuration file. Any errors will be saved in the local ValidationErrors.
53 */
54 private void validateModels() {
55 for (Models.Model model : project.getModels().getModel()) {
56
57 // we create (using reflection) the model(s) in the configuration file and check that the parameters
58 // and priors in the configuration file are valid for the model (by checking that the model has fields
59 // marked with the @Parameter and @Prior annotations).
60 final String clazz = model.getClassname();
61 final Model modelObj = this.<Model>createObject(Model.class, clazz);
62
63 if (modelObj == null) {
64 errors.addError(String.format("Could not create class [%s]. Does it exist?", clazz));
65 }
66 // TODO else perform any validation
67 }
68 }
69
70 /**
71 * If the project has been validated, i.e. it is structurally ok, then this method will simply return the project
72 * supplied in this objects constructor, else it will return null.
73 * @return null if the project is invalid (i.e. contains major errors) else returns the project object supplied to
74 * the constructor.
75 */
76 public Project getValidatedProject() {
77 if (errors.isValid()) {
78 return project;
79 } else {
80 return null;
81 }
82 }
83
84 /**
85 * Create an object through reflection, to use this method to create a solver object
86 * <code>
87 * Solver solverObj = this.<Solver>createObject(Solver.class, "RungeKutta4");
88 * </code>
89 * @param <T> the type of object to create.
90 * @param clazz the class type of the object we will create.
91 * @param name the name of the class that is to be instantiated.
92 * @return the created object.
93 */
94 private <T> T createObject(final Class<T> clazz, final String name) {
95 T object = null;
96 try {
97 // Check if the class exists
98 object = clazz.cast(Class.forName(name).newInstance());
99
100 } catch (InstantiationException | IllegalAccessException | ClassNotFoundException ex) {
101 errors.addError("Could not find " + clazz.getCanonicalName() + " class <" + name + ">");
102 }
103 return object;
104 }
105
106 private Project project;
107 private ConfigValidationErrors errors = new ConfigValidationErrors();
108 }