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 }