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