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 package info.magnolia.config.source.yaml.construct;
35
36 import static info.magnolia.config.source.yaml.dependency.YamlDependencyResoutionProblemType.DEPENDENCY_RESOLUTION;
37
38 import info.magnolia.config.maputil.ConfigurationMapOverlay;
39 import info.magnolia.config.maputil.ToMap;
40 import info.magnolia.config.registry.DefinitionProvider.Problem;
41 import info.magnolia.config.source.yaml.YamlReader;
42 import info.magnolia.config.source.yaml.dependency.YamlFileDependency;
43 import info.magnolia.resourceloader.ResourceOrigin;
44
45 import java.util.Map;
46 import java.util.function.Consumer;
47 import java.util.regex.Matcher;
48 import java.util.regex.Pattern;
49
50 import org.apache.commons.lang3.StringUtils;
51 import org.yaml.snakeyaml.nodes.Node;
52 import org.yaml.snakeyaml.nodes.ScalarNode;
53
54
55
56
57
58
59 public final class IncludeFileYamlWithModificationPossibility extends MgnlYamlConstruct {
60
61 public static final String TAG_PREFIX = "!include:";
62
63 private static final Pattern INCLUSION_MATCHER = Pattern.compile("^!include:(?<path>[0-9a-zA-Z_/-]+.yaml)$");
64
65 private final YamlReader yamlReader;
66 private final ResourceOrigin<?> resourceOrigin;
67
68 public IncludeFileYamlWithModificationPossibility(YamlReader yamlReader, ResourceOrigin<?> resourceOrigin, Consumer<Problem> problemCollector) {
69 super(problemCollector);
70 this.yamlReader = yamlReader;
71 this.resourceOrigin = resourceOrigin;
72 }
73
74 @Override
75 public Object construct(Node node) {
76 final Map<String, Object> baseData = ToMap.toMap(getConstructor().getConstructByNodeType(node).construct(node));
77
78 if (node instanceof ScalarNode) {
79 final String scalarValue = ((ScalarNode) node).getValue();
80 if (StringUtils.isNotBlank(scalarValue)) {
81 reportProblem(
82 Problem.minor()
83 .withType(DEPENDENCY_RESOLUTION)
84 .withTitle("Redundant inclusion syntax used")
85 .withDetails(String.format("Scalar value [%s] of node [%s] will be ignored due to !include:<resource_path> semantics",
86 scalarValue, node.getNodeId()))
87 .build());
88 }
89 }
90
91 final Matcher resourcePathMatcher = INCLUSION_MATCHER.matcher(node.getTag().getValue());
92 if (!resourcePathMatcher.matches()) {
93 reportProblem(
94 Problem.severe()
95 .withType(DEPENDENCY_RESOLUTION)
96 .withTitle("Mis-configured YAML resource dependency")
97 .withDetails(String.format("Tag [%s] does not match the inclusion pattern !include:<yaml_resource_path>",
98 node.getTag().getValue()))
99 .build());
100 return baseData;
101 }
102
103 final String path = resourcePathMatcher.group("path");
104 final YamlFileDependency dependency = new YamlFileDependency(resourceOrigin, path, yamlReader, getConstructor().getDependencyAggregator(), this::reportProblem);
105
106 if (!dependency.exists()) {
107 reportProblem(
108 Problem.major()
109 .withType(DEPENDENCY_RESOLUTION)
110 .withTitle("Missing YAML resource dependency")
111 .withDetails(String.format("Resource dependency at [%s] does not exist", path))
112 .build());
113 }
114
115 getConstructor().getDependencyAggregator().addDependency(dependency);
116
117 return ConfigurationMapOverlay
118 .of(ToMap.toMap(dependency.readData()))
119 .by(baseData)
120 .at("/")
121 .overlay();
122 }
123 }