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.ui.workbench.tree;
35
36 import info.magnolia.context.MgnlContext;
37 import info.magnolia.jcr.util.NodeTypes;
38 import info.magnolia.jcr.util.NodeUtil;
39 import info.magnolia.ui.vaadin.integration.contentconnector.JcrContentConnectorDefinition;
40 import info.magnolia.ui.vaadin.integration.contentconnector.NodeTypeDefinition;
41 import info.magnolia.ui.vaadin.integration.jcr.JcrItemAdapter;
42 import info.magnolia.ui.vaadin.integration.jcr.JcrItemId;
43 import info.magnolia.ui.vaadin.integration.jcr.JcrItemUtil;
44 import info.magnolia.ui.workbench.container.AbstractJcrContainer;
45
46 import java.util.ArrayList;
47 import java.util.Collection;
48 import java.util.Collections;
49 import java.util.Comparator;
50 import java.util.List;
51
52 import javax.jcr.Item;
53 import javax.jcr.Node;
54 import javax.jcr.NodeIterator;
55 import javax.jcr.Property;
56 import javax.jcr.PropertyIterator;
57 import javax.jcr.RepositoryException;
58 import javax.jcr.Session;
59
60 import org.apache.commons.lang3.StringUtils;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 import com.vaadin.data.Container;
65
66
67
68
69 public class HierarchicalJcrContainer extends AbstractJcrContainer implements Container.Hierarchical {
70
71 private static final Logger log = LoggerFactory.getLogger(HierarchicalJcrContainer.class);
72
73 private static class ItemNameComparator implements Comparator<Item> {
74 @Override
75 public int compare(Item lhs, Item rhs) {
76 try {
77 return lhs.getName().compareTo(rhs.getName());
78 } catch (RepositoryException e) {
79 log.warn("Cannot compare item names: " + e);
80 return 0;
81 }
82 }
83 }
84
85 public HierarchicalJcrContainer(JcrContentConnectorDefinition definition) {
86 super(definition);
87 }
88
89 @Override
90 public Collection<JcrItemId> getChildren(Object itemId) {
91 long start = System.currentTimeMillis();
92 Collection<Item> children = getChildren(getJcrItem(itemId));
93 log.debug("Fetched {} children in {}ms", children.size(), System.currentTimeMillis() - start);
94 return createContainerIds(children);
95 }
96
97 @Override
98 public JcrItemId getParent(Object itemId) {
99 try {
100 Item item = getJcrItem(itemId);
101 if (item.isNode() && item.getDepth() == 0) {
102 return null;
103 }
104 return JcrItemUtil.getItemId(item.getParent());
105 } catch (RepositoryException e) {
106 handleRepositoryException(log, "Cannot determine parent for itemId: " + itemId, e);
107 return null;
108 }
109 }
110
111 @Override
112 public Collection<JcrItemId> rootItemIds() {
113 try {
114 return createContainerIds(getRootItemIds());
115 } catch (RepositoryException e) {
116 handleRepositoryException(log, "Cannot retrieve root item id's", e);
117 return Collections.emptySet();
118 }
119 }
120
121 @Override
122 public void refresh() {
123 resetOffset();
124 clearItemIndexes();
125 fireItemSetChange();
126 }
127
128 @Override
129 public boolean setParent(Object itemId, Object newParentId) throws UnsupportedOperationException {
130 fireItemSetChange();
131 return true;
132 }
133
134 @Override
135 public boolean areChildrenAllowed(Object itemId) {
136 final JcrItemAdapter item = ((JcrItemAdapter) getItem(itemId));
137 if (item == null) {
138 return false;
139 }
140 return item.isNode() && hasChildren(itemId);
141 }
142
143 @Override
144 public boolean setChildrenAllowed(Object itemId, boolean areChildrenAllowed) throws UnsupportedOperationException {
145 throw new UnsupportedOperationException();
146 }
147
148 @Override
149 public boolean isRoot(Object itemId) {
150 try {
151 return isRoot(getJcrItem(itemId));
152 } catch (RepositoryException e) {
153 handleRepositoryException(log, "Cannot determine whether item is root - itemId: " + itemId, e);
154 return true;
155 }
156 }
157
158 @Override
159 public boolean hasChildren(Object itemId) {
160 final Item item = getJcrItem(itemId);
161 if (item.isNode()) {
162 final Node node = (Node) item;
163 try {
164 final NodeIterator it = node.getNodes();
165 while (it.hasNext()) {
166 if (isNodeVisible(it.nextNode())) {
167 return true;
168 }
169 }
170 } catch (RepositoryException e) {
171 log.warn("Failed to get child nodes of {}", NodeUtil.getPathIfPossible((node)));
172 }
173
174
175 if (getConfiguration().isIncludeProperties()) {
176 try {
177 final PropertyIterator propertyIterator = node.getProperties();
178 while (propertyIterator.hasNext()) {
179 final Property property = propertyIterator.nextProperty();
180 if (!isJcrOrMgnlProperty(property)) {
181 return true;
182 }
183 }
184 } catch (RepositoryException e) {
185 log.warn("Failed to get child nodes of {}", NodeUtil.getPathIfPossible((node)));
186 }
187 }
188 }
189 return false;
190 }
191
192 private boolean isJcrOrMgnlProperty(Property property) throws RepositoryException {
193 final String propertyName = property.getName();
194 return propertyName.startsWith(NodeTypes.JCR_PREFIX) || propertyName.startsWith(NodeTypes.MGNL_PREFIX);
195 }
196
197 protected Collection<JcrItemId> createContainerIds(Collection <Item> children) {
198 ArrayList<JcrItemId> ids = new ArrayList<JcrItemId>();
199 for (Item child : children) {
200 try {
201 JcrItemId itemId = JcrItemUtil.getItemId(child);
202 ids.add(itemId);
203 } catch (RepositoryException e) {
204 handleRepositoryException(log, "Cannot retrieve currentId", e);
205 }
206 }
207 return ids;
208 }
209
210 @Override
211 public List<String> getSortableContainerPropertyIds() {
212
213 return Collections.emptyList();
214 }
215
216 public Collection<Item> getChildren(Item item) {
217 if (!item.isNode()) {
218 return Collections.emptySet();
219 }
220
221 Node node = (Node) item;
222
223 ArrayList<Item> items = new ArrayList<Item>();
224
225 try {
226 NodeIterator iterator = node.getNodes();
227 while (iterator.hasNext()) {
228 Node next = iterator.nextNode();
229 if (isNodeVisible(next)) {
230 items.add(next);
231 }
232 }
233
234 if (getConfiguration().isIncludeProperties()) {
235 ArrayList<Property> properties = new ArrayList<Property>();
236 PropertyIterator propertyIterator = node.getProperties();
237 while (propertyIterator.hasNext()) {
238 final Property property = propertyIterator.nextProperty();
239 if (!isJcrOrMgnlProperty(property)) {
240 properties.add(property);
241 }
242 }
243 ItemNameComparator itemNameComparator = new ItemNameComparator();
244 Collections.sort(properties, itemNameComparator);
245 items.addAll(properties);
246 }
247 } catch (RepositoryException e) {
248 handleRepositoryException(log, "Could not retrieve children", e);
249 }
250
251 return Collections.unmodifiableCollection(items);
252 }
253
254 protected boolean isNodeVisible(Node node) throws RepositoryException {
255
256 if (!getConfiguration().isIncludeSystemNodes() && node.getName().startsWith("jcr:") || node.getName().startsWith("rep:")) {
257 return false;
258 }
259
260 String primaryNodeTypeName = node.getPrimaryNodeType().getName();
261 for (NodeTypeDefinition nodeTypeDefinition : getConfiguration().getNodeTypes()) {
262 if (nodeTypeDefinition.isStrict()) {
263 if (primaryNodeTypeName.equals(nodeTypeDefinition.getName())) {
264 return true;
265 }
266 } else if (NodeUtil.isNodeType(node, nodeTypeDefinition.getName())) {
267 return true;
268 }
269 }
270 return false;
271 }
272
273 public Collection<Item> getRootItemIds() throws RepositoryException {
274 return getChildren(getRootNode());
275 }
276
277
278
279
280
281 public boolean isRoot(Item item) throws RepositoryException {
282 if (item != null) {
283 try {
284 int rootDepth = getRootNode().getDepth();
285 return item.getDepth() <= rootDepth + 1;
286 } catch (RepositoryException e) {
287 handleRepositoryException(log, "Cannot determine depth of jcr item", e);
288 }
289 }
290 return true;
291 }
292
293
294
295
296 String getPathInTree(Item item) throws RepositoryException {
297 String base = getConfiguration().getRootPath();
298 return "/".equals(base) ? item.getPath() : StringUtils.substringAfter(item.getPath(), base);
299 }
300
301 private Session getSession() throws RepositoryException {
302 return MgnlContext.getJCRSession(getWorkspace());
303 }
304
305 protected Node getRootNode() throws RepositoryException {
306 return getSession().getNode(getConfiguration().getRootPath());
307 }
308 }