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.jcr.node2bean.impl;
35
36 import info.magnolia.jcr.decoration.ContentDecorator;
37 import info.magnolia.jcr.iterator.FilteringPropertyIterator;
38 import info.magnolia.jcr.node2bean.Node2BeanException;
39 import info.magnolia.jcr.node2bean.Node2BeanProcessor;
40 import info.magnolia.jcr.node2bean.Node2BeanTransformer;
41 import info.magnolia.jcr.node2bean.PropertyTypeDescriptor;
42 import info.magnolia.jcr.node2bean.TransformationState;
43 import info.magnolia.jcr.node2bean.TypeDescriptor;
44 import info.magnolia.jcr.node2bean.TypeMapping;
45 import info.magnolia.jcr.predicate.AbstractPredicate;
46 import info.magnolia.jcr.util.NodeTypes;
47 import info.magnolia.jcr.util.NodeUtil;
48 import info.magnolia.jcr.util.PropertyUtil;
49 import info.magnolia.jcr.wrapper.ExtendingNodeWrapper;
50 import info.magnolia.objectfactory.ComponentProvider;
51 import info.magnolia.objectfactory.Components;
52
53 import java.util.Collection;
54 import java.util.LinkedHashMap;
55 import java.util.Map;
56
57 import javax.inject.Inject;
58 import javax.inject.Singleton;
59 import javax.jcr.Node;
60 import javax.jcr.NodeIterator;
61 import javax.jcr.Property;
62 import javax.jcr.PropertyIterator;
63 import javax.jcr.RepositoryException;
64
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
67
68
69
70
71 @Singleton
72 public class Node2BeanProcessorImpl implements Node2BeanProcessor {
73 private static final Logger log = LoggerFactory.getLogger(Node2BeanProcessorImpl.class);
74
75 private final TypeMapping typeMapping;
76
77 private final Node2BeanTransformer defaultTransformer;
78
79 private boolean forceCreation = true;
80
81 @Inject
82 public Node2BeanProcessorImpl(TypeMapping typeMapping, Node2BeanTransformer transformer) {
83 this.typeMapping = typeMapping;
84 this.defaultTransformer = transformer;
85 }
86
87 @Override
88 public Object toBean(Node node) throws Node2BeanException, RepositoryException {
89 return toBean(node, true, defaultTransformer, defaultTransformer.newState(), Components.getComponentProvider());
90 }
91
92 @Override
93 public Object toBean(Node node, final Class<?> defaultClass) throws Node2BeanException, RepositoryException {
94 return toBean(node, true, new Node2BeanTransformerImpl() {
95 @Override
96 protected TypeDescriptor onResolveType(TypeMapping mapping, TransformationState state, TypeDescriptor resolvedType, ComponentProvider componentProvider) {
97 if(resolvedType==null && state.getLevel() == 1){
98 return mapping.getTypeDescriptor(defaultClass);
99 }
100 return resolvedType;
101 }
102 }, defaultTransformer.newState(), Components.getComponentProvider());
103 }
104
105 @Override
106 public Object toBean(Node node, boolean recursive, final Node2BeanTransformer transformer, ComponentProvider componentProvider) throws Node2BeanException, RepositoryException {
107 return toBean(node, recursive, transformer, transformer.newState(), componentProvider);
108 }
109
110 protected Object toBean(Node node, boolean recursive, Node2BeanTransformer transformer, TransformationState state, ComponentProvider componentProvider) throws Node2BeanException, RepositoryException{
111 if (!NodeUtil.isWrappedWith(node, ExtendingNodeWrapper.class)) {
112 node = new ExtendingNodeWrapper(node);
113 }
114 state.pushNode(node);
115 TypeDescriptor type = null;
116 try {
117 type = transformer.resolveType(typeMapping, state, componentProvider);
118 } catch (Throwable e) {
119 if(isForceCreation()){
120 log.warn("can't resolve class for node " + node.getPath(), e);
121 } else {
122 throw new Node2BeanException("can't resolve class for node " + node.getPath(), e);
123 }
124 }
125
126 Object bean = null;
127 if (type != null) {
128 state.pushType(type);
129
130 transformer = resolveTransformer(type, transformer);
131
132 Map<String, Object> values = toMap(node, recursive, transformer, state, componentProvider);
133
134 try {
135 bean = transformer.newBeanInstance(state, values, componentProvider);
136 } catch (Throwable e) {
137 if(isForceCreation()){
138 log.warn("Can't instantiate bean for " + node.getPath(), e);
139 } else {
140 throw new Node2BeanException("Can't instantiate bean for " + node.getPath(), e);
141 }
142 }
143
144 if (bean != null) {
145 state.pushBean(bean);
146
147 setProperties(values, transformer, state);
148
149 transformer.initBean(state, values);
150
151 bean = state.getCurrentBean();
152
153 state.popBean();
154 } else {
155 if(forceCreation){
156 log.warn("can't instantiate bean of type " + type.getType().getName() + " for node " + node.getPath());
157 } else {
158 throw new Node2BeanException("can't instantiate bean of type " + type.getType().getName());
159 }
160 }
161
162 state.popType();
163 }
164 state.popNode();
165
166 return bean;
167 }
168
169 @Override
170 public Object setProperties(final Object bean, Node node, boolean recursive, Node2BeanTransformer transformer, ComponentProvider componentProvider) throws Node2BeanException, RepositoryException {
171
172 node = new ExtendingNodeWrapper(node);
173
174 TransformationState state = transformer.newState();
175 state.pushBean(bean);
176 state.pushNode(node);
177
178 TypeDescriptor type = typeMapping.getTypeDescriptor(bean.getClass());
179
180 state.pushType(type);
181
182 transformer = resolveTransformer(type, transformer);
183
184 Map<String, Object> values = toMap(node, recursive, transformer, state, componentProvider);
185
186 setProperties(values, transformer, state);
187
188 transformer.initBean(state, values);
189
190 state.popBean();
191 state.popType();
192 state.popNode();
193
194 return bean;
195 }
196
197
198
199
200
201 protected Map<String, Object> toMap(Node node, boolean recursive, Node2BeanTransformer transformer, TransformationState state, ComponentProvider componentProvider) throws Node2BeanException, RepositoryException {
202 Map<String, Object> map = new LinkedHashMap<String, Object>();
203 PropertyIterator it = new FilteringPropertyIterator(node.getProperties(), new AbstractPredicate<Property>() {
204 @Override
205 public boolean evaluateTyped(Property t) {
206 try {
207 return !(t.getName().startsWith(NodeTypes.JCR_PREFIX) || t.getName().startsWith(NodeTypes.MGNL_PREFIX));
208 } catch (RepositoryException e) {
209 return false;
210 }
211 }
212 }, (ContentDecorator) null);
213 while (it.hasNext()) {
214 Property p = it.nextProperty();
215 Object val = PropertyUtil.getValueObject(p.getValue());
216 if (val != null) {
217 map.put(p.getName(), val);
218 }
219 }
220 if(recursive){
221 final NodeIterator children = transformer.getChildren(node);
222
223 while (children.hasNext()) {
224 Node childNode = (Node) children.next();
225
226
227
228 Object childBean = toBean(childNode, true, transformer, state, componentProvider);
229
230 if(childBean != null){
231 String name = childNode.getName();
232 try {
233 if(childNode.getIndex() > 1){
234 name += childNode.getIndex();
235 }
236 }
237 catch (RepositoryException e) {
238 log.error("can't read index of the node [" + childNode + "]", e);
239 }
240 map.put(name, childBean);
241 }
242 }
243 }
244
245 return map;
246 }
247
248
249
250
251
252
253 protected void setProperties(Map<String, Object> values, final Node2BeanTransformer transformer, TransformationState state) throws Node2BeanException, RepositoryException {
254 Object bean = state.getCurrentBean();
255 log.debug("will populate bean {} with the values {}", bean.getClass().getName(), values);
256
257 if (bean instanceof Map) {
258 ((Map<String, Object>)bean).putAll(values);
259 }
260
261 if (bean instanceof Collection) {
262 ((Collection<Object>)bean).addAll(values.values());
263 } else {
264 TypeDescriptor beanTypeDescriptor = typeMapping.getTypeDescriptor(bean.getClass());
265 final Collection<PropertyTypeDescriptor> dscrs = beanTypeDescriptor.getPropertyDescriptors(typeMapping).values();
266
267 for (PropertyTypeDescriptor descriptor : dscrs) {
268 transformer.setProperty(typeMapping, state, descriptor, values);
269 }
270 }
271 }
272
273
274
275
276
277
278
279 protected Node2BeanTransformer resolveTransformer(TypeDescriptor type, Node2BeanTransformer transformer) {
280 Node2BeanTransformer customTransformer = type.getTransformer();
281 if(customTransformer != null){
282 transformer = customTransformer;
283 }
284 return transformer;
285 }
286
287 public boolean isForceCreation() {
288 return this.forceCreation;
289 }
290
291 public void setForceCreation(boolean forceCreation) {
292 this.forceCreation = forceCreation;
293 }
294 }