1 /**
2  * @copyright
3  * ====================================================================
4  *    Licensed to the Apache Software Foundation (ASF) under one
5  *    or more contributor license agreements.  See the NOTICE file
6  *    distributed with this work for additional information
7  *    regarding copyright ownership.  The ASF licenses this file
8  *    to you under the Apache License, Version 2.0 (the
9  *    "License"); you may not use this file except in compliance
10  *    with the License.  You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  *    Unless required by applicable law or agreed to in writing,
15  *    software distributed under the License is distributed on an
16  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  *    KIND, either express or implied.  See the License for the
18  *    specific language governing permissions and limitations
19  *    under the License.
20  * ====================================================================
21  * @endcopyright
22  *
23  * @file OutputStream.cpp
24  * @brief Implementation of the class OutputStream
25  */
26 
27 #include "OutputStream.h"
28 #include "JNIUtil.h"
29 #include "JNIByteArray.h"
30 
31 /**
32  * Create an OutputStream object.
33  * @param jthis the Java object to be stored
34  */
OutputStream(jobject jthis)35 OutputStream::OutputStream(jobject jthis)
36 {
37   m_jthis = jthis;
38 }
39 
40 /**
41  * Destroy an Inputer object.
42  */
~OutputStream()43 OutputStream::~OutputStream()
44 {
45   // The m_jthis does not need to be destroyed, because it is the
46   // passed in parameter to the Java method.
47 }
48 
49 /**
50  * Create a svn_stream_t structure for this object.  This will be used
51  * as an output stream by Subversion.
52  * @param pool  the pool, from which the structure is allocated
53  * @return the output stream
54  */
getStream(const SVN::Pool & pool)55 svn_stream_t *OutputStream::getStream(const SVN::Pool &pool)
56 {
57   // Create a stream with this as the baton and set the write and
58   // close functions.
59   svn_stream_t *ret = svn_stream_create(this, pool.getPool());
60   svn_stream_set_write(ret, OutputStream::write);
61   svn_stream_set_close(ret, OutputStream::close);
62   return ret;
63 }
64 
65 /**
66  * Implements svn_write_fn_t to write data out from Subversion.
67  * @param baton     an OutputStream object for the callback
68  * @param buffer    the buffer for the write data
69  * @param len       on input the buffer len, on output the number of written
70  *                  bytes
71  * @return a subversion error or SVN_NO_ERROR
72  */
write(void * baton,const char * buffer,apr_size_t * len)73 svn_error_t *OutputStream::write(void *baton, const char *buffer,
74                                  apr_size_t *len)
75 {
76   JNIEnv *env = JNIUtil::getEnv();
77 
78   // An object of our class is passed in as the baton.
79   OutputStream *that = static_cast<OutputStream *>(baton);
80 
81   // The method id will not change during the time this library is
82   // loaded, so it can be cached.
83   static jmethodID mid = 0;
84   if (mid == 0)
85     {
86       jclass clazz = env->FindClass("java/io/OutputStream");
87       if (JNIUtil::isJavaExceptionThrown())
88         return SVN_NO_ERROR;
89 
90       mid = env->GetMethodID(clazz, "write", "([B)V");
91       if (JNIUtil::isJavaExceptionThrown() || mid == 0)
92         return SVN_NO_ERROR;
93 
94       env->DeleteLocalRef(clazz);
95     }
96 
97   // convert the data to a Java byte array
98   jbyteArray data = JNIUtil::makeJByteArray(buffer, static_cast<int>(*len));
99   if (JNIUtil::isJavaExceptionThrown())
100     return SVN_NO_ERROR;
101 
102   // write the data
103   env->CallObjectMethod(that->m_jthis, mid, data);
104   if (JNIUtil::isJavaExceptionThrown())
105     return SVN_NO_ERROR;
106 
107   env->DeleteLocalRef(data);
108 
109   return SVN_NO_ERROR;
110 }
111 
112 /**
113  * Implements svn_close_fn_t to close the output stream.
114  * @param baton     an OutputStream object for the callback
115  * @return a subversion error or SVN_NO_ERROR
116  */
close(void * baton)117 svn_error_t *OutputStream::close(void *baton)
118 {
119   JNIEnv *env = JNIUtil::getEnv();
120 
121   // An object of our class is passed in as the baton
122   OutputStream *that = reinterpret_cast<OutputStream*>(baton);
123 
124   // The method id will not change during the time this library is
125   // loaded, so it can be cached.
126   static jmethodID mid = 0;
127   if (mid == 0)
128     {
129       jclass clazz = env->FindClass("java/io/OutputStream");
130       if (JNIUtil::isJavaExceptionThrown())
131         return SVN_NO_ERROR;
132 
133       mid = env->GetMethodID(clazz, "close", "()V");
134       if (JNIUtil::isJavaExceptionThrown() || mid == 0)
135         return SVN_NO_ERROR;
136 
137       env->DeleteLocalRef(clazz);
138     }
139 
140   // Call the Java object, to close the stream.
141   env->CallVoidMethod(that->m_jthis, mid);
142   // No need to check for exception here because we return anyway.
143 
144   return SVN_NO_ERROR;
145 }
146