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