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.rendering.template.registry.validator;
35
36 import static info.magnolia.config.registry.DefinitionProvider.Problem.DefaultTypes.RESOLUTION;
37 import static info.magnolia.config.registry.DefinitionProvider.Problem.*;
38 import static info.magnolia.util.DeprecationUtil.getDeprecationMessage;
39
40 import info.magnolia.config.registry.DefinitionMetadata;
41 import info.magnolia.config.registry.DefinitionProvider;
42 import info.magnolia.config.registry.validator.DefinitionValidator;
43 import info.magnolia.rendering.DefinitionTypes;
44 import info.magnolia.rendering.model.RenderingModel;
45 import info.magnolia.rendering.renderer.registry.RendererRegistry;
46 import info.magnolia.rendering.template.AreaDefinition;
47 import info.magnolia.rendering.template.ComponentAvailability;
48 import info.magnolia.rendering.template.TemplateDefinition;
49 import info.magnolia.rendering.template.registry.TemplateDefinitionRegistry;
50 import info.magnolia.resourceloader.ResourceOrigin;
51
52 import java.util.ArrayList;
53 import java.util.Collection;
54 import java.util.Map;
55 import java.util.Optional;
56
57 import javax.inject.Inject;
58 import javax.inject.Provider;
59
60
61
62
63
64
65 public class TemplateDefinitionValidator implements DefinitionValidator<TemplateDefinition> {
66
67 private final Provider<TemplateDefinitionRegistry> templateDefinitionRegistryProvider;
68 private final RendererRegistry rendererRegistry;
69 private final ResourceOrigin resourceOrigin;
70
71 @Inject
72 public TemplateDefinitionValidator(Provider<TemplateDefinitionRegistry> templateDefinitionRegistryProvider, RendererRegistry rendererRegistry, ResourceOrigin resourceOrigin) {
73 this.templateDefinitionRegistryProvider = templateDefinitionRegistryProvider;
74 this.rendererRegistry = rendererRegistry;
75 this.resourceOrigin = resourceOrigin;
76 }
77
78 @Override
79 public Collection<DefinitionProvider.Problem> validate(DefinitionProvider<TemplateDefinition> provider) {
80 final Collection<DefinitionProvider.Problem> problems = new ArrayList<>();
81 if (provider.isValid()) {
82 validateDefinition(problems, provider);
83 }
84 return problems;
85 }
86
87 protected void validateDefinition(Collection<DefinitionProvider.Problem> problems, DefinitionProvider<TemplateDefinition> definitionProvider) {
88 TemplateDefinition definition = definitionProvider.get();
89 String renderType = definition.getRenderType();
90 validateRenderType(problems, "", renderType);
91 validateTemplateScript(problems, "", definition.getTemplateScript(), renderType);
92 validateModelClass(problems, "", definition.getModelClass());
93 definition.getAreas().forEach((areaName, area) -> validateArea(definitionProvider, problems, "", area));
94 }
95
96 protected void validateArea(DefinitionProvider<TemplateDefinition> definitionProvider, Collection<DefinitionProvider.Problem> problems, String rootPath, AreaDefinition areaDefinition) {
97 final String areaPath = rootPath + "areas/" + areaDefinition.getName() + "/";
98
99 Map<String, ComponentAvailability> availableComponents = areaDefinition.getAvailableComponents();
100
101 if (availableComponents != null) {
102 availableComponents.forEach((componentName, componentAvailability) -> {
103 Optional<DefinitionMetadata> componentMetadataOptional = templateDefinitionRegistryProvider.get().getAllMetadata().stream()
104 .filter(metadata -> metadata.getReferenceId().equals(componentAvailability.getId()))
105 .findAny();
106
107 if (!componentMetadataOptional.isPresent()) {
108 problems.add(major()
109 .withType(DefinitionProvider.Problem.DefaultTypes.REFERENCES)
110 .withTitle("Template availability problem")
111 .withDetails("Template {" + componentAvailability.getId() + "} is not registered.")
112 .withLocation(areaPath + "availableComponents/" + componentName)
113 .build());
114 }
115
116 else if (!definitionProvider.getMetadata().getDeprecation().isPresent() && componentMetadataOptional.get().getDeprecation().isPresent()) {
117 DefinitionMetadata componentMetadata = componentMetadataOptional.get();
118 componentMetadata.getDeprecation().ifPresent(deprecation -> {
119 String deprecationMessage = getDeprecationMessage(DefinitionTypes.TEMPLATE.getName(), componentMetadata.getName(), deprecation.since(), deprecation.description());
120
121 problems.add(deprecated()
122 .withTitle("Deprecated definition usage")
123 .withDetails(deprecationMessage)
124 .withLocation(areaPath + "availableComponents/" + componentName)
125 .withType(RESOLUTION)
126 .build());
127 });
128 }
129 }
130 );
131 }
132
133 String renderType = areaDefinition.getRenderType();
134 validateTemplateScript(problems, areaPath, areaDefinition.getTemplateScript(), renderType);
135 validateRenderType(problems, areaPath, renderType);
136 validateModelClass(problems, areaPath, areaDefinition.getModelClass());
137 areaDefinition.getAreas().forEach(((areaName, area) -> validateArea(definitionProvider, problems, areaPath, area)));
138 }
139
140 private void validateTemplateScript(Collection<DefinitionProvider.Problem> problems, String rootPath, String scriptPath, String renderType) {
141 if (("freemarker".equals(renderType) || "site".equals(renderType)) &&
142 scriptPath != null && (!scriptPath.startsWith("/") || !resourceOrigin.hasPath(scriptPath))) {
143 problems.add(major()
144 .withType(DefinitionProvider.Problem.DefaultTypes.REFERENCES)
145 .withTitle("Template script definition problem")
146 .withDetails("Resource {" + scriptPath + "} does not exist.")
147 .withLocation(rootPath + "templateScript")
148 .build());
149 }
150 }
151
152 private void validateRenderType(Collection<DefinitionProvider.Problem> problems, String rootPath, String renderType) {
153 if (renderType != null && rendererRegistry.getAllMetadata().stream().noneMatch(metadata -> metadata.getReferenceId().equals(renderType))) {
154 problems.add(major()
155 .withType(DefinitionProvider.Problem.DefaultTypes.REFERENCES)
156 .withTitle("Template renderer definition problem")
157 .withDetails("Renderer {" + renderType + "} is not registered.")
158 .withLocation(rootPath + "renderType")
159 .build());
160 }
161 }
162
163 private void validateModelClass(Collection<DefinitionProvider.Problem> problems, String rootPath, Class<?> modelClass) {
164 if (modelClass != null && !RenderingModel.class.isAssignableFrom(modelClass)) {
165 problems.add(major()
166 .withType(DefinitionProvider.Problem.DefaultTypes.REFERENCES)
167 .withTitle("Model class definition problem")
168 .withDetails("Model " + modelClass + " is not an instance of " + RenderingModel.class)
169 .withLocation(rootPath + "modelClass")
170 .build());
171 }
172 }
173 }