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