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