001 /*
002 * JBoss DNA (http://www.jboss.org/dna)
003 * See the COPYRIGHT.txt file distributed with this work for information
004 * regarding copyright ownership. Some portions may be licensed
005 * to Red Hat, Inc. under one or more contributor license agreements.
006 * See the AUTHORS.txt file in the distribution for a full listing of
007 * individual contributors.
008 *
009 * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
010 * is licensed to you under the terms of the GNU Lesser General Public License as
011 * published by the Free Software Foundation; either version 2.1 of
012 * the License, or (at your option) any later version.
013 *
014 * JBoss DNA is distributed in the hope that it will be useful,
015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017 * Lesser General Public License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this software; if not, write to the Free
021 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
023 */
024 package org.jboss.dna.repository.util;
025
026 import java.io.IOException;
027 import java.io.InputStream;
028 import java.util.HashMap;
029 import java.util.Map;
030 import javax.jcr.Node;
031 import javax.jcr.NodeIterator;
032 import javax.jcr.PathNotFoundException;
033 import javax.jcr.Property;
034 import javax.jcr.PropertyType;
035 import javax.jcr.RepositoryException;
036 import javax.jcr.Session;
037 import javax.jcr.Value;
038 import javax.jcr.ValueFormatException;
039 import org.jboss.dna.common.collection.Problem;
040 import org.jboss.dna.common.collection.Problems;
041 import org.jboss.dna.common.util.IoUtil;
042 import org.jboss.dna.common.util.Logger;
043 import org.jboss.dna.common.util.StringUtil;
044 import org.jboss.dna.repository.RepositoryI18n;
045
046 /**
047 * @author Randall Hauch
048 */
049 public class JcrTools {
050
051 public Map<String, Object> loadProperties( Node propertyContainer, Problems problems ) {
052 return loadProperties(propertyContainer, null, problems);
053 }
054
055 public Map<String, Object> loadProperties( Node propertyContainer, Map<String, Object> properties, Problems problems ) {
056 if (properties == null) properties = new HashMap<String, Object>();
057 if (propertyContainer != null) {
058 try {
059 NodeIterator iter = propertyContainer.getNodes();
060 while (iter.hasNext()) {
061 Node propertyNode = iter.nextNode();
062 if (propertyNode != null && propertyNode.getPrimaryNodeType().isNodeType("dna:property")) {
063 String propertyName = propertyNode.getName();
064 Object propertyValue = getPropertyValue(propertyNode, "dna:propertyValue", true, problems);
065 properties.put(propertyName, propertyValue);
066 }
067 }
068 } catch (RepositoryException e) {
069 problems.addError(e, RepositoryI18n.errorReadingPropertiesFromContainerNode, getReadable(propertyContainer));
070 }
071 }
072
073 return properties;
074 }
075
076 public boolean removeProblems( Node parent ) throws RepositoryException {
077 Node problemsNode = null;
078 if (parent.hasNode("dna:problems")) {
079 problemsNode = parent.getNode("dna:problems");
080 problemsNode.remove();
081 return true;
082 }
083 return false;
084 }
085
086 public boolean storeProblems( Node parent, Problems problems ) throws RepositoryException {
087 Node problemsNode = null;
088 if (parent.hasNode("dna:problems")) {
089 problemsNode = parent.getNode("dna:problems");
090 // Delete all problems ...
091 removeAllChildren(problemsNode);
092 }
093 if (problems.isEmpty()) {
094 return false;
095 }
096 if (problemsNode == null) {
097 problemsNode = parent.addNode("dna:problems"); // primary type dictated by child definition
098 }
099
100 // Add a child for each problem ...
101 for (Problem problem : problems) {
102 Node problemNode = problemsNode.addNode("problem", "dna:problem");
103 // - dna:status (string) mandatory copy
104 // < 'ERROR', 'WARNING', 'INFO'
105 // - dna:message (string) mandatory copy
106 // - dna:code (string) copy
107 // - dna:type (string) copy
108 // - dna:resource (string) copy
109 // - dna:location (string) copy
110 // - dna:trace (string) copy
111 problemNode.setProperty("dna:status", problem.getStatus().name());
112 problemNode.setProperty("dna:message", problem.getMessageString());
113 if (problem.getCode() != Problem.DEFAULT_CODE) {
114 problemNode.setProperty("dna:code", Integer.toString(problem.getCode()));
115 }
116 String resource = problem.getResource();
117 if (resource != null) {
118 problemNode.setProperty("dna:resource", resource);
119 }
120 String location = problem.getLocation();
121 if (location != null) {
122 problemNode.setProperty("dna:location", location);
123 }
124 Throwable t = problem.getThrowable();
125 if (t != null) {
126 String trace = StringUtil.getStackTrace(t);
127 problemNode.setProperty("dna:trace", trace);
128 }
129 }
130 return true;
131 }
132
133 public int removeAllChildren( Node node ) throws RepositoryException {
134 int childrenRemoved = 0;
135 NodeIterator iter = node.getNodes();
136 while (iter.hasNext()) {
137 Node child = iter.nextNode();
138 child.remove();
139 ++childrenRemoved;
140 }
141 return childrenRemoved;
142 }
143
144 public String getPropertyAsString( Node node, String propertyName, boolean required, Problems problems ) {
145 return getPropertyAsString(node, propertyName, required, null);
146 }
147
148 public String getPropertyAsString( Node node, String propertyName, boolean required, String defaultValue, Problems problems ) {
149 try {
150 Property property = node.getProperty(propertyName);
151 return property.getString();
152 } catch (ValueFormatException e) {
153 if (required) {
154 problems.addError(e, RepositoryI18n.requiredPropertyOnNodeWasExpectedToBeStringValue, propertyName, getReadable(node));
155 } else {
156 problems.addError(e, RepositoryI18n.optionalPropertyOnNodeWasExpectedToBeStringValue, propertyName, getReadable(node));
157 }
158 } catch (PathNotFoundException e) {
159 if (required) {
160 problems.addError(e, RepositoryI18n.requiredPropertyIsMissingFromNode, propertyName, getReadable(node));
161 }
162 if (!required) return defaultValue;
163 } catch (RepositoryException err) {
164 if (required) {
165 problems.addError(err, RepositoryI18n.errorGettingRequiredPropertyFromNode, propertyName, getReadable(node));
166 } else {
167 problems.addError(err, RepositoryI18n.errorGettingOptionalPropertyFromNode, propertyName, getReadable(node));
168 }
169 }
170 return null;
171 }
172
173 public Object getPropertyValue( Node node, String propertyName, boolean required, Problems problems ) {
174 try {
175 Property property = node.getProperty(propertyName);
176 switch (property.getType()) {
177 case PropertyType.BINARY: {
178 InputStream stream = property.getStream();
179 try {
180 stream = property.getStream();
181 return IoUtil.readBytes(stream);
182 } finally {
183 if (stream != null) {
184 try {
185 stream.close();
186 } catch (IOException e) {
187 // Log ...
188 Logger.getLogger(this.getClass()).error(e, RepositoryI18n.errorClosingBinaryStreamForPropertyFromNode, propertyName, node.getPath());
189 }
190 }
191 }
192 }
193 default: {
194 return property.getString();
195 }
196 }
197 } catch (IOException e) {
198 if (required) {
199 problems.addError(e, RepositoryI18n.requiredPropertyOnNodeCouldNotBeRead, propertyName, getReadable(node));
200 } else {
201 problems.addError(e, RepositoryI18n.optionalPropertyOnNodeCouldNotBeRead, propertyName, getReadable(node));
202 }
203 } catch (PathNotFoundException e) {
204 if (required) {
205 problems.addError(e, RepositoryI18n.requiredPropertyIsMissingFromNode, propertyName, getReadable(node));
206 }
207 } catch (RepositoryException err) {
208 if (required) {
209 problems.addError(err, RepositoryI18n.errorGettingRequiredPropertyFromNode, propertyName, getReadable(node));
210 } else {
211 problems.addError(err, RepositoryI18n.errorGettingOptionalPropertyFromNode, propertyName, getReadable(node));
212 }
213 }
214 return null;
215 }
216
217 public String[] getPropertyAsStringArray( Node node, String propertyName, boolean required, Problems problems, String... defaultValues ) {
218 String[] result = defaultValues;
219 try {
220 Property property = node.getProperty(propertyName);
221 if (property.getDefinition().isMultiple()) {
222 Value[] values = property.getValues();
223 result = new String[values.length];
224 int i = 0;
225 for (Value value : values) {
226 result[i++] = value.getString();
227 }
228 } else {
229 result = new String[] {property.getString()};
230 }
231 } catch (ValueFormatException e) {
232 if (required) {
233 problems.addError(e, RepositoryI18n.requiredPropertyOnNodeWasExpectedToBeStringArrayValue, propertyName, getReadable(node));
234 } else {
235 problems.addError(e, RepositoryI18n.optionalPropertyOnNodeWasExpectedToBeStringArrayValue, propertyName, getReadable(node));
236 }
237 } catch (PathNotFoundException e) {
238 if (required) {
239 problems.addError(e, RepositoryI18n.requiredPropertyIsMissingFromNode, propertyName, getReadable(node));
240 }
241 } catch (RepositoryException err) {
242 if (required) {
243 problems.addError(err, RepositoryI18n.errorGettingRequiredPropertyFromNode, propertyName, getReadable(node));
244 } else {
245 problems.addError(err, RepositoryI18n.errorGettingOptionalPropertyFromNode, propertyName, getReadable(node));
246 }
247 }
248 return result;
249 }
250
251 public Node getNode( Node node, String relativePath, boolean required, Problems problems ) {
252 Node result = null;
253 try {
254 result = node.getNode(relativePath);
255 } catch (PathNotFoundException e) {
256 if (required) problems.addError(e, RepositoryI18n.requiredNodeDoesNotExistRelativeToNode, relativePath, getReadable(node));
257 } catch (RepositoryException err) {
258 problems.addError(err, RepositoryI18n.errorGettingNodeRelativeToNode, relativePath, getReadable(node));
259 }
260 return result;
261 }
262
263 public String getReadable( Node node ) {
264 if (node == null) return "";
265 try {
266 return node.getPath();
267 } catch (RepositoryException err) {
268 return node.toString();
269 }
270 }
271
272 public Node findOrCreateNode( Session session, String path ) throws RepositoryException {
273 return findOrCreateNode(session, path, null, null);
274 }
275
276 public Node findOrCreateNode( Session session, String path, String nodeType ) throws RepositoryException {
277 return findOrCreateNode(session, path, nodeType, nodeType);
278 }
279
280 public Node findOrCreateNode( Session session, String path, String defaultNodeType, String finalNodeType ) throws RepositoryException {
281 Node root = session.getRootNode();
282 return findOrCreateNode(session, root, path, defaultNodeType, finalNodeType);
283 }
284
285 public Node findOrCreateNode( Session session, Node parentNode, String path, String defaultNodeType, String finalNodeType ) throws RepositoryException {
286 // Remove leading and trailing slashes ...
287 String relPath = path.replaceAll("^/+", "").replaceAll("/+$", "");
288
289 // Look for the node first ...
290 try {
291 return parentNode.getNode(relPath);
292 } catch (PathNotFoundException e) {
293 // continue
294 }
295 // Create the node, which has to be done segment by segment ...
296 String[] pathSegments = relPath.split("/");
297 Node node = parentNode;
298 for (int i = 0, len = pathSegments.length; i != len; ++i) {
299 String pathSegment = pathSegments[i];
300 pathSegment = pathSegment.trim();
301 if (pathSegment.length() == 0) continue;
302 if (node.hasNode(pathSegment)) {
303 // Find the existing node ...
304 node = node.getNode(pathSegment);
305 } else {
306 // Make sure there is no index on the final segment ...
307 String pathSegmentWithNoIndex = pathSegment.replaceAll("(\\[\\d+\\])+$", "");
308 // Create the node ...
309 String nodeType = defaultNodeType;
310 if (i == len - 1 && finalNodeType != null) nodeType = finalNodeType;
311 if (nodeType != null) {
312 node = node.addNode(pathSegmentWithNoIndex, nodeType);
313 } else {
314 node = node.addNode(pathSegmentWithNoIndex);
315 }
316 }
317 }
318 return node;
319 }
320
321 public Node findOrCreateChild( Session session, Node parent, String name ) throws RepositoryException {
322 return findOrCreateChild(session, parent, name, null);
323 }
324
325 public Node findOrCreateChild( Session session, Node parent, String name, String nodeType ) throws RepositoryException {
326 return findOrCreateNode(session, parent, name, nodeType, nodeType);
327 }
328
329 }