View Javadoc

1   /*
2    * Copyright 2007-2012 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springbyexample.jcr;
18  
19  import java.io.IOException;
20  import java.util.HashSet;
21  import java.util.Iterator;
22  import java.util.Set;
23  
24  import javax.jcr.Node;
25  import javax.jcr.PathNotFoundException;
26  import javax.jcr.RepositoryException;
27  import javax.jcr.Session;
28  
29  import org.slf4j.Logger;
30  import org.slf4j.LoggerFactory;
31  import org.springframework.beans.factory.annotation.Autowired;
32  import org.springframework.stereotype.Component;
33  import org.springframework.util.StringUtils;
34  import org.springmodules.jcr.JcrCallback;
35  import org.springmodules.jcr.JcrConstants;
36  import org.springmodules.jcr.JcrTemplate;
37  
38  /**
39   * Used for recursing through the repository.
40   * It also can start at a specified path (default is the root node)
41   * and also matching on specific nodes if a node name 
42   * is specified.  If no specific node names are 
43   * specified, all nodes will be processed.
44   * 
45   * @author David Winterfeldt
46   */
47  @Component
48  public class JcrRecurser {
49  
50      final Logger logger = LoggerFactory.getLogger(JcrRecurser.class);
51  
52      @Autowired
53      protected JcrTemplate template = null;
54      
55      protected String path = null;
56      protected String pathDelim = "/";
57      protected Set<String> matchingNodes = new HashSet<String>();
58  
59      /**
60       * Constructor.
61       */
62      public JcrRecurser() {}
63      
64      /**
65       * Constructor.
66       * 
67       * @param   path            Relative path from root to start recursing.
68       */
69      public JcrRecurser(String path) {
70          this.path = path;
71      }
72  
73      /**
74       * Constructor.
75       * 
76       * @param   matchingNodes   <code>Set</code> of node names to match for callbacks.
77       */
78      public JcrRecurser(Set<String> matchingNodes) {
79          this.matchingNodes = matchingNodes;
80      }
81  
82      /**
83       * Constructor.
84       * 
85       * @param   path            Relative path from root to start recursing.
86       * @param   matchingNodes   <code>Set</code> of node names to match for callbacks.
87       */
88      public JcrRecurser(String path, Set<String> matchingNodes) {
89          this.path = path;
90          this.matchingNodes = matchingNodes;
91      }
92      
93      /**
94       * Gets JCR template.
95       */
96      public JcrTemplate getTemplate() {
97          return template;
98      }
99  
100     /**
101      * Sets JCR template.
102      */
103     public void setTemplate(JcrTemplate template) {
104         this.template = template;
105     }
106 
107     /**
108      * Gets relative path from root to start recursing.
109      */
110     public String getPath() {
111         return path;
112     }
113 
114     /**
115      * Sets relative path from root to start recursing.
116      */
117     public void setPath(String path) {
118         this.path = path;
119     }
120 
121     /**
122      * Gets path delimiter.
123      */
124     public String getPathDelim() {
125         return pathDelim;
126     }
127 
128     /**
129      * Sets path delimiter.
130      */
131     public void setPathDelim(String pathDelim) {
132         this.pathDelim = pathDelim;
133     }
134 
135     /**
136      * Gets matching names.  If any node names match, 
137      * then the <code>JcrNodeCallback</code> will be 
138      * run.  If no specific node names are specified, 
139      * all nodes will be processed.
140      */
141     public Set<String> getMatchingNodeSet() {
142         return matchingNodes;
143     }
144 
145     /**
146      * Sets matching names.  If any node names match, 
147      * then the <code>JcrNodeCallback</code> will be 
148      * run.  If no specific node names are specified, 
149      * all nodes will be processed.
150      */
151     public void setMatchingNodeSet(Set<String> matchingNodes) {
152         this.matchingNodes = matchingNodes;
153     }
154 
155     /**
156      * Add matching node.
157      */
158     public void addMatchingNode(String nodeName) {
159         matchingNodes.add(nodeName);
160     }
161 
162     /**
163      * Recurses through all nodes processing the callback 
164      * when a matching node is found.
165      */
166     public void recurse(final JcrNodeCallback callback) {
167         template.execute(new JcrCallback() {
168             public Object doInJcr(Session session) throws RepositoryException,
169                     IOException {
170                 Node root = session.getRootNode();
171                 JcrConstants jcrConstants = new JcrConstants(session);
172                 
173                 Node startNode = getStartNode(root);
174                 
175                 logger.debug("Recursing beginging at '{}' node.", startNode.getName());
176 
177                 recurseNodes(session, jcrConstants, startNode, callback);
178 
179                 return null;
180             }
181         });
182     }
183 
184     /**
185      * Gets start node.  If a path was specified, it will find the node 
186      * matching the path (ex: 'albums/album') from the root.  Otherwise 
187      * the root passed in will be returned.
188      */
189     public Node getStartNode(Node root) throws PathNotFoundException, RepositoryException {
190         Node result = null;
191         
192         if (!StringUtils.hasText(path)) {
193             result = root;
194         } else if (path.indexOf(pathDelim) == -1) {
195             result = root.getNode(path);
196         } else {
197             String[] nodes = StringUtils.split(path, pathDelim);
198             Node lastNode = root;
199             
200             for (String nodeName : nodes) {
201                 if (StringUtils.hasText(nodeName)) {
202                     lastNode = lastNode.getNode(nodeName);
203                 }
204             }
205             
206             result = lastNode;
207         }
208     
209         return result;
210     }
211     
212     /**
213      * Recurse nodes.
214      */
215     @SuppressWarnings("unchecked")
216 	protected void recurseNodes(Session session, JcrConstants jcrConstants,
217 	                            Node node, JcrNodeCallback callback)
218             throws IOException, RepositoryException {
219         // process callback if no specific node names specified 
220         // or there is a match
221         if (matchingNodes.size() == 0 ||
222             matchingNodes.contains(node.getName())) {
223             callback.doInJcrNode(session, node);
224         }
225 
226         if (node.hasNodes()) {
227             for (Iterator<Node> i = (Iterator<Node>)node.getNodes(); i.hasNext();) {
228                 Node childNode = i.next();
229 
230                 recurseNodes(session, jcrConstants, childNode, callback);
231             }
232         }
233     }
234 
235 }