Return-Path: Delivered-To: apmail-jackrabbit-commits-archive@www.apache.org Received: (qmail 85959 invoked from network); 15 Dec 2009 16:20:34 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 15 Dec 2009 16:20:34 -0000 Received: (qmail 29273 invoked by uid 500); 15 Dec 2009 16:20:34 -0000 Delivered-To: apmail-jackrabbit-commits-archive@jackrabbit.apache.org Received: (qmail 29182 invoked by uid 500); 15 Dec 2009 16:20:33 -0000 Mailing-List: contact commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@jackrabbit.apache.org Delivered-To: mailing list commits@jackrabbit.apache.org Received: (qmail 29173 invoked by uid 99); 15 Dec 2009 16:20:33 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 15 Dec 2009 16:20:33 +0000 X-ASF-Spam-Status: No, hits=-2.9 required=5.0 tests=AWL,BAYES_00 X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 15 Dec 2009 16:20:31 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id E57CB23888DC; Tue, 15 Dec 2009 16:20:09 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r890864 - /jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/JcrUtils.java Date: Tue, 15 Dec 2009 16:20:09 -0000 To: commits@jackrabbit.apache.org From: jukka@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20091215162009.E57CB23888DC@eris.apache.org> Author: jukka Date: Tue Dec 15 16:20:09 2009 New Revision: 890864 URL: http://svn.apache.org/viewvc?rev=890864&view=rev Log: JCR-2439: More utility methods in JcrUtils Add getOrAddFolder() and putFile() methods. Revert the getOrAddNode(parent, name, type) method back to data-first style, i.e. don't enforce the node type. Modified: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/JcrUtils.java Modified: jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/JcrUtils.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/JcrUtils.java?rev=890864&r1=890863&r2=890864&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/JcrUtils.java (original) +++ jackrabbit/trunk/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/JcrUtils.java Tue Dec 15 16:20:09 2009 @@ -16,6 +16,8 @@ */ package org.apache.jackrabbit.commons; +import java.io.InputStream; +import java.util.Calendar; import java.util.HashMap; import java.util.Iterator; import java.util.Map; @@ -23,7 +25,6 @@ import javax.imageio.spi.ServiceRegistry; import javax.jcr.Binary; import javax.jcr.Item; -import javax.jcr.ItemExistsException; import javax.jcr.Node; import javax.jcr.NodeIterator; import javax.jcr.Property; @@ -33,6 +34,7 @@ import javax.jcr.RepositoryException; import javax.jcr.RepositoryFactory; import javax.jcr.Value; +import javax.jcr.nodetype.NodeType; import javax.jcr.query.QueryResult; import javax.jcr.query.Row; import javax.jcr.query.RowIterator; @@ -357,7 +359,7 @@ * @see Node#addNode(String) * @param parent parent node * @param name name of the child node - * @return child node + * @return the child node * @throws RepositoryException if the child node can not be * accessed or created */ @@ -375,44 +377,160 @@ * it does not already exist. If the child node gets added, then it * is created with the given node type. The caller is expected to take * care of saving or discarding any transient changes. - *

- * This method ensures not only that the named child node exists but - * also that it matches the given node type. If the child node already - * exists but does not match the given node type, then an - * {@link ItemExistsException} is thrown to indicate that a node of the - * given type can only be added if the previous node is first removed. * * @see Node#getNode(String) * @see Node#addNode(String, String) * @see Node#isNodeType(String) * @param parent parent node * @param name name of the child node - * @param type type of the child node - * @return child node - * @throws ItemExistsException if the child node already exists but - * has a different type than specified - * @throws RepositoryException if the child node can not be - * accessed or created + * @param type type of the child node, ignored if the child already exists + * @return the child node + * @throws RepositoryException if the child node can not be accessed + * or created */ public static Node getOrAddNode(Node parent, String name, String type) throws RepositoryException { if (parent.hasNode(name)) { - Node node = parent.getNode(name); - if (node.isNodeType(type)) { - return node; - } else { - throw new ItemExistsException( - "Unable to add a node of type " + type - + " at path " + node.getPath() - + " since it already exists with the different type " - + node.getPrimaryNodeType().getName()); - } + return parent.getNode(name); } else { return parent.addNode(name, type); } } /** + * Returns the named child of the given node, creating it as an + * nt:folder node if it does not already exist. The caller is expected + * to take care of saving or discarding any transient changes. + *

+ * Note that the type of the returned node is not guaranteed + * to match nt:folder in case the node already existed. The caller can + * use an explicit {@link Node#isNodeType(String)} check if needed, or + * simply use a data-first approach and not worry about the node type + * until a constraint violation is encountered. + * + * @param parent parent node + * @param name name of the child node + * @return the child node + * @throws RepositoryException if the child node can not be accessed + * or created + */ + public static Node getOrAddFolder(Node parent, String name) + throws RepositoryException { + return getOrAddNode(parent, name, NodeType.NT_FOLDER); + } + + /** + * Creates or updates the named child of the given node. If the child + * does not already exist, then it is created using the nt:file node type. + * This file child node is returned from this method. + *

+ * If the file node does not already contain a jcr:content child, then + * one is created using the nt:resource node type. The following + * properties are set on the jcr:content node: + *

+ *
jcr:mimeType
+ *
media type
+ *
jcr:encoding (optional)
+ *
charset parameter of the media type, if any
+ *
jcr:lastModified
+ *
current time
+ *
jcr:data
+ *
binary content
+ *
+ *

+ * Note that the types of the returned node or the jcr:content child are + * not guaranteed to match nt:file and nt:resource in case the + * nodes already existed. The caller can use an explicit + * {@link Node#isNodeType(String)} check if needed, or simply use a + * data-first approach and not worry about the node type until a constraint + * violation is encountered. + *

+ * The given binary content stream is closed by this method. + * + * @param parent parent node + * @param name name of the file + * @param mime media type of the file + * @param data binary content of the file + * @return the child node + * @throws RepositoryException if the child node can not be created + * or updated + */ + public static Node putFile( + Node parent, String name, String mime, InputStream data) + throws RepositoryException { + return putFile(parent, name, mime, Calendar.getInstance(), data); + } + + /** + * Creates or updates the named child of the given node. If the child + * does not already exist, then it is created using the nt:file node type. + * This file child node is returned from this method. + *

+ * If the file node does not already contain a jcr:content child, then + * one is created using the nt:resource node type. The following + * properties are set on the jcr:content node: + *

+ *
jcr:mimeType
+ *
media type
+ *
jcr:encoding (optional)
+ *
charset parameter of the media type, if any
+ *
jcr:lastModified
+ *
date of last modification
+ *
jcr:data
+ *
binary content
+ *
+ *

+ * Note that the types of the returned node or the jcr:content child are + * not guaranteed to match nt:file and nt:resource in case the + * nodes already existed. The caller can use an explicit + * {@link Node#isNodeType(String)} check if needed, or simply use a + * data-first approach and not worry about the node type until a constraint + * violation is encountered. + *

+ * The given binary content stream is closed by this method. + * + * @param parent parent node + * @param name name of the file + * @param mime media type of the file + * @param date date of last modification + * @param data binary content of the file + * @return the child node + * @throws RepositoryException if the child node can not be created + * or updated + */ + public static Node putFile( + Node parent, String name, String mime, Calendar date, + InputStream data) throws RepositoryException { + Binary binary = + parent.getSession().getValueFactory().createBinary(data); + try { + Node file = getOrAddNode(parent, name, NodeType.NT_FILE); + Node content = + getOrAddNode(file, Node.JCR_CONTENT, NodeType.NT_RESOURCE); + + content.setProperty(Property.JCR_MIMETYPE, mime); + String[] parameters = mime.split(";"); + for (int i = 1; i < parameters.length; i++) { + int equals = parameters[i].indexOf('='); + if (equals != -1) { + String parameter = parameters[i].substring(0, equals); + if ("charset".equalsIgnoreCase(parameter.trim())) { + content.setProperty( + Property.JCR_ENCODING, + parameters[i].substring(equals + 1).trim()); + } + } + } + + content.setProperty(Property.JCR_LAST_MODIFIED, date); + content.setProperty(Property.JCR_DATA, binary); + return file; + } finally { + binary.dispose(); + } + } + + /** * Returns a string representation of the given item. The returned string * is designed to be easily readable while providing maximum amount of * information for logging and debugging purposes.