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