1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.portals.graffito.jcr.persistence.collectionconverter.impl;
18
19
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Map;
25
26 import javax.jcr.Node;
27 import javax.jcr.NodeIterator;
28 import javax.jcr.RepositoryException;
29 import javax.jcr.Session;
30
31 import org.apache.portals.graffito.jcr.exception.JcrMappingException;
32 import org.apache.portals.graffito.jcr.mapper.Mapper;
33 import org.apache.portals.graffito.jcr.mapper.model.ClassDescriptor;
34 import org.apache.portals.graffito.jcr.mapper.model.CollectionDescriptor;
35 import org.apache.portals.graffito.jcr.persistence.collectionconverter.ManageableCollection;
36 import org.apache.portals.graffito.jcr.persistence.collectionconverter.ManageableCollectionUtil;
37 import org.apache.portals.graffito.jcr.persistence.objectconverter.ObjectConverter;
38 import org.apache.portals.graffito.jcr.reflection.ReflectionUtils;
39
40 /***
41 * Default Collection Mapping/convertion implementation.
42 *
43 * This collection mapping strategy maps a collection under an extra JCR node (specify by the jcrName in the CollectionDescriptor).
44 * It is usefull when the node type "nt:unstructured" is applied to the collection elements. By this way, it is possible
45 * to distinguish the collection elements from the other main object fields.
46 *
47 * If the collection element class contains an id (see the FieldDescriptor definition), this id value is used to build the collection element node.
48 * Otherwise, the element node name is a simple indexed constant.
49 *
50 * Example - without an id attribute:
51 * /test (Main object containing the collection field )
52 * /mycollection (extra node used to store the entire collection)
53 * /collection-element (node used to store the first collection element)
54 * /item-prop
55 * ....
56 * /collection-element (node used to store the second collection element)
57 * ...
58 *
59 * Example - with an id attribute:
60 * /test (Main object containing the collection field )
61 * /mycollection (extra node used to store the entire collection)
62 * /aValue (id value assigned to the first element)
63 * /item-prop
64 * ....
65 * /anotherValue (id value assigned to the first element)
66 * ...
67
68 * @author <a href="mailto:christophe.lombart@gmail.com">Christophe Lombart</a>
69 * @author <a href='mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu</a>
70 */
71 public class DefaultCollectionConverterImpl extends AbstractCollectionConverterImpl {
72
73 private static final String COLLECTION_ELEMENT_NAME = "collection-element";
74
75 /***
76 * Constructor
77 * @param atomicTypeConverters
78 * @param objectConverter
79 * @param mapper
80 */
81 public DefaultCollectionConverterImpl(Map atomicTypeConverters,
82 ObjectConverter objectConverter,
83 Mapper mapper) {
84 super(atomicTypeConverters, objectConverter, mapper);
85 }
86
87 /***
88 * @see AbstractCollectionConverterImpl#doInsertCollection(Session, Node, CollectionDescriptor, ManageableCollection)
89 */
90 protected void doInsertCollection(Session session,
91 Node parentNode,
92 CollectionDescriptor collectionDescriptor,
93 ManageableCollection collection) throws RepositoryException {
94 if (collection == null) {
95 return;
96 }
97
98 String jcrName = collectionDescriptor.getJcrName();
99
100 if (jcrName == null) {
101 throw new JcrMappingException(
102 "The JcrName attribute is not defined for the CollectionDescriptor : "
103 + collectionDescriptor.getFieldName() + " for the classdescriptor : " + collectionDescriptor.getClassDescriptor().getClassName());
104 }
105
106 Node collectionNode = parentNode.addNode(jcrName);
107
108 ClassDescriptor elementClassDescriptor = mapper.getClassDescriptorByClass( ReflectionUtils.forName(collectionDescriptor.getElementClassName()));
109
110 Iterator collectionIterator = collection.getIterator();
111 while (collectionIterator.hasNext()) {
112 Object item = collectionIterator.next();
113 String elementJcrName = null;
114
115
116 if (elementClassDescriptor.hasIdField()) {
117 String idFieldName = elementClassDescriptor.getIdFieldDescriptor()
118 .getFieldName();
119 elementJcrName = ReflectionUtils.getNestedProperty(item, idFieldName).toString();
120 }
121 else {
122 elementJcrName = COLLECTION_ELEMENT_NAME;
123 }
124
125 objectConverter.insert(session, collectionNode, elementJcrName, item);
126 }
127 }
128
129 /***
130 *
131 * @see AbstractCollectionConverterImpl#doUpdateCollection(Session, Node, CollectionDescriptor, ManageableCollection)
132 */
133 protected void doUpdateCollection(Session session,
134 Node parentNode,
135 CollectionDescriptor collectionDescriptor,
136 ManageableCollection collection) throws RepositoryException {
137
138 String jcrName = getCollectionJcrName(collectionDescriptor);
139 if (collection == null)
140 {
141 if (parentNode.hasNode(jcrName))
142 {
143 parentNode.getNode(jcrName).remove();
144 }
145 return;
146 }
147
148
149 ClassDescriptor elementClassDescriptor = mapper.getClassDescriptorByClass( ReflectionUtils.forName(collectionDescriptor.getElementClassName()));
150 Node collectionNode = parentNode.getNode(jcrName);
151
152 if (!elementClassDescriptor.hasIdField()) {
153 collectionNode.remove();
154 collectionNode = parentNode.addNode(jcrName);
155 }
156
157 Iterator collectionIterator = collection.getIterator();
158
159 Map updatedItems = new HashMap();
160 while (collectionIterator.hasNext()) {
161 Object item = collectionIterator.next();
162
163 String elementJcrName = null;
164
165 if (elementClassDescriptor.hasIdField()) {
166
167 String idFieldName = elementClassDescriptor.getIdFieldDescriptor().getFieldName();
168 elementJcrName = ReflectionUtils.getNestedProperty(item, idFieldName).toString();
169
170
171 if (collectionNode.hasNode(elementJcrName)) {
172 objectConverter.update(session, collectionNode, elementJcrName, item);
173 }
174 else {
175
176 objectConverter.insert(session, collectionNode, elementJcrName, item);
177 }
178
179 updatedItems.put(elementJcrName, item);
180 }
181 else {
182 elementJcrName = COLLECTION_ELEMENT_NAME ;
183 objectConverter.insert(session, collectionNode, elementJcrName, item);
184 }
185 }
186
187
188 if (elementClassDescriptor.hasIdField()) {
189 NodeIterator nodeIterator = collectionNode.getNodes();
190 List removeNodes = new ArrayList();
191 while (nodeIterator.hasNext()) {
192 Node child = nodeIterator.nextNode();
193 if (!updatedItems.containsKey(child.getName())) {
194 removeNodes.add(child);
195 }
196 }
197 for(int i = 0; i < removeNodes.size(); i++) {
198 ((Node) removeNodes.get(i)).remove();
199 }
200 }
201 }
202
203 /***
204 * @see AbstractCollectionConverterImpl#doGetCollection(Session, Node, CollectionDescriptor, Class)
205 */
206 protected ManageableCollection doGetCollection(Session session,
207 Node parentNode,
208 CollectionDescriptor collectionDescriptor,
209 Class collectionFieldClass) throws RepositoryException {
210 String jcrName = getCollectionJcrName(collectionDescriptor);
211
212 if (parentNode == null || !parentNode.hasNode(jcrName)) {
213 return null;
214 }
215
216 ManageableCollection collection = ManageableCollectionUtil.getManageableCollection(collectionFieldClass);
217 Node collectionNode = parentNode.getNode(jcrName);
218 NodeIterator children = collectionNode.getNodes();
219 Class elementClass = ReflectionUtils.forName(collectionDescriptor.getElementClassName());
220
221 while (children.hasNext()) {
222 Node itemNode = children.nextNode();
223 Object item = objectConverter.getObject(session, itemNode.getPath());
224 collection.addObject(item);
225 }
226
227 return collection;
228 }
229
230 /***
231 * @see AbstractCollectionConverterImpl#doIsNull(Session, Node, CollectionDescriptor, Class)
232 */
233 protected boolean doIsNull(Session session,
234 Node parentNode,
235 CollectionDescriptor collectionDescriptor,
236 Class collectionFieldClass) throws RepositoryException {
237 String jcrName = getCollectionJcrName(collectionDescriptor);
238
239 if (parentNode == null || !parentNode.hasNode(jcrName)) {
240 return true;
241 }
242 return false;
243 }
244 }