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;
35
36 import info.magnolia.config.registry.DefinitionProvider;
37 import info.magnolia.config.registry.Registry;
38 import info.magnolia.config.source.AbstractConfigurationSourceBuilder;
39 import info.magnolia.init.MagnoliaConfigurationProperties;
40 import info.magnolia.map2bean.Map2BeanTransformer;
41 import info.magnolia.module.ModuleRegistry;
42 import info.magnolia.objectfactory.Components;
43 import info.magnolia.resourceloader.ResourceOrigin;
44
45 import java.util.HashMap;
46 import java.util.Map;
47 import java.util.function.Consumer;
48 import java.util.function.Function;
49 import java.util.regex.Pattern;
50 import java.util.regex.PatternSyntaxException;
51
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54 import org.yaml.snakeyaml.constructor.Construct;
55
56
57
58
59 public class YamlConfigurationSourceBuilder extends AbstractConfigurationSourceBuilder {
60
61 private static final Logger log = LoggerFactory.getLogger(YamlConfigurationSourceBuilder.class);
62
63
64
65
66
67
68 private static final String MODULE_CONVENTIONS_FORMAT = "^/(?<module>[a-zA-Z0-9-_]+)/(?<deftype>%s)/(?<relPath>.*/)?(?<name>[a-zA-Z0-9-_\\.]+)\\.yaml$";
69
70 private final ResourceOrigin origin;
71 private final YamlReader yamlReader;
72 private final MagnoliaConfigurationProperties magnoliaConfigurationProperties;
73 private final Map2BeanTransformer map2BeanTransformer;
74 private final ModuleRegistry moduleRegistry;
75 private final Map<String, Function<Consumer<DefinitionProvider.Problem>, Construct>> customConstructs = new HashMap<>();
76 private final Map<String, Function<Consumer<DefinitionProvider.Problem>, Construct>> customMultiConstructs = new HashMap<>();
77 private String pathPattern;
78
79 public YamlConfigurationSourceBuilder(ResourceOrigin origin, Map2BeanTransformer map2BeanTransformer, YamlReader yamlReader, MagnoliaConfigurationProperties magnoliaConfigurationProperties, ModuleRegistry moduleRegistry) {
80 this.origin = origin;
81 this.map2BeanTransformer = map2BeanTransformer;
82 this.yamlReader = yamlReader;
83 this.magnoliaConfigurationProperties = magnoliaConfigurationProperties;
84 this.moduleRegistry = moduleRegistry;
85 }
86
87
88
89
90 @Deprecated
91 public YamlConfigurationSourceBuilder(ResourceOrigin origin, info.magnolia.config.map2bean.Map2BeanTransformer map2BeanTransformer, YamlReader yamlReader) {
92 this(origin, map2BeanTransformer, yamlReader, Components.getComponent(MagnoliaConfigurationProperties.class), Components.getComponent(ModuleRegistry.class));
93 }
94
95
96
97
98 @Deprecated
99 public YamlConfigurationSourceBuilder(ResourceOrigin origin, Map2BeanTransformer map2BeanTransformer, YamlReader yamlReader, MagnoliaConfigurationProperties magnoliaConfigurationProperties) {
100 this(origin, map2BeanTransformer, yamlReader, magnoliaConfigurationProperties, Components.getComponent(ModuleRegistry.class));
101 }
102
103 public YamlConfigurationSourceBuilder withPattern(String pathPattern) {
104 this.pathPattern = pathPattern;
105 return this;
106 }
107
108 public YamlConfigurationSourceBuilder withCustomConstruct(String tag, Function<Consumer<DefinitionProvider.Problem>, Construct> constructSupplier) {
109 this.customConstructs.put(tag, constructSupplier);
110 return this;
111 }
112
113 public YamlConfigurationSourceBuilder withCustomMultiConstruct(String tagPrefix, Function<Consumer<DefinitionProvider.Problem>, Construct> constructSupplier) {
114 this.customMultiConstructs.put(tagPrefix, constructSupplier);
115 return this;
116 }
117
118 public YamlConfigurationSourceBuilder withCustomMultiConstruct(String tagPrefix, Construct construct) {
119 this.yamlReader.registerCustomMultiConstruct(tagPrefix, construct);
120 return this;
121 }
122
123 public YamlConfigurationSourceBuilder withCustomConstruct(String tag, Construct construct) {
124 this.yamlReader.registerCustomConstruct(tag, construct);
125 return this;
126 }
127
128 @Override
129 public void bindTo(Registry<?> registry) {
130 final Pattern pathPattern = validatePathPattern(this.pathPattern);
131 if (registry == null) {
132 throw new NullPointerException("Must pass a registry instance");
133 }
134
135 new YamlConfigurationSource<>(origin, map2BeanTransformer, registry, pathPattern, yamlReader, magnoliaConfigurationProperties, moduleRegistry, customConstructs, customMultiConstructs).start();
136 }
137
138 public void bindWithDefaults(Registry registry) {
139 if (pathPattern != null) {
140 throw new IllegalStateException(this + " is already partially configured, don't use bindWithDefaults().");
141 }
142 withPattern(moduleConventionsFormatFor(registry)).bindTo(registry);
143 }
144
145 protected Pattern validatePathPattern(String regex) {
146 if (pathPattern == null) {
147 throw new IllegalStateException(this + " is incomplete.");
148 }
149 try {
150
151 return Pattern.compile(regex);
152 } catch (PatternSyntaxException e) {
153 log.warn("Pattern {} is invalid: {}", regex, e.getMessage());
154 return Pattern.compile("$^");
155 }
156 }
157
158
159 protected String moduleConventionsFormatFor(Registry registry) {
160 return String.format(MODULE_CONVENTIONS_FORMAT, registry.type().getPluralName());
161 }
162
163 }