You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2013/11/15 22:08:05 UTC
svn commit: r1542401 - in /subversion/trunk: ./
subversion/bindings/javahl/native/
subversion/bindings/javahl/native/jniwrapper/
subversion/bindings/javahl/src/org/apache/subversion/javahl/
subversion/bindings/javahl/src/org/apache/subversion/javahl/ut...
Author: brane
Date: Fri Nov 15 21:08:05 2013
New Revision: 1542401
URL: http://svn.apache.org/r1542401
Log:
Add utilities for file content translation to JavaHL.
* build.conf (private-built-includes):
Added org_apache_subversion_javahl_util_SubstLib.h.
[in subversion/bindings/javahl]
* src/org/apache/subversion/javahl/SVNUtil.java
(SVNUtil.substLib,
SVNUtil.EOL_LF SVNUtil.EOL_CR SVNUtil.EOL_CRLF,
SVNUtil.buildKeywords, SVNUtil.translateStream): New.
* src/org/apache/subversion/javahl/util/SubstLib.java: New class.
* native/jniwrapper/jni_string_map.hpp,
native/jniwrapper/jni_string_map.cpp: New; JNI wrapper for
the java.util.Map class with String keys.
* org_apache_subversion_javahl_util_SubstLib.cpp: New;
Implementation of native methods in class SubstLib.
* tests/org/apache/subversion/javahl/UtilTests.java
(UtilTests.testBuildKeywords): New testcase.
Added:
subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_string_map.cpp (with props)
subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_string_map.hpp (with props)
subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_SubstLib.cpp (with props)
subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/SubstLib.java (with props)
Modified:
subversion/trunk/build.conf
subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java
subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java
Modified: subversion/trunk/build.conf
URL: http://svn.apache.org/viewvc/subversion/trunk/build.conf?rev=1542401&r1=1542400&r2=1542401&view=diff
==============================================================================
--- subversion/trunk/build.conf (original)
+++ subversion/trunk/build.conf Fri Nov 15 21:08:05 2013
@@ -82,6 +82,7 @@ private-built-includes =
subversion/bindings/javahl/include/org_apache_subversion_javahl_util_ConfigLib.h
subversion/bindings/javahl/include/org_apache_subversion_javahl_util_DiffLib.h
subversion/bindings/javahl/include/org_apache_subversion_javahl_util_PropLib.h
+ subversion/bindings/javahl/include/org_apache_subversion_javahl_util_SubstLib.h
subversion/bindings/javahl/include/org_apache_subversion_javahl_util_TunnelChannel.h
subversion/bindings/javahl/include/org_apache_subversion_javahl_util_RequestChannel.h
subversion/bindings/javahl/include/org_apache_subversion_javahl_util_ResponseChannel.h
Added: subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_string_map.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_string_map.cpp?rev=1542401&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_string_map.cpp (added)
+++ subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_string_map.cpp Fri Nov 15 21:08:05 2013
@@ -0,0 +1,145 @@
+/**
+ * @copyright
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ * @endcopyright
+ */
+
+#include <stdexcept>
+
+#include "jni_string.hpp"
+#include "jni_string_map.hpp"
+
+namespace Java {
+
+// Class Java::BaseMap
+
+const char* const BaseMap::m_class_name = "java/util/Map";
+
+jobject BaseMap::operator[](const std::string& index) const
+{
+ somap::const_iterator it = m_contents.find(index);
+ if (it == m_contents.end())
+ {
+ std::string msg(_("Map does not contain key: "));
+ msg += index;
+ throw std::out_of_range(msg.c_str());
+ }
+ return it->second;
+}
+
+BaseMap::somap BaseMap::convert_to_map(Env env, jclass cls, jobject jmap)
+{
+ if (!env.CallIntMethod(jmap, env.GetMethodID(cls, "size", "()I")))
+ return somap();
+
+ // Get an iterator over the map's entry set
+ const jobject entries = env.CallObjectMethod(
+ jmap, env.GetMethodID(cls, "entrySet", "()Ljava/util/Set;"));
+ const jobject iterator = env.CallObjectMethod(
+ entries, env.GetMethodID(env.GetObjectClass(entries), "iterator",
+ "()Ljava/util/Iterator;"));
+ const jclass cls_iterator = env.GetObjectClass(iterator);
+ const jmethodID mid_it_has_next = env.GetMethodID(cls_iterator,
+ "hasNext", "()Z");
+ const jmethodID mid_it_next = env.GetMethodID(cls_iterator, "next",
+ "()Ljava/lang/Object;");
+
+ // Find the methods for retreiving the key and value from an entry
+ const jclass cls_entry = env.FindClass("java/util/Map$Entry");
+ const jmethodID mid_get_key = env.GetMethodID(cls_entry, "getKey",
+ "()Ljava/lang/Object;");
+ const jmethodID mid_get_value = env.GetMethodID(cls_entry, "getValue",
+ "()Ljava/lang/Object;");
+
+ // And finally ... iterate over the map, filling the native map
+ somap contents;
+ while (env.CallBooleanMethod(iterator, mid_it_has_next))
+ {
+ const jobject e = env.CallObjectMethod(iterator, mid_it_next);
+ const String keystr(env, jstring(env.CallObjectMethod(e, mid_get_key)));
+ const jobject value(env.CallObjectMethod(e, mid_get_value));
+ const String::Contents key(keystr);
+ contents.insert(somap::value_type(key.c_str(), value));
+ }
+ return contents;
+}
+
+// Class Java::BaseMutableMap
+
+const char* const BaseMutableMap::m_class_name = "java/util/HashMap";
+
+namespace {
+jobject make_hash_map(Env env, const char* class_name, jint length)
+{
+ const jclass cls = env.FindClass(class_name);
+ const jmethodID mid_ctor = env.GetMethodID(cls, "<init>", "(I)V");
+ return env.NewObject(cls, mid_ctor, length);
+}
+} // anonymous namespace
+
+BaseMutableMap::BaseMutableMap(Env env, jint length)
+ : Object(env, m_class_name,
+ make_hash_map(env, m_class_name, length))
+{}
+
+void BaseMutableMap::clear()
+{
+ if (!m_mid_clear)
+ m_mid_clear = m_env.GetMethodID(m_class, "clear", "()V");
+ m_env.CallVoidMethod(m_jthis, m_mid_clear);
+}
+
+jint BaseMutableMap::length() const
+{
+ if (!m_mid_size)
+ m_mid_size = m_env.GetMethodID(m_class, "size", "()I");
+ return m_env.CallIntMethod(m_jthis, m_mid_size);
+}
+
+void BaseMutableMap::put(const std::string& key, jobject obj)
+{
+ if (!m_mid_put)
+ m_mid_put = m_env.GetMethodID(m_class, "put",
+ "(Ljava/lang/Object;Ljava/lang/Object;)"
+ "Ljava/lang/Object;");
+ m_env.CallObjectMethod(m_jthis, m_mid_put, String(m_env, key).get(), obj);
+}
+
+jobject BaseMutableMap::operator[](const std::string& index) const
+{
+ if (!m_mid_has_key)
+ m_mid_has_key = m_env.GetMethodID(m_class, "containsKey",
+ "(Ljava/lang/Object;)Z");
+
+ const String key(m_env, index);
+ if (!m_env.CallBooleanMethod(m_jthis, m_mid_has_key, key.get()))
+ {
+ std::string msg(_("Map does not contain key: "));
+ msg += index;
+ throw std::out_of_range(msg.c_str());
+ }
+
+ if (!m_mid_get)
+ m_mid_get = m_env.GetMethodID(m_class, "get",
+ "(Ljava/lang/Object;)Ljava/lang/Object;");
+ return m_env.CallObjectMethod(m_jthis, m_mid_get, key.get());
+}
+
+} // namespace Java
Propchange: subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_string_map.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Added: subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_string_map.hpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_string_map.hpp?rev=1542401&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_string_map.hpp (added)
+++ subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_string_map.hpp Fri Nov 15 21:08:05 2013
@@ -0,0 +1,249 @@
+/**
+ * @copyright
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ * @endcopyright
+ */
+
+#ifndef SVN_JAVAHL_JNIWRAPPER_STRING_MAP_HPP
+#define SVN_JAVAHL_JNIWRAPPER_STRING_MAP_HPP
+
+#include <map>
+#include <string>
+#include <algorithm>
+
+#include "jni_env.hpp"
+#include "jni_object.hpp"
+
+#include "svn_private_config.h"
+
+namespace Java {
+
+/**
+ * Non-template base for an immutable type-safe Java map with String keys.
+ *
+ * Converts the map to a @c std::map containing @c jobject references.
+ *
+ * @since New in 1.9.
+ */
+class BaseMap : public Object
+{
+ typedef std::map<std::string, jobject> somap;
+
+public:
+ /**
+ * Returns the number of elements in the map.
+ */
+ jint length() const
+ {
+ return jint(m_contents.size());
+ }
+
+protected:
+ /**
+ * Constructs the map wrapper, converting the contents to an
+ * @c std::map.
+ */
+ explicit BaseMap(Env env, jobject jmap)
+ : Object(env, m_class_name, jmap),
+ m_contents(convert_to_map(env, m_class, m_jthis))
+ {}
+
+ /**
+ * Returns the object reference identified by @a index.
+ * @throw std::out_of_range if there is no such element.
+ */
+ jobject operator[](const std::string& index) const;
+
+ const somap m_contents;
+
+private:
+ static const char* const m_class_name;
+ static somap convert_to_map(Env env, jclass cls, jobject jmap);
+};
+
+/**
+ * Template wrapper for an immutable type-safe Java map.
+ *
+ * @since New in 1.9.
+ */
+template <typename T, typename NativeT=jobject>
+class Map : public BaseMap
+{
+public:
+ /**
+ * Constructs the map wrapper, converting the contents to an
+ * @c std::map.
+ */
+ explicit Map(Env env, jobject jmap)
+ : BaseMap(env, jmap)
+ {}
+
+ /**
+ * Returns a wrapper object for the object reference identified by @a index.
+ * @throw std::out_of_range if there is no such element.
+ */
+ T operator[](const std::string& index) const
+ {
+ return T(m_env, NativeT(BaseMap::operator[](index)));
+ }
+
+ /**
+ * Iterates over the items in the map, calling @a function for
+ * each item.
+ * @see std::for_each
+ * @note Unlike std::for_each, which invokes the functor with a
+ * single @c value_type argument, this iterator adapts it to cal
+ * @a function with separate @c const references to the key and
+ * value.
+ */
+ template<typename F>
+ F for_each(F function) const
+ {
+ const FunctorAdapter<F> adapter(m_env, function);
+ std::for_each(m_contents.begin(), m_contents.end(), adapter);
+ return function;
+ }
+
+private:
+ template<typename F>
+ struct FunctorAdapter
+ {
+ explicit FunctorAdapter(const Env& env, F& function)
+ : m_env(env),
+ m_function(function)
+ {}
+
+ void operator()(const std::pair<std::string, jobject>& item) const
+ {
+ const std::string& key(item.first);
+ const T value(m_env, NativeT(item.second));
+ m_function(key, value);
+ }
+
+ const Env& m_env;
+ F& m_function;
+ };
+};
+
+/**
+ * Non-template base for a mutable type-safe Java map with String keys.
+ *
+ * @since New in 1.9.
+ */
+class BaseMutableMap : public Object
+{
+public:
+ /**
+ * Clears the contents of the map.
+ */
+ void clear();
+
+ /**
+ * Returns the number of elements in the map.
+ */
+ jint length() const;
+
+ /**
+ * Checks if the map is empty.
+ */
+ bool is_empty() const
+ {
+ return (length() == 0);
+ }
+
+protected:
+ /**
+ * Constructs the map wrapper, deriving the class from @a jmap.
+ */
+ explicit BaseMutableMap(Env env, jobject jmap)
+ : Object(env, jmap)
+ {}
+
+ /**
+ * Constructs and wraps an empty map of type @c java.util.HashMap
+ * with initial allocation size @a length.
+ */
+ explicit BaseMutableMap(Env env, jint length);
+
+ /**
+ * Inserts @a obj identified by @a key into the map.
+ */
+ void put(const std::string& key, jobject obj);
+
+ /**
+ * Returns the object reference identified by @a index.
+ * @throw std::out_of_range if there is no such element.
+ */
+ jobject operator[](const std::string& index) const;
+
+private:
+ static const char* const m_class_name;
+ MethodID m_mid_put;
+ MethodID m_mid_clear;
+ mutable MethodID m_mid_has_key;
+ mutable MethodID m_mid_get;
+ mutable MethodID m_mid_size;
+};
+
+/**
+ * Template wrapper for a mutable type-safe Java map.
+ *
+ * @since New in 1.9.
+ */
+template <typename T, typename NativeT=jobject>
+class MutableMap : public BaseMutableMap
+{
+public:
+ /**
+ * Constructs the map wrapper, deriving the class from @a jmap.
+ */
+ explicit MutableMap(Env env, jobject jmap)
+ : BaseMutableMap(env, jmap)
+ {}
+
+ /**
+ * Constructs and wraps an empty map of type @c java.util.HashMap
+ * with initial allocation size @a length.
+ */
+ explicit MutableMap(Env env, jint length = 0)
+ : BaseMutableMap(env, length)
+ {}
+
+ /**
+ * Inserts @a obj identified by @a key into the map.
+ */
+ void put(const std::string& key, const T& obj)
+ {
+ BaseMutableMap::put(key, obj.get());
+ }
+
+ /**
+ * Returns a wrapper object for the object reference identified by @a index.
+ * @throw std::out_of_range if there is no such element.
+ */
+ T operator[](const std::string& index) const
+ {
+ return T(m_env, NativeT(BaseMutableMap::operator[](index)));
+ }
+};
+
+} // namespace Java
+
+#endif // SVN_JAVAHL_JNIWRAPPER_STRING_MAP_HPP
Propchange: subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_string_map.hpp
------------------------------------------------------------------------------
svn:eol-style = native
Added: subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_SubstLib.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_SubstLib.cpp?rev=1542401&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_SubstLib.cpp (added)
+++ subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_SubstLib.cpp Fri Nov 15 21:08:05 2013
@@ -0,0 +1,107 @@
+/**
+ * @copyright
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ * @endcopyright
+ *
+ * @file org_apache_subversion_javahl_util_SubstLib.cpp
+ * @brief Implementation of the native methods in the Java class SubstLib
+ */
+
+#include "../include/org_apache_subversion_javahl_util_SubstLib.h"
+
+#include "jniwrapper/jni_stack.hpp"
+#include "jniwrapper/jni_array.hpp"
+#include "jniwrapper/jni_string.hpp"
+#include "jniwrapper/jni_string_map.hpp"
+
+#include "JNIUtil.h"
+#include "InputStream.h"
+
+#include <apr_strings.h>
+#include <apr_hash.h>
+
+#include "svn_subst.h"
+
+#include "svn_private_config.h"
+
+
+namespace {
+} // anoymous namespace
+
+
+JNIEXPORT jobject JNICALL
+Java_org_apache_subversion_javahl_util_SubstLib_buildKeywords(
+ JNIEnv* jenv, jobject jthis,
+ jbyteArray jkeywords_value, jlong jrevision,
+ jstring jurl, jstring jrepos_root_url,
+ jobject jdate, jstring jauthor)
+{
+ SVN_JAVAHL_JNI_TRY(SubstLib, buildKeywords)
+ {
+ const Java::Env env(jenv);
+
+ const Java::ByteArray keywords_value(env, jkeywords_value);
+ const Java::String url(env, jurl);
+ const Java::String repos_root_url(env, jrepos_root_url);
+ const Java::String author(env, jauthor);
+
+ // Using a "global" request pool since we don't keep a context with
+ // its own pool around for these functions.
+ SVN::Pool pool;
+
+ const Java::ByteArray::Contents keywords_contents(keywords_value);
+ svn_string_t* keywords_string = keywords_contents.get_string(pool);
+ const char* revision = (jrevision < 0 ? NULL
+ : apr_psprintf(pool.getPool(),
+ "%"APR_UINT64_T_FMT,
+ apr_uint64_t(jrevision)));
+ const Java::String::Contents url_contents(url);
+ const Java::String::Contents root_url_contents(repos_root_url);
+ const Java::String::Contents author_contents(author);
+
+ apr_hash_t* kw = NULL;
+ SVN_JAVAHL_CHECK(svn_subst_build_keywords3(
+ &kw,
+ keywords_string->data,
+ revision,
+ url_contents.c_str(),
+ root_url_contents.c_str(),
+ (jdate ? JNIUtil::getDate(jdate) : 0),
+ author_contents.c_str(),
+ pool.getPool()));
+
+ Java::MutableMap<Java::ByteArray, jbyteArray>
+ keywords(env, jint(apr_hash_count(kw)));
+ for (apr_hash_index_t* hi = apr_hash_first(pool.getPool(), kw);
+ hi; hi = apr_hash_next(hi))
+ {
+ const void* rkey;
+ void* rval;
+ apr_hash_this(hi, &rkey, NULL, &rval);
+
+ svn_string_t* const val = static_cast<svn_string_t*>(rval);
+ keywords.put(static_cast<const char*>(rkey),
+ Java::ByteArray(env, val->data, jsize(val->len)));
+ }
+ return keywords.get();
+ }
+ SVN_JAVAHL_JNI_CATCH;
+ return NULL;
+}
Propchange: subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_SubstLib.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java?rev=1542401&r1=1542400&r2=1542401&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java (original)
+++ subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/SVNUtil.java Fri Nov 15 21:08:05 2013
@@ -29,7 +29,9 @@ import org.apache.subversion.javahl.util
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.Date;
import java.util.List;
+import java.util.Map;
public class SVNUtil
{
@@ -398,6 +400,7 @@ public class SVNUtil
* <dd>relative to the scheme</dd>
* <dt><code>/</code></dt>
* <dd>relative to the server's hostname</dd>
+ * </dl>
*<p>
* The <code>../<code> and ^/ relative URLs may use <code>..<code>
* to remove path elements up to the server root.
@@ -416,4 +419,234 @@ public class SVNUtil
return propLib.resolveExternalsUrl(
external, reposRootUrl, parentDirUrl);
}
+
+ //
+ // Newline translation and keyword expansion
+ //
+ private static final SubstLib substLib = new SubstLib();
+
+ /**
+ * Use the linefeed code point ('<code>\x0a</code>')
+ * for the newline separator.
+ * @see translateStream
+ * @see untranslateStream
+ */
+ public static final byte[] EOL_LF = substLib.EOL_LF;
+
+ /**
+ * Use the carraige-return code point ('<code>\x0d</code>')
+ * for the newline separator.
+ * @see translateStream
+ * @see untranslateStream
+ */
+ public static final byte[] EOL_CR = substLib.EOL_CR;
+
+ /**
+ * Use carriage-return/linefeed sequence ('<code>\x0d\x0a</code>')
+ * for the newline separator.
+ * @see translateStream
+ * @see untranslateStream
+ */
+ public static final byte[] EOL_CRLF = substLib.EOL_CRLF;
+
+
+ /**
+ * Build a dictionary of expanded keyword values, given the
+ * contents of a file's <code>svn:keywords</code> property, its
+ * revision, URL, the date it was committed on, the author of the
+ * commit and teh URL of the repository root.
+ *<p>
+ * Custom keywords defined in <code>svn:keywords</code> properties
+ * are expanded using the provided parameters and in accordance
+ * with the following format substitutions in the
+ * <code>keywordsValue</code>:
+ * <dl>
+ * <dt><code>%a</dt></code>
+ * <dd>The author.</dd>
+ * <dt><code>%b</dt></code>
+ * <dd>The basename of the URL.</dd>
+ * <dt><code>%d</dt></code>
+ * <dd>Short format of the date.</dd>
+ * <dt><code>%D</dt></code>
+ * <dd>Long format of the date.</dd>
+ * <dt><code>%P</dt></code>
+ * <dd>The file's path, relative to the repository root URL.</dd>
+ * <dt><code>%r</dt></code>
+ * <dd>The revision.</dd>
+ * <dt><code>%R</dt></code>
+ * <dd>The URL to the root of the repository.</dd>
+ * <dt><code>%u</dt></code>
+ * <dd>The URL of the file.</dd>
+ * <dt><code>%_</dt></code>
+ * <dd>A space (keyword definitions cannot contain a literal space).</dd>
+ * <dt><code>%%</dt></code>
+ * <dd>A literal '%'.</dd>
+ * <dt><code>%H</dt></code>
+ * <dd>Equivalent to <code>%P%_%r%_%d%_%a</code>.</dd>
+ * <dt><code>%I</dt></code>
+ * <dd>Equivalent to <code>%b%_%r%_%d%_%a</code>.</dd>
+ * </dl>
+ *<p>
+ * Custom keywords are defined by appending '=' to the keyword
+ * name, followed by a string containing any combination of the
+ * format substitutions.
+ *<p>
+ * Any of the <code>revision</code>, <code>url</code>,
+ * <code>reposRootUrl</code>, <code>date</code> and
+ * <code>author</code> parameters may be <code>null</code>, or
+ * {@link Revision#SVN_INVALID_REVNUM} for <code>revision</code>,
+ * to indicate that the information is not present. Each piece of
+ * information that is not present expands to the empty string
+ * wherever it appears in an expanded keyword value. (This can
+ * result in multiple adjacent spaces in the expansion of a
+ * multi-valued keyword such as "<code>Id</code>".)
+ */
+ public static Map<String, byte[]> buildKeywords(byte[] keywordsValue,
+ long revision,
+ String url,
+ String reposRootUrl,
+ Date date,
+ String author)
+ throws SubversionException, ClientException
+ {
+ return substLib.buildKeywords(keywordsValue, revision,
+ url, reposRootUrl, date, author);
+ }
+
+ /**
+ * Return a stream which performs end-of-line translation and
+ * keyword expansion when read from.
+ *<p>
+ * Make sure you close the reurned stream stream to ensure all
+ * data are flushed and cleaned up (this will also close the
+ * provided stream).
+ *<p>
+ * If <code>eolMarker</code> is not <code>null</code>, replace
+ * whatever any end-of-line sequences in the input with
+ * <code>eolMarker</code>. If the input has an inconsistent line
+ * ending style, then:
+ * <ul>
+ * <li>if <code>repairEol</code> is <code>false</code>, then a
+ * subsequent read or other operation on the stream will
+ * generate an error when the inconsistency is detected;</li>
+ * <li>if <code>repaorEol</code> is <code>true</code>, convert any
+ * line ending to <code>eolMarker</code>.<br/>
+ * Recognized line endings are: "\n", "\r", and "\r\n".</li>
+ * </ul>
+ *<p>
+ * Expand or contract keywords using the contents of
+ * <code>keywords</code> as the new values. If
+ * <code>expandKeywords</code> is <code>true</code>, expand
+ * contracted keywords and re-expand expanded keywords; otherwise,
+ * contract expanded keywords and ignore contracted ones.
+ * Keywords not found in the dictionary are ignored (not
+ * contracted or expanded). If the <code>keywords</code> itself
+ * is <code>null</code>, keyword substitution will be altogether
+ * ignored.
+ *<p>
+ * Detect only keywords that are no longer than
+ * <code>SVN_KEYWORD_MAX_LEN</code> bytes (currently: 255),
+ * including the delimiters and the keyword itself.
+ *<p>
+ * Recommendation: if <code>expandKeywords</code> is
+ * <code>false</code>, then you don't care about the keyword
+ * values, so just put <code>null</code> values into the
+ * <code>keywords</code> dictionary.
+ *<p>
+ * If the inner stream implements marking and seeking via
+ * {@link InputStream#mark} and {@link InputStream#reset}, the
+ * translated stream will too.
+ *
+ * @param source the source (untranslated) stream.
+ * @param eolMarker the byte sequence to use as the end-of-line marker;
+ * must be one of {@link #EOL_LF}, {@link #EOL_CR}
+ * or {@link #EOL_CRLF}.
+ * @param repairEol flag to repair end-of-lines; see above
+ * @param keywords the keyword dictionary; see {@link buildKeywords}
+ * @param expandKeywords flag to expand keywords
+ */
+ public static InputStream translateStream(InputStream source,
+ byte[] eolMarker,
+ boolean repairEol,
+ Map<String, byte[]> keywords,
+ boolean expandKeywords)
+ throws SubversionException, ClientException
+ {
+ return substLib.translateInputStream(
+ source, eolMarker, repairEol,
+ keywords, true, expandKeywords,
+ null, Revision.SVN_INVALID_REVNUM,
+ null, null, null, null);
+ }
+
+ /**
+ * Expand keywords and return a stream which performs end-of-line
+ * translation and keyword expansion when read from.
+ * @see buildKeywords
+ * @see translateStream(InputStream,byte[],boolean,Map,boolean)
+ */
+ public static InputStream translateStream(InputStream source,
+ byte[] eolMarker,
+ boolean repairEol,
+ boolean expandKeywords,
+ byte[] keywordsValue,
+ long revision,
+ String url,
+ String reposRootUrl,
+ Date date,
+ String author)
+ throws SubversionException, ClientException
+ {
+ return substLib.translateInputStream(
+ source, eolMarker, repairEol,
+ null, false, expandKeywords,
+ keywordsValue, revision,
+ url, reposRootUrl, date, author);
+ }
+
+ /**
+ * Return a stream which performs end-of-line translation and
+ * keyword expansion when written to. Behaves like
+ * {@link #translateStream(InputStream,byte[],boolean,Map,boolean)},
+ * except that it translates an <code>OutputStream</code> and never
+ * supports marking and seeking.
+ */
+ public static OutputStream translateStream(OutputStream destination,
+ byte[] eolMarker,
+ boolean repairEol,
+ Map<String, byte[]> keywords,
+ boolean expandKeywords)
+ throws SubversionException, ClientException
+ {
+ return substLib.translateOutputStream(
+ destination, eolMarker, repairEol,
+ keywords, true, expandKeywords,
+ null, Revision.SVN_INVALID_REVNUM,
+ null, null, null, null);
+ }
+
+ /**
+ * Expand keywords and return a stream which performs end-of-line
+ * translation and keyword expansion when written to.
+ * @see buildKeywords
+ * @see translateStream(OutputStream,byte[],boolean,Map,boolean)
+ */
+ public static OutputStream translateStream(OutputStream destination,
+ byte[] eolMarker,
+ boolean repairEol,
+ boolean expandKeywords,
+ byte[] keywordsValue,
+ long revision,
+ String url,
+ String reposRootUrl,
+ Date date,
+ String author)
+ throws SubversionException, ClientException
+ {
+ return substLib.translateOutputStream(
+ destination, eolMarker, repairEol,
+ null, false, expandKeywords,
+ keywordsValue, revision,
+ url, reposRootUrl, date, author);
+ }
}
Added: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/SubstLib.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/SubstLib.java?rev=1542401&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/SubstLib.java (added)
+++ subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/SubstLib.java Fri Nov 15 21:08:05 2013
@@ -0,0 +1,119 @@
+/**
+ * @copyright
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ * @endcopyright
+ */
+
+package org.apache.subversion.javahl.util;
+
+import org.apache.subversion.javahl.SVNUtil;
+import org.apache.subversion.javahl.ClientException;
+import org.apache.subversion.javahl.SubversionException;
+import org.apache.subversion.javahl.NativeResources;
+
+import java.util.Date;
+import java.util.Map;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Encapsulates utility functions for substitution and translation
+ * provided by the <code>svn_subst</code> module of
+ * <code>libsvn_subr</code>.
+ * @since 1.9
+ */
+public class SubstLib
+{
+ /**
+ * Load the required native library.
+ */
+ static
+ {
+ NativeResources.loadNativeLibrary();
+ }
+
+ /**
+ * @see SVNUtil.EOL_LF
+ */
+ public static final byte[] EOL_LF = new byte[]{ (byte)10 };
+
+ /**
+ * @see SVNUtil.EOL_CR
+ */
+ public static final byte[] EOL_CR = new byte[]{ (byte)13 };
+
+ /**
+ * @see SVNUtil.EOL_CRLF
+ */
+ public static final byte[] EOL_CRLF = new byte[]{ EOL_CR[0], EOL_LF[0] };
+
+ /**
+ * @see SVNUtil.buildKeywords
+ */
+ public native Map<String, byte[]> buildKeywords(byte[] keywordsValue,
+ long revision,
+ String url,
+ String reposRootUrl,
+ Date date,
+ String author)
+ throws SubversionException, ClientException;
+
+ /**
+ * @see SVNUtil.translateStream
+ */
+ public /*native*/ InputStream translateInputStream(
+ InputStream source,
+ byte[] eolMarker,
+ boolean repairEol,
+ Map<String, byte[]> keywords,
+ boolean useKeywordsMap,
+ boolean expandKeywords,
+ byte[] keywordsValue,
+ long revision,
+ String url,
+ String reposRootUrl,
+ Date date,
+ String author)
+ throws SubversionException, ClientException//;
+ {
+ throw new RuntimeException("Not implemented: SubstLib.translateInputStream");
+ }
+
+ /**
+ * @see SVNUtil.translateStream
+ */
+ public /*native*/ OutputStream translateOutputStream(
+ OutputStream destination,
+ byte[] eolMarker,
+ boolean repairEol,
+ Map<String, byte[]> keywords,
+ boolean useKeywordsMap,
+ boolean expandKeywords,
+ byte[] keywordsValue,
+ long revision,
+ String url,
+ String reposRootUrl,
+ Date date,
+ String author)
+ throws SubversionException, ClientException//;
+ {
+ throw new RuntimeException("Not implemented: SubstLib.translateOutputStream");
+ }
+}
Propchange: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/SubstLib.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java?rev=1542401&r1=1542400&r2=1542401&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java (original)
+++ subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java Fri Nov 15 21:08:05 2013
@@ -35,6 +35,7 @@ import java.util.Arrays;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import java.util.Map;
/**
* Tests the JavaHL SVNUtil APIs.
@@ -392,4 +393,20 @@ public class UtilTests extends SVNTests
new ExternalItem("x", "//a/b/c", null, null),
"http://a", "http://a/b"));
}
+
+ public void testBuildKeywords() throws Throwable
+ {
+ final byte[] kwval = "TEST=%H%_%b%_%u".getBytes();
+
+ Map<String, byte[]> result;
+
+ result = SVNUtil.buildKeywords(kwval, Revision.SVN_INVALID_REVNUM,
+ null, null, null, null);
+ assertEquals(" ", new String(result.get("TEST")));
+
+ result = SVNUtil.buildKeywords(kwval, 48, "http://a/b/c",
+ "http://a", new Date(1), "X");
+ assertEquals("b/c 48 1970-01-01 00:00:00Z X c http://a/b/c",
+ new String(result.get("TEST")));
+ }
}