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.converters;
35
36 import info.magnolia.config.registry.DefinitionRawView;
37
38 import java.io.InputStreamReader;
39 import java.io.Reader;
40 import java.util.Collection;
41 import java.util.Collections;
42 import java.util.Deque;
43 import java.util.LinkedList;
44 import java.util.List;
45
46 import org.apache.commons.io.IOUtils;
47 import org.apache.commons.lang3.StringUtils;
48
49 import com.google.common.base.Charsets;
50 import com.google.common.base.Optional;
51 import com.google.common.base.Preconditions;
52 import com.google.common.base.Predicate;
53 import com.google.common.collect.ImmutableList;
54 import com.google.common.collect.Iterables;
55 import com.google.common.collect.Lists;
56
57
58
59
60 public class DefinitionRawViewToYamlConverterImpl implements DefinitionRawViewToYamlConverter {
61
62 private ConversionState state = new ConversionState();
63
64 @Override
65 public Reader convert(DefinitionRawView rawView) {
66 List<DefinitionRawView.Property> properties = rawView.properties();
67 Preconditions.checkNotNull(properties, "DefinitionRawView properties should not be null");
68
69 this.state = new ConversionState();
70 processProperties(properties);
71
72 return new InputStreamReader(IOUtils.toInputStream(state.conversionResult()), Charsets.UTF_8);
73 }
74
75 private void processProperties(Collection<DefinitionRawView.Property> properties) {
76 final List<DefinitionRawView.Property> elements = Lists.newArrayList();
77
78 for (DefinitionRawView.Property property : properties) {
79 switch (property.getKind()) {
80 case simple:
81 state.printProperty(property.getName(), property.getSimpleValue());
82 break;
83 case subBean:
84 case collection:
85 elements.add(property);
86 break;
87 }
88 }
89
90
91 for (DefinitionRawView.Property element : elements) {
92
93
94 if (!state.isProcessingCollection()) {
95 state.printProperty(element.getName(), "");
96 }
97
98 final Collection<DefinitionRawView.Property> childProperties = resolveProperties(element);
99
100 state.beginElement(element.getKind());
101 processProperties(childProperties);
102 state.finishCurrentElement();
103 }
104 }
105
106 private Collection<DefinitionRawView.Property> resolveProperties(DefinitionRawView.Property rawViewProperty) {
107 switch (rawViewProperty.getKind()) {
108 case collection:
109 return rawViewProperty.getCollection();
110 case subBean:
111 final List<DefinitionRawView.Property> properties = rawViewProperty.getSubRawView().properties();
112
113
114 if (state.isProcessingCollection()) {
115 final Optional<DefinitionRawView.Property> nameProperty = Iterables.tryFind(properties, new IsNameProperty());
116 if (!nameProperty.isPresent()) {
117 return ImmutableList.<DefinitionRawView.Property>builder().
118 add(DefinitionRawView.Property.simple("name", rawViewProperty.getName())).
119 addAll(properties).build();
120 }
121 }
122 return properties;
123 default:
124 return Collections.emptySet();
125 }
126 }
127
128 private static class ConversionState {
129
130 private static final String SINGLE_TAB = " ";
131 private static final String NEW_LINE = System.lineSeparator();
132
133 private StringBuilder yamlBuffer = new StringBuilder();
134 private Deque<DefinitionRawView.Kind> elementKinds = new LinkedList<>();
135 private int nestedCollectionDepth = 0;
136
137 void beginElement(DefinitionRawView.Kind kind) {
138 if (isProcessingCollection()) {
139 ++nestedCollectionDepth;
140 }
141 elementKinds.push(kind);
142 }
143
144 void finishCurrentElement() {
145 elementKinds.pop();
146 nestedCollectionDepth = 0;
147 }
148
149 void printProperty(String propertyName, String value) {
150 indent();
151 keyValue(propertyName, value);
152 newLine();
153 }
154
155 String conversionResult() {
156 return yamlBuffer.toString();
157 }
158
159 private void keyValue(String propertyName, String value) {
160 if (nestedCollectionDepth > 0) {
161 for (int i = 0; i < nestedCollectionDepth; ++i) {
162 collectionElementModifier();
163 }
164
165 nestedCollectionDepth = 0;
166 }
167
168 yamlBuffer.append(propertyName).append(":");
169 if (!StringUtils.isBlank(value)) {
170 yamlBuffer.append(" ").append(value);
171 }
172 }
173
174 private void collectionElementModifier() {
175 yamlBuffer.append("- ");
176 }
177
178 private void indent() {
179 final int indentLength = depth() - nestedCollectionDepth;
180 for (int i = 0; i < indentLength; ++i) {
181 yamlBuffer.append(SINGLE_TAB);
182 }
183 }
184
185 private boolean isProcessingCollection() {
186 return elementKinds.peek() == DefinitionRawView.Kind.collection;
187 }
188
189 private int depth() {
190 return elementKinds.size();
191 }
192
193 private void newLine() {
194 yamlBuffer.append(NEW_LINE);
195 }
196 }
197
198 private static class IsNameProperty implements Predicate<DefinitionRawView.Property> {
199 @Override
200 public boolean apply(DefinitionRawView.Property property) {
201 return "name".equals(property.getName());
202 }
203 }
204 }