summaryrefslogtreecommitdiffstats
path: root/dcaedt_validator/checker/src/main/java/org/onap/sdc/dcae/checker/validation/TOSCAValidator.java
blob: 099502eb1d5e1edf06f5c4ac212235c8dd453964 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package org.onap.sdc.dcae.checker.validation;

import kwalify.Rule;
import kwalify.Types;
import kwalify.Validator;
import org.onap.sdc.common.onaplog.enums.LogLevel;
import org.onap.sdc.common.onaplog.OnapLoggerDebug;
import org.onap.sdc.common.onaplog.OnapLoggerError;
import org.onap.sdc.dcae.checker.IChecker;
import org.onap.sdc.dcae.checker.Target;

import java.util.*;

public class TOSCAValidator extends Validator {
    private static OnapLoggerError errLogger = OnapLoggerError.getInstance();
    private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance();
    private final IChecker checker;
    //what were validating
    private Target target;

    /* Some of the TOSCA entries accept a 'short form/notation' instead of the canonical map representation.
     * kwalify cannot easily express these alternatives and as such we handle them here. In the pre-validation phase we detect the presence of a short notation
and compute the canonical form and validate it. In the post-validation phase we
substitute the canonical form for the short form so that checking does not have to deal with it.
     */

    public Map<String, Object> getCanonicals() {
        return canonicals;
    }

    private Map<String, Object> canonicals = new TreeMap<>();

    public TOSCAValidator(Target theTarget, Object theSchema, IChecker checker) {
        super(theSchema);
        this.checker = checker;
        this.target = theTarget;
    }

    public Target getTarget() {
        return this.target;
    }

    /* hook method called by Validator#validate()
     */
    @Override
    protected boolean preValidationHook(Object value, Rule rule, ValidationContext context) {

        checker.validationHook("pre", value, rule, context);
        //short form handling
        String hint = rule.getShort();
        if (value != null &&
                hint != null) {

            debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Attempting canonical at {}, rule {}", context.getPath(), rule.getName());

            Object canonical = null;
            //if the canonical form requires a collection
            if (Types.isCollectionType(rule.getType())) {
                //and the actual value isn't one
                if (!(value instanceof Map || value instanceof List)) {
                    //used to use singleton map/list here (was good for catching errors)
                    //but there is the possibility if short forms within short forms so
                    //the created canonicals need to accomodate other values.
                    if (Types.isMapType(rule.getType())) {
                        canonical = new HashMap();
                        ((Map) canonical).put(hint, value);
                    } else {
                        //the hint is irrelevant here but we should impose a value when the target is a list
                        canonical = new LinkedList();
                        ((List) canonical).add(value);
                    }
                } else {
                    //we can accomodate:
                    // map to list of map transformation
                    if (!Types.isMapType(rule.getType()) /* a seq */ &&
                            value instanceof Map) {
                        canonical = new LinkedList();
                        ((List) canonical).add(value);
                    } else {
                        debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Grammar for rule {} (at {}) would require unsupported short form transformation: {} to {}", rule.getName(), context.getPath(), value.getClass(), rule.getType());
                        return false;
                    }
                }

                int errc = context.errorCount();
                validateRule(canonical, rule, context);
                if (errc != context.errorCount()) {
                    debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Short notation for {} through {} at {} failed validation", rule.getName(), hint, context.getPath());
                } else {
                    debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Short notation for {} through {} at {} passed validation. Canonical form is {}", rule.getName(), hint, context.getPath(), canonical);
                    //replace the short notation with the canonicall one so we don't
                    //have to deal it again during checking
                    this.canonicals.put(context.getPath(), canonical);
                    return true;
                }
            } else {
                debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Grammar for rule {} (at {}) would require unsupported short form transformation: {} to {}", rule.getName(), context.getPath(), value.getClass(), rule.getType());
            }
        }

        //perform default validation process
        return false;
    }

    /*
     * Only gets invoked once the value was succesfully verified against the syntax indicated by the given rule.
     */
    @Override
    protected void postValidationHook(Object value,
                                      Rule rule,
                                      ValidationContext context) {
        checker.validationHook("post", value, rule, context);
    }

}