Author: brane
Date: Fri Jun 21 08:51:49 2013
New Revision: 1495335

URL: http://svn.apache.org/r1495335
Log:
Add methods to the JavaHL RA api for manipulating revprops.

[in subversion/bindings/javahl/src/org/apache/subversion/javahl]
* ISVNRemote.java
  (ISVNRemote.changeRevisionProperty,
   ISVNRemote.getRevisionProperties,
   ISVNRemote.getRevisionProperty): New methods.
* remote/RemoteSession.java
  (ISVNRemote.changeRevisionProperty,
   ISVNRemote.getRevisionProperties,
   ISVNRemote.getRevisionProperty): New methods.
  (RemoteSession.nativeChangeRevisionProperty): New native wrapper.

Modified:
    subversion/trunk/subversion/bindings/javahl/native/RemoteSession.cpp
    subversion/trunk/subversion/bindings/javahl/native/RemoteSession.h
    
subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp
    
subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java
    
subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java
    
subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java

Modified: subversion/trunk/subversion/bindings/javahl/native/RemoteSession.cpp
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/RemoteSession.cpp?rev=1495335&r1=1495334&r2=1495335&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/RemoteSession.cpp 
(original)
+++ subversion/trunk/subversion/bindings/javahl/native/RemoteSession.cpp Fri 
Jun 21 08:51:49 2013
@@ -27,10 +27,12 @@
 #include <cstring>
 #include <set>
 
+#include "JNIByteArray.h"
 #include "JNIStringHolder.h"
 #include "JNIUtil.h"
 
 #include "svn_ra.h"
+#include "svn_string.h"
 
 #include "CreateJ.h"
 #include "EnumMapper.h"
@@ -387,6 +389,81 @@ RemoteSession::getRevisionByTimestamp(jl
   return rev;
 }
 
+namespace {
+bool byte_array_to_svn_string(JNIByteArray& ary, svn_string_t& str)
+{
+  if (ary.isNull())
+    return false;
+
+  str.data = reinterpret_cast<const char*>(ary.getBytes());
+  str.len = ary.getLength();
+  return true;
+}
+} // anonymous namespace
+
+void
+RemoteSession::changeRevisionProperty(
+    jlong jrevision, jstring jname,
+    jbyteArray jold_value, jbyteArray jvalue)
+{
+  JNIStringHolder name(jname);
+  if (JNIUtil::isExceptionThrown())
+    return;
+
+  JNIByteArray old_value(jold_value);
+  if (JNIUtil::isExceptionThrown())
+    return;
+
+  JNIByteArray value(jvalue);
+  if (JNIUtil::isExceptionThrown())
+    return;
+
+  svn_string_t str_old_value;
+  svn_string_t* const p_old_value = &str_old_value;
+  svn_string_t* const* pp_old_value = NULL;
+  if (byte_array_to_svn_string(old_value, str_old_value))
+      pp_old_value = &p_old_value;
+
+  svn_string_t str_value;
+  svn_string_t* p_value = NULL;
+  if (byte_array_to_svn_string(value, str_value))
+      p_value = &str_value;
+
+  SVN::Pool subPool(pool);
+  SVN_JNI_ERR(svn_ra_change_rev_prop2(m_session,
+                                      svn_revnum_t(jrevision),
+                                      name, pp_old_value, p_value,
+                                      subPool.getPool()), );
+}
+
+jobject
+RemoteSession::getRevisionProperties(jlong jrevision)
+{
+  SVN::Pool subPool(pool);
+  apr_hash_t *props;
+  SVN_JNI_ERR(svn_ra_rev_proplist(m_session, svn_revnum_t(jrevision),
+                                  &props, subPool.getPool()),
+              NULL);
+
+  return CreateJ::PropertyMap(props);
+}
+
+jbyteArray
+RemoteSession::getRevisionProperty(jlong jrevision, jstring jname)
+{
+  JNIStringHolder name(jname);
+  if (JNIUtil::isExceptionThrown())
+    return NULL;
+
+  SVN::Pool subPool(pool);
+  svn_string_t *propval;
+  SVN_JNI_ERR(svn_ra_rev_prop(m_session, svn_revnum_t(jrevision),
+                              name, &propval, subPool.getPool()),
+              NULL);
+
+  return JNIUtil::makeJByteArray(propval);
+}
+
 jobject
 RemoteSession::getLocks(jstring jpath, jobject jdepth)
 {

Modified: subversion/trunk/subversion/bindings/javahl/native/RemoteSession.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/RemoteSession.h?rev=1495335&r1=1495334&r2=1495335&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/RemoteSession.h 
(original)
+++ subversion/trunk/subversion/bindings/javahl/native/RemoteSession.h Fri Jun 
21 08:51:49 2013
@@ -65,8 +65,12 @@ class RemoteSession : public SVNBase
     jstring getReposUUID();
     jstring getReposRootUrl();
     jlong getLatestRevision();
-
-    jlong getRevisionByTimestamp(jlong timestamp);
+    jlong getRevisionByTimestamp(jlong jtimestamp);
+    void changeRevisionProperty(jlong jrevision, jstring jname,
+                                jbyteArray jold_value,
+                                jbyteArray jvalue);
+    jobject getRevisionProperties(jlong jrevision);
+    jbyteArray getRevisionProperty(jlong jrevision, jstring jname);
     jobject getLocks(jstring jpath, jobject jdepth);
     jobject checkPath(jstring jpath, jlong jrevision);
     jboolean hasCapability(jstring capability);

Modified: 
subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp?rev=1495335&r1=1495334&r2=1495335&view=diff
==============================================================================
--- 
subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp
 (original)
+++ 
subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_remote_RemoteSession.cpp
 Fri Jun 21 08:51:49 2013
@@ -154,6 +154,40 @@ Java_org_apache_subversion_javahl_remote
   return ras->getRevisionByTimestamp(timestamp);
 }
 
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_remote_RemoteSession_nativeChangeRevisionProperty(
+    JNIEnv *env, jobject jthis, jlong jrevision, jstring jname,
+    jbyteArray jold_value, jbyteArray jvalue)
+{
+  JNIEntry(RemoteSession, nativeChangeRevisionProperty);
+  RemoteSession *ras = RemoteSession::getCppObject(jthis);
+  CPPADDR_NULL_PTR(ras, );
+
+  return ras->changeRevisionProperty(jrevision, jname, jold_value, jvalue);
+}
+
+JNIEXPORT jobject JNICALL
+Java_org_apache_subversion_javahl_remote_RemoteSession_getRevisionProperties(
+    JNIEnv *env, jobject jthis, jlong jrevision)
+{
+  JNIEntry(SVNReposAccess, getRevisionProperties);
+  RemoteSession *ras = RemoteSession::getCppObject(jthis);
+  CPPADDR_NULL_PTR(ras, NULL);
+
+  return ras->getRevisionProperties(jrevision);
+}
+
+JNIEXPORT jbyteArray JNICALL
+Java_org_apache_subversion_javahl_remote_RemoteSession_getRevisionProperty(
+    JNIEnv *env, jobject jthis, jlong jrevision, jstring jname)
+{
+  JNIEntry(SVNReposAccess, getRevisionProperty);
+  RemoteSession *ras = RemoteSession::getCppObject(jthis);
+  CPPADDR_NULL_PTR(ras, NULL);
+
+  return ras->getRevisionProperty(jrevision, jname);
+}
+
 JNIEXPORT jobject JNICALL
 Java_org_apache_subversion_javahl_remote_RemoteSession_checkPath(
     JNIEnv *env, jobject jthis, jstring jpath, jlong jrevision)

Modified: 
subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java?rev=1495335&r1=1495334&r2=1495335&view=diff
==============================================================================
--- 
subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java
 (original)
+++ 
subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/ISVNRemote.java
 Fri Jun 21 08:51:49 2013
@@ -111,6 +111,56 @@ public interface ISVNRemote
     long getRevisionByTimestamp(long timestamp) throws ClientException;
 
     /**
+     * Change the value of an unversioned property.
+     * @param revision The revision to which the propery is attached
+     * @param propertyName The name of the propery
+     * @param oldValue The previous value of the property (see note below)
+     * @param newValue The new value of the property. If <code>newValue</code>
+     *        is <code>null</code>, the property will be deleted.
+     *
+     * @node If the server has Capability.atomic_revprops and
+     *       <code>oldValue</code> is not <code>null</code>, and the
+     *       present value of the propery is not <code>oldValue</code>
+     *       (e.g., if another client changed the property), then
+     *       the operation will fail.
+     * @note If the server does not adveritse Capability.atomic_revprops,
+     *       then <code>oldValue</code> <em>must</em> be <code>null</code>.
+     *
+     * @throws IllegalArgumentException if <code>oldValue</code> is not
+     *         <code>null</code> and the server does not advertise the
+     *         atomic_revprops capability.
+     * @throws ClientException
+     */
+    void changeRevisionProperty(long revision,
+                                String propertyName,
+                                byte[] oldValue,
+                                byte[] newValue)
+            throws ClientException;
+
+    /**
+     * Return the set of unversioned properties set on <code>revision</code>
+     * in the session's repository.
+     * @throws ClientException
+     */
+    Map<String, byte[]> getRevisionProperties(long revision)
+            throws ClientException;
+
+    /**
+     * Return the value of unversioned property <code>propertyName</code>
+     * in <code>revision</code> in the session's repository.
+     * Returns <code>null</code> if the property does not exist.
+     * @throws ClientException
+     */
+    byte[] getRevisionProperty(long revision, String propertyName)
+            throws ClientException;
+
+    /**
+     * Create a commit editor instance, rooted at the current session URL.
+     * @throws ClientException
+     */
+    ISVNEditor getCommitEditor() throws ClientException;
+
+    /**
      * Return the kind of the node in path at revision.
      * @param path A path relative to the sessionn URL
      * @throws ClientException
@@ -131,10 +181,11 @@ public interface ISVNRemote
             throws ClientException;
 
     /**
-     * Create a commit editor instance, rooted at the current session URL.
+     * Check if the server associated with this session has
+     * the given <code>capability</code>.
      * @throws ClientException
      */
-    ISVNEditor getCommitEditor() throws ClientException;
+    boolean hasCapability(Capability capability) throws ClientException;
 
     /**
      * Enumeration of known capabilities of the repository and server.
@@ -212,11 +263,4 @@ public interface ISVNRemote
 
         private String token;
     }
-
-    /**
-     * Check if the server associated with this session has
-     * the given <code>capability</code>.
-     * @throws ClientException
-     */
-    boolean hasCapability(Capability capability) throws ClientException;
 }

Modified: 
subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java?rev=1495335&r1=1495334&r2=1495335&view=diff
==============================================================================
--- 
subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java
 (original)
+++ 
subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/remote/RemoteSession.java
 Fri Jun 21 08:51:49 2013
@@ -86,10 +86,25 @@ public class RemoteSession extends JNIOb
     public native long getRevisionByTimestamp(long timestamp)
             throws ClientException;
 
-    public native NodeKind checkPath(String path, long revision)
+    public void changeRevisionProperty(long revision,
+                                       String propertyName,
+                                       byte[] oldValue,
+                                       byte[] newValue)
+            throws ClientException
+    {
+        if (oldValue != null && !hasCapability(Capability.atomic_revprops))
+            throw new IllegalArgumentException(
+                "oldValue must be null;\n" +
+                "The server does not support" +
+                " atomic revision property changes");
+        nativeChangeRevisionProperty(revision, propertyName,
+                                     oldValue, newValue);
+    }
+
+    public native Map<String, byte[]> getRevisionProperties(long revision)
             throws ClientException;
 
-    public native Map<String, Lock> getLocks(String path, Depth depth)
+    public native byte[] getRevisionProperty(long revision, String 
propertyName)
             throws ClientException;
 
     public ISVNEditor getCommitEditor() throws ClientException
@@ -101,6 +116,12 @@ public class RemoteSession extends JNIOb
         return ed;
     }
 
+    public native NodeKind checkPath(String path, long revision)
+            throws ClientException;
+
+    public native Map<String, Lock> getLocks(String path, Depth depth)
+            throws ClientException;
+
     public boolean hasCapability(Capability capability)
             throws ClientException
     {
@@ -118,9 +139,17 @@ public class RemoteSession extends JNIOb
         super(cppAddr);
     }
 
+    /*
+     * Wrapped private native implementation declarations.
+     */
     private native void nativeDispose();
-
-    private native boolean nativeHasCapability(String capability);
+    private native void nativeChangeRevisionProperty(long revision,
+                                                     String propertyName,
+                                                     byte[] oldValue,
+                                                     byte[] newValue)
+            throws ClientException;
+    private native boolean nativeHasCapability(String capability)
+            throws ClientException;
 
     /*
      * NOTE: This field is accessed from native code for callbacks.

Modified: 
subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java?rev=1495335&r1=1495334&r2=1495335&view=diff
==============================================================================
--- 
subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java
 (original)
+++ 
subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java
 Fri Jun 21 08:51:49 2013
@@ -26,11 +26,13 @@ import org.apache.subversion.javahl.*;
 import org.apache.subversion.javahl.remote.*;
 import org.apache.subversion.javahl.types.*;
 
+import java.util.Arrays;
 import java.util.Date;
 import java.util.Set;
 import java.util.Map;
 import java.util.HashSet;
 import java.io.IOException;
+import java.nio.charset.Charset;
 
 /**
  * This class is used for testing the SVNReposAccess class
@@ -248,4 +250,81 @@ public class SVNRemoteTests extends SVNT
         ISVNRemote session = getSession();
         assert(session.hasCapability(ISVNRemote.Capability.depth));
     }
+
+    public void testChangeRevpropNoAtomic() throws Exception
+    {
+        Charset UTF8 = Charset.forName("UTF-8");
+        ISVNRemote session = getSession();
+
+        boolean atomic =
+            session.hasCapability(ISVNRemote.Capability.atomic_revprops);
+
+        if (atomic)
+            return;
+
+        boolean exceptioned = false;
+        try
+        {
+            byte[] oldValue = "bumble".getBytes(UTF8);
+            byte[] newValue = "bee".getBytes(UTF8);
+            session.changeRevisionProperty(1, "svn:author",
+                                           oldValue, newValue);
+        }
+        catch (IllegalArgumentException ex)
+        {
+            exceptioned = true;
+        }
+        assert(exceptioned);
+    }
+
+    public void testChangeRevpropAtomic() throws Exception
+    {
+        Charset UTF8 = Charset.forName("UTF-8");
+        ISVNRemote session = getSession();
+
+        boolean atomic =
+            session.hasCapability(ISVNRemote.Capability.atomic_revprops);
+
+        if (!atomic)
+            return;
+
+        byte[] oldValue = USERNAME.getBytes(UTF8);
+        byte[] newValue = "rayjandom".getBytes(UTF8);
+        try
+        {
+            session.changeRevisionProperty(1, "svn:author",
+                                           oldValue, newValue);
+        }
+        catch (ClientException ex)
+        {
+            String msg = ex.getMessage();
+            int index = msg.indexOf('\n');
+            assertEquals(msg.substring(0, index),
+                         "Disabled repository feature");
+            return;
+        }
+
+        byte[] check = client.revProperty(getTestRepoUrl(), "svn:author",
+                                          Revision.getInstance(1));
+        assertTrue(Arrays.equals(newValue, check));
+    }
+
+    public void testGetRevpropList() throws Exception
+    {
+        Charset UTF8 = Charset.forName("UTF-8");
+        ISVNRemote session = getSession();
+
+        Map<String, byte[]> proplist = session.getRevisionProperties(1);
+        assertTrue(Arrays.equals(proplist.get("svn:author"),
+                                 USERNAME.getBytes(UTF8)));
+    }
+
+    public void testGetRevprop() throws Exception
+    {
+        Charset UTF8 = Charset.forName("UTF-8");
+        ISVNRemote session = getSession();
+
+        byte[] propval = session.getRevisionProperty(1, "svn:author");
+        assertTrue(Arrays.equals(propval, USERNAME.getBytes(UTF8)));
+    }
 }


Reply via email to