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.Collection;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Map;
26
27 import javax.jcr.Node;
28 import javax.jcr.NodeIterator;
29 import javax.jcr.PathNotFoundException;
30 import javax.jcr.RepositoryException;
31 import javax.jcr.Session;
32 import javax.jcr.ValueFormatException;
33 import javax.jcr.lock.LockException;
34 import javax.jcr.nodetype.ConstraintViolationException;
35 import javax.jcr.version.VersionException;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.apache.portals.graffito.jcr.mapper.Mapper;
40 import org.apache.portals.graffito.jcr.mapper.model.ClassDescriptor;
41 import org.apache.portals.graffito.jcr.mapper.model.CollectionDescriptor;
42 import org.apache.portals.graffito.jcr.persistence.collectionconverter.ManageableCollection;
43 import org.apache.portals.graffito.jcr.persistence.collectionconverter.ManageableCollectionUtil;
44 import org.apache.portals.graffito.jcr.persistence.objectconverter.ObjectConverter;
45 import org.apache.portals.graffito.jcr.reflection.ReflectionUtils;
46
47 /***
48 * Collection Mapping/convertion based on node type.
49 *
50 * This collection mapping strategy maps a collection into several nodes based on specific node type.
51 *
52 *
53 * If the collection element class contains an id (see the FieldDescriptor definition), this id value is used to build the collection element node.
54 * Otherwise, the element node name is a simple constant (collection-element)
55 *
56 * Example - without an id attribute:
57 * /test (Main object containing the collection field )
58 * /collection-element (node used to store the first collection element)
59 * /item-prop
60 * ....
61 * /collection-element (node used to store the second collection element)
62 * ...
63 *
64 * Example - with an id attribute:
65 * /test (Main object containing the collection field )
66 * /aValue (id value assigned to the first element)
67 * /item-prop
68 * ....
69 * /anotherValue (id value assigned to the first element)
70 * ...
71 *
72 * @author <a href="mailto:christophe.lombart@gmail.com">Christophe Lombart</a>
73 *
74 */
75 public class NTCollectionConverterImpl extends AbstractCollectionConverterImpl {
76
77 private final static Log log = LogFactory.getLog(NTCollectionConverterImpl.class);
78
79 private static final String COLLECTION_ELEMENT_NAME = "collection-element";
80
81 /***
82 * Constructor
83 *
84 * @param atomicTypeConverters
85 * @param objectConverter
86 * @param mapper
87 */
88 public NTCollectionConverterImpl(Map atomicTypeConverters,
89 ObjectConverter objectConverter,
90 Mapper mapper) {
91 super(atomicTypeConverters, objectConverter, mapper);
92 }
93
94 /***
95 * @see AbstractCollectionConverterImpl#doInsertCollection(Session, Node, CollectionDescriptor, ManageableCollection)
96 */
97 protected void doInsertCollection(Session session,
98 Node parentNode,
99 CollectionDescriptor collectionDescriptor,
100 ManageableCollection collection) {
101 if (collection == null) {
102 return;
103 }
104
105 ClassDescriptor elementClassDescriptor = mapper.getClassDescriptorByClass( ReflectionUtils.forName(collectionDescriptor.getElementClassName()));
106
107 Iterator collectionIterator = collection.getIterator();
108 while (collectionIterator.hasNext()) {
109 Object item = collectionIterator.next();
110 String elementJcrName = null;
111
112
113 if (elementClassDescriptor.hasIdField()) {
114 String idFieldName = elementClassDescriptor.getIdFieldDescriptor().getFieldName();
115 elementJcrName = ReflectionUtils.getNestedProperty(item, idFieldName).toString();
116 }
117 else {
118 elementJcrName = COLLECTION_ELEMENT_NAME;
119 }
120
121 objectConverter.insert(session, parentNode, elementJcrName, item);
122 }
123 }
124
125 /***
126 *
127 * @see org.apache.portals.graffito.jcr.persistence.collectionconverter.CollectionConverter#updateCollection(javax.jcr.Session, javax.jcr.Node, org.apache.portals.graffito.jcr.mapper.model.CollectionDescriptor, org.apache.portals.graffito.jcr.persistence.collectionconverter.ManageableCollection)
128 */
129 protected void doUpdateCollection(Session session,
130 Node parentNode,
131 CollectionDescriptor collectionDescriptor,
132 ManageableCollection collection) throws RepositoryException {
133 Mapper mapper = collectionDescriptor.getClassDescriptor().getMappingDescriptor().getMapper();
134 ClassDescriptor elementClassDescriptor = mapper.getClassDescriptorByClass(
135 ReflectionUtils.forName(collectionDescriptor.getElementClassName()));
136
137 if (collection == null || !elementClassDescriptor.hasIdField()) {
138 this.deleteCollectionItems(session,
139 parentNode,
140 elementClassDescriptor.getJcrNodeType());
141 }
142
143 if (collection == null) {
144 return;
145 }
146
147 Iterator collectionIterator = collection.getIterator();
148 Map updatedItems = new HashMap();
149 while (collectionIterator.hasNext()) {
150 Object item = collectionIterator.next();
151
152 String elementJcrName = null;
153
154 if (elementClassDescriptor.hasIdField()) {
155 String idFieldName = elementClassDescriptor.getIdFieldDescriptor().getFieldName();
156 elementJcrName = ReflectionUtils.getNestedProperty(item, idFieldName).toString();
157
158
159 if (parentNode.hasNode(elementJcrName)) {
160 objectConverter.update(session, parentNode, elementJcrName, item);
161 }
162 else {
163
164 objectConverter.insert(session, parentNode, elementJcrName, item);
165 }
166
167 updatedItems.put(elementJcrName, item);
168 }
169 else {
170 elementJcrName = COLLECTION_ELEMENT_NAME;
171 objectConverter.insert(session, parentNode, elementJcrName, item);
172 }
173 }
174
175
176 if (elementClassDescriptor.hasIdField()) {
177 Iterator nodeIterator = this.getCollectionNodes(session, parentNode,
178 elementClassDescriptor.getJcrNodeType()).iterator();
179
180 while (nodeIterator.hasNext()) {
181 Node child = (Node) nodeIterator.next();
182
183 if (!updatedItems.containsKey(child.getName())) {
184 child.remove();
185 }
186 }
187 }
188 }
189
190 /***
191 * @see org.apache.portals.graffito.jcr.persistence.collectionconverter.CollectionConverter#getCollection(javax.jcr.Session, javax.jcr.Node, org.apache.portals.graffito.jcr.mapper.model.CollectionDescriptor, java.lang.Class)
192 */
193 protected ManageableCollection doGetCollection(Session session,
194 Node parentNode,
195 CollectionDescriptor collectionDescriptor,
196 Class collectionFieldClass) throws RepositoryException {
197 ClassDescriptor elementClassDescriptor = mapper.getClassDescriptorByClass( ReflectionUtils.forName(collectionDescriptor.getElementClassName()));
198 ManageableCollection collection = ManageableCollectionUtil.getManageableCollection(collectionFieldClass);
199 Class elementClass = ReflectionUtils.forName(collectionDescriptor.getElementClassName());
200 Iterator children = this.getCollectionNodes(session, parentNode,
201 elementClassDescriptor.getJcrNodeType()).iterator();
202
203 while (children.hasNext()) {
204 Node itemNode = (Node) children.next();
205 log.debug("Collection node found : " + itemNode.getPath());
206 Object item = objectConverter.getObject(session, itemNode.getPath());
207 collection.addObject(item);
208 }
209
210 return collection;
211 }
212
213 /***
214 * @see AbstractCollectionConverterImpl#doIsNull(Session, Node, CollectionDescriptor, Class)
215 */
216 protected boolean doIsNull(Session session,
217 Node parentNode,
218 CollectionDescriptor collectionDescriptor,
219 Class collectionFieldClass) throws RepositoryException {
220
221
222 return false;
223 }
224
225 private Collection getCollectionNodes(Session session, Node parentNode, String itemNodeType)
226 throws PathNotFoundException, ValueFormatException, RepositoryException {
227
228 List collectionNodes = new ArrayList();
229
230
231
232
233 if (!parentNode.getPath().startsWith("/jcr:system/jcr:versionStorage")) {
234 NodeIterator nodeIterator = parentNode.getNodes();
235 while (nodeIterator.hasNext()) {
236 Node child = nodeIterator.nextNode();
237
238 if (child.isNodeType(itemNodeType)) {
239 collectionNodes.add(child);
240 }
241 }
242 }
243 else {
244 NodeIterator nodeIterator = parentNode.getNodes();
245 while (nodeIterator.hasNext()) {
246 Node child = nodeIterator.nextNode();
247
248 if (child.getProperty("jcr:frozenPrimaryType").getString().equals(itemNodeType)) {
249 collectionNodes.add(child);
250 }
251 }
252
253 }
254
255 return collectionNodes;
256 }
257
258 private void deleteCollectionItems(Session session, Node parentNode, String itemNodeType)
259 throws VersionException,
260 LockException,
261 ConstraintViolationException,
262 PathNotFoundException,
263 ValueFormatException,
264 RepositoryException
265 {
266 Iterator nodeIterator = this.getCollectionNodes(session, parentNode, itemNodeType).iterator();
267 while (nodeIterator.hasNext()) {
268 Node node = (Node) nodeIterator.next();
269 node.remove();
270 }
271 }
272 }