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.decoration;
35
36 import static info.magnolia.config.converters.RawDefinitionViewToMapConverter.rawViewToMap;
37 import static info.magnolia.config.maputil.ToMap.toMap;
38 import static info.magnolia.config.registry.DefinitionProvider.Problem.DefaultTypes.DECORATION;
39
40 import info.magnolia.cms.util.ExceptionUtil;
41 import info.magnolia.config.maputil.ConfigurationMapOverlay;
42 import info.magnolia.config.registry.DefinitionProvider;
43 import info.magnolia.config.registry.DefinitionProviderBuilder;
44 import info.magnolia.config.registry.DefinitionProviderProblemLogger;
45 import info.magnolia.config.registry.DefinitionReferenceIdResolver;
46 import info.magnolia.config.registry.decoration.DefinitionDecorator;
47 import info.magnolia.config.source.DefinitionProviderWrapperWithProxyFallback;
48 import info.magnolia.config.source.raw.DefinitionRawViewMapWrapper;
49 import info.magnolia.config.source.yaml.YamlReader;
50 import info.magnolia.init.MagnoliaConfigurationProperties;
51 import info.magnolia.map2bean.Map2BeanTransformer;
52 import info.magnolia.objectfactory.Components;
53 import info.magnolia.resourceloader.Resource;
54 import info.magnolia.transformer.TransformationResult;
55
56 import java.util.HashMap;
57 import java.util.Map;
58 import java.util.Optional;
59
60 import org.apache.commons.lang3.exception.ExceptionUtils;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 import com.google.common.collect.ImmutableList;
65
66 import lombok.SneakyThrows;
67
68
69
70
71
72
73
74 public class YamlDefinitionDecorator<T> extends AbstractFileDefinitionDecorator<T> {
75
76 private static final Logger log = LoggerFactory.getLogger(YamlDefinitionDecorator.class);
77
78 private final YamlReader yamlReader;
79
80 private final Resource yamlFile;
81
82 private final MagnoliaConfigurationProperties magnoliaConfigurationProperties;
83
84 private final YamlDefinitionDecoratorMetadata metadata;
85
86 private final DefinitionReferenceIdResolver referenceIdResolver;
87
88 private final Map2BeanTransformer map2BeanTransformer;
89
90
91
92
93 @Deprecated
94 public YamlDefinitionDecorator(
95 YamlDefinitionDecoratorMetadata metadata,
96 DefinitionReferenceIdResolver referenceIdResolver,
97 Resource decoratorYamlFile,
98 Map2BeanTransformer map2BeanTransformer) {
99 this(metadata, referenceIdResolver, decoratorYamlFile, map2BeanTransformer, Components.getComponent(MagnoliaConfigurationProperties.class));
100 }
101
102 public YamlDefinitionDecorator(
103 YamlDefinitionDecoratorMetadata metadata,
104 DefinitionReferenceIdResolver referenceIdResolver,
105 Resource decoratorYamlFile,
106 Map2BeanTransformer map2BeanTransformer,
107 MagnoliaConfigurationProperties magnoliaConfigurationProperties) {
108 this.yamlFile = decoratorYamlFile;
109 this.magnoliaConfigurationProperties = magnoliaConfigurationProperties;
110 this.yamlReader = new YamlReader();
111 this.metadata = metadata;
112 this.referenceIdResolver = referenceIdResolver;
113 this.map2BeanTransformer = map2BeanTransformer;
114 }
115
116 @Override
117 public Resource getDecoratorFile() {
118 return yamlFile;
119 }
120
121 @Override
122 public YamlDefinitionDecoratorMetadata metadata() {
123 return metadata;
124 }
125
126 @Override
127 public boolean appliesTo(DefinitionProvider<T> definitionProvider) {
128 return definitionProvider.getMetadata().getReferenceId().equals(referenceIdResolver.getReferenceId(metadata.getDecoratedDefinitionReference()));
129 }
130
131 @Override
132 public DefinitionProvider<T> decorate(final DefinitionProvider<T> definitionProvider) {
133 final DefinitionProviderBuilder<T> definitionProviderBuilder = DefinitionProviderBuilder.newBuilder();
134
135 Map<String, Object> decoratedMapRepresentation;
136 try {
137 final Map<String, Object> decoratorData = parseYamlFile();
138
139 if (decoratorData.isEmpty()) {
140 definitionProviderBuilder
141 .addProblem(
142 DefinitionProvider.Problem
143 .major()
144 .withType(DECORATION)
145 .withTitle(String.format("Decoration data from [%s] is empty", yamlFile.getPath()))
146 .build());
147 }
148
149 decoratedMapRepresentation = ConfigurationMapOverlay
150 .of(rawViewToMap(definitionProvider.getRaw()))
151 .by(decoratorData)
152 .at(metadata.getDecoratedPath())
153 .overlay();
154
155 } catch (Exception e) {
156 decoratedMapRepresentation = new HashMap<>();
157 definitionProviderBuilder.addProblem(
158 DefinitionProvider.Problem
159 .major()
160 .withType(DECORATION)
161 .withTitle(String.format("Failed to parse decoration data from [%s]", yamlFile.getPath()))
162 .withRelatedException(e)
163 .withDetails(ExceptionUtil.exceptionToWords(
164 Optional
165 .ofNullable(ExceptionUtils.getRootCause(e))
166 .orElse(e)))
167 .build());
168 }
169
170
171 final TransformationResult<T> transformationResult =
172 map2BeanTransformer
173 .transform(decoratedMapRepresentation, definitionProvider.getMetadata().getType().baseClass());
174
175 final DefinitionProvider<T> decoratedDefinitionProvider = definitionProviderBuilder
176 .metadata(definitionProvider.getMetadata())
177 .rawView(new DefinitionRawViewMapWrapper(decoratedMapRepresentation))
178 .decorators(ImmutableList
179 .<DefinitionDecorator<T>>builder()
180 .addAll(definitionProvider.getDecorators())
181 .add(YamlDefinitionDecorator.this)
182 .build())
183 .buildFromTransformationResult(transformationResult);
184
185 log.info("Applied {} to definition provider [{}]", this, definitionProvider.getMetadata());
186
187 DefinitionProviderProblemLogger.withLoggingContext(log, magnoliaConfigurationProperties.getBooleanProperty("magnolia.develop")).logProblems(decoratedDefinitionProvider);
188
189 return new DefinitionProviderWrapperWithProxyFallback<>(decoratedDefinitionProvider, definitionProvider.get());
190 }
191
192 @SneakyThrows
193
194 protected final Map<String, Object> parseYamlFile() {
195 return toMap(yamlReader.read(yamlFile));
196 }
197
198 @Override
199 public String toString() {
200 return String.format("YAML file based decorator from [%s]", yamlFile.getPath());
201 }
202 }