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.content2bean.impl;
35
36 import info.magnolia.cms.core.Content;
37 import info.magnolia.cms.core.NodeData;
38 import info.magnolia.cms.util.ExtendingContentWrapper;
39 import info.magnolia.cms.util.NodeDataUtil;
40 import info.magnolia.content2bean.Content2BeanException;
41 import info.magnolia.content2bean.Content2BeanProcessor;
42 import info.magnolia.content2bean.Content2BeanTransformer;
43 import info.magnolia.content2bean.PropertyTypeDescriptor;
44 import info.magnolia.content2bean.TransformationState;
45 import info.magnolia.content2bean.TypeDescriptor;
46 import info.magnolia.content2bean.TypeMapping;
47 import info.magnolia.objectfactory.ComponentProvider;
48
49 import java.util.Collection;
50 import java.util.LinkedHashMap;
51 import java.util.Map;
52
53 import javax.inject.Inject;
54 import javax.inject.Singleton;
55 import javax.jcr.RepositoryException;
56
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60
61
62
63
64
65 @Singleton
66 public class Content2BeanProcessorImpl implements Content2BeanProcessor {
67 private static final Logger log = LoggerFactory.getLogger(Content2BeanProcessorImpl.class);
68
69 private final TypeMapping typeMapping;
70
71 private boolean forceCreation = true;
72
73 @Inject
74 public Content2BeanProcessorImpl(TypeMapping typeMapping) {
75 this.typeMapping = typeMapping;
76 }
77
78 @Override
79 public Object toBean(Content node, boolean recursive, final Content2BeanTransformer transformer, ComponentProvider componentProvider) throws Content2BeanException {
80 return toBean(new ExtendingContentWrapper(node), recursive, transformer, transformer.newState(), componentProvider);
81 }
82
83 protected Object toBean(Content node, boolean recursive, Content2BeanTransformer transformer, TransformationState state, ComponentProvider componentProvider) throws Content2BeanException {
84
85 state.pushContent(node);
86
87 TypeDescriptor type = null;
88 try {
89 type = transformer.resolveType(typeMapping, state, componentProvider);
90 } catch (Throwable e) {
91 if (isForceCreation()) {
92 log.warn("can't resolve class for node {}", node.getHandle(), e);
93 } else {
94 throw new Content2BeanException("can't resolve class for node " + node.getHandle(), e);
95 }
96 }
97
98 Object bean = null;
99 if (type != null) {
100 state.pushType(type);
101
102 transformer = resolveTransformer(type, transformer);
103
104 Map<String, Object> values = toMap(node, recursive, transformer, state, componentProvider);
105
106 try {
107 bean = transformer.newBeanInstance(state, values, componentProvider);
108 } catch (Throwable e) {
109 if (isForceCreation()) {
110 log.warn("Can't instantiate bean for {}", node.getHandle(), e);
111 } else {
112 throw new Content2BeanException("Can't instantiate bean for " + node.getHandle(), e);
113 }
114 }
115
116 if (bean != null) {
117 state.pushBean(bean);
118
119 setProperties(values, transformer, state);
120
121 transformer.initBean(state, values);
122
123 bean = state.getCurrentBean();
124
125 state.popBean();
126 } else {
127 if (forceCreation) {
128 log.warn("can't instantiate bean of type {} for node {}", type.getType().getName(), node.getHandle());
129 } else {
130 throw new Content2BeanException("can't instantiate bean of type " + type.getType().getName());
131 }
132 }
133
134 state.popType();
135 }
136 state.popContent();
137
138 return bean;
139 }
140
141 @Override
142 public Object setProperties(final Object bean, Content node, boolean recursive, Content2BeanTransformer transformer, ComponentProvider componentProvider) throws Content2BeanException {
143
144 node = new ExtendingContentWrapper(node);
145
146 TransformationState state = transformer.newState();
147 state.pushBean(bean);
148 state.pushContent(node);
149
150
151 TypeDescriptor type = typeMapping.getTypeDescriptor(bean.getClass());
152
153 state.pushType(type);
154
155 transformer = resolveTransformer(type, transformer);
156
157 Map<String, Object> values = toMap(node, recursive, transformer, state, componentProvider);
158
159 setProperties(values, transformer, state);
160
161 transformer.initBean(state, values);
162
163 state.popBean();
164 state.popType();
165 state.popContent();
166
167 return bean;
168 }
169
170
171
172
173 protected Map<String, Object> toMap(Content node, boolean recursive, Content2BeanTransformer transformer, TransformationState state, ComponentProvider componentProvider) throws Content2BeanException {
174 Map<String, Object> map = new LinkedHashMap<String, Object>();
175 for (NodeData nd : node.getNodeDataCollection()) {
176 Object val = NodeDataUtil.getValueObject(nd);
177 if (val != null) {
178 map.put(nd.getName(), val);
179 }
180 }
181
182 if (recursive) {
183 final Collection<Content> children = transformer.getChildren(node);
184 for (Content childNode : children) {
185
186
187
188 Object childBean = toBean(childNode, true, transformer, state, componentProvider);
189
190 if (childBean != null) {
191 String name = childNode.getName();
192 try {
193 if (childNode.getIndex() > 1) {
194 name += childNode.getIndex();
195 }
196 } catch (RepositoryException e) {
197 log.error("can't read index of the node [{}]", childNode, e);
198 }
199 map.put(name, childBean);
200 }
201 }
202 }
203
204 return map;
205 }
206
207
208
209
210
211
212 protected void setProperties(Map<String, Object> values, final Content2BeanTransformer transformer, TransformationState state) throws Content2BeanException {
213 Object bean = state.getCurrentBean();
214 log.debug("will populate bean {} with the values {}", bean.getClass().getName(), values);
215
216 if (bean instanceof Map) {
217 ((Map<String, Object>) bean).putAll(values);
218 }
219
220 if (bean instanceof Collection) {
221 ((Collection<Object>) bean).addAll(values.values());
222 } else {
223
224 TypeDescriptor beanTypeDescriptor = typeMapping.getTypeDescriptor(bean.getClass());
225 final Collection<PropertyTypeDescriptor> dscrs = beanTypeDescriptor.getPropertyDescriptors(typeMapping).values();
226
227 for (PropertyTypeDescriptor descriptor : dscrs) {
228 transformer.setProperty(typeMapping, state, descriptor, values);
229 }
230 }
231 }
232
233 protected Content2BeanTransformer resolveTransformer(TypeDescriptor type, Content2BeanTransformer transformer) {
234 Content2BeanTransformer customTransformer = type.getTransformer();
235 if (customTransformer != null) {
236 transformer = customTransformer;
237 }
238 return transformer;
239 }
240
241 public boolean isForceCreation() {
242 return this.forceCreation;
243 }
244
245
246
247
248 public void setForceCreation(boolean handleExceptions) {
249 this.forceCreation = handleExceptions;
250 }
251
252 }