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 validateRenderType(problems, "", definition.getRenderType());
88 validateTemplateScript(problems, "", definition.getTemplateScript());
89 validateModelClass(problems, "", definition.getModelClass());
90 definition.getAreas().forEach((areaName, area) -> validateArea(definitionProvider, problems, "", area));
91 }
92
93 protected void validateArea(DefinitionProvider<TemplateDefinition> definitionProvider, Collection<DefinitionProvider.Problem> problems, String rootPath, AreaDefinition areaDefinition) {
94 final String areaPath = rootPath + "areas/" + areaDefinition.getName() + "/";
95
96 areaDefinition.getAvailableComponents().forEach((componentName, componentAvailability) -> {
97 Optional<DefinitionMetadata> componentMetadataOptional = templateDefinitionRegistryProvider.get().getAllMetadata().stream()
98 .filter(metadata -> metadata.getReferenceId().equals(componentAvailability.getId()))
99 .findAny();
100
101 if (!componentMetadataOptional.isPresent()) {
102 problems.add(major().withType(DefinitionProvider.Problem.DefaultTypes.REFERENCES)
103 .withTitle("Template availability problem")
104 .withDetails("Template {" + componentAvailability.getId() + "} is not registered.")
105 .withLocation(areaPath + "availableComponents/" + componentName)
106 .build());
107 }
108
109 else if (!definitionProvider.getMetadata().getDeprecation().isPresent() && componentMetadataOptional.get().getDeprecation().isPresent()) {
110 DefinitionMetadata componentMetadata = componentMetadataOptional.get();
111 componentMetadata.getDeprecation().ifPresent(deprecation -> {
112 String deprecationMessage = getDeprecationMessage(DefinitionTypes.TEMPLATE.getName(), componentMetadata.getName(), deprecation.since(), deprecation.description());
113
114 problems.add(minor().withTitle("Deprecated definition usage")
115 .withDetails(deprecationMessage)
116 .withLocation(areaPath + "availableComponents/" + componentName)
117 .withType(RESOLUTION)
118 .build());
119 });
120 }
121 }
122 );
123 validateTemplateScript(problems, areaPath, areaDefinition.getTemplateScript());
124 validateRenderType(problems, areaPath, areaDefinition.getRenderType());
125 validateModelClass(problems, areaPath, areaDefinition.getModelClass());
126 areaDefinition.getAreas().forEach(((areaName, area) -> validateArea(definitionProvider, problems, areaPath, area)));
127 }
128
129 private void validateTemplateScript(Collection<DefinitionProvider.Problem> problems, String rootPath, String scriptPath) {
130 if (scriptPath != null && (!scriptPath.startsWith("/") || !resourceOrigin.hasPath(scriptPath))) {
131 problems.add(major()
132 .withType(DefinitionProvider.Problem.DefaultTypes.REFERENCES)
133 .withTitle("Template script definition problem")
134 .withDetails("Resource {" + scriptPath + "} does not exist.")
135 .withLocation(rootPath + "templateScript")
136 .build());
137 }
138 }
139
140 private void validateRenderType(Collection<DefinitionProvider.Problem> problems, String rootPath, String renderType) {
141 if (renderType != null && rendererRegistry.getAllMetadata().stream().noneMatch(metadata -> metadata.getReferenceId().equals(renderType))) {
142 problems.add(major()
143 .withType(DefinitionProvider.Problem.DefaultTypes.REFERENCES)
144 .withTitle("Template renderer definition problem")
145 .withDetails("Renderer {" + renderType + "} is not registered.")
146 .withLocation(rootPath + "renderType")
147 .build());
148 }
149 }
150
151 private void validateModelClass(Collection<DefinitionProvider.Problem> problems, String rootPath, Class<?> modelClass) {
152 if (modelClass != null && !RenderingModel.class.isAssignableFrom(modelClass)) {
153 problems.add(major()
154 .withType(DefinitionProvider.Problem.DefaultTypes.REFERENCES)
155 .withTitle("Model class definition problem")
156 .withDetails("Model " + modelClass + " is not an instance of " + RenderingModel.class)
157 .withLocation(rootPath + "modelClass")
158 .build());
159 }
160 }
161 }