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