java input stream adapters working
[cvc5.git] / src / bindings / java_stream_adapters.h
1 /********************* */
2 /*! \file java_stream_adapters.h
3 ** \verbatim
4 ** Original author: mdeters
5 ** Major contributors: none
6 ** Minor contributors (to current version): none
7 ** This file is part of the CVC4 prototype.
8 ** Copyright (c) 2009-2012 New York University and The University of Iowa
9 ** See the file COPYING in the top-level source directory for licensing
10 ** information.\endverbatim
11 **
12 ** \brief An OutputStream adapter for the Java bindings
13 **
14 ** An OutputStream adapter for the Java bindings. This works with a lot
15 ** of help from SWIG, and custom typemaps in the ".i" SWIG interface files
16 ** for CVC4. The basic idea is that, when a CVC4 function with a
17 ** std::ostream& parameter is called, a Java-side binding is generated
18 ** taking a java.io.OutputStream. Now, the problem is that std::ostream
19 ** has no Java equivalent, and java.io.OutputStream has no C++ equivalent,
20 ** so we use this class (which exists on both sides) as the go-between.
21 ** The wrapper connecting the Java function (taking an OutputStream) and
22 ** the C++ function (taking an ostream) creates a JavaOutputStreamAdapter,
23 ** and call the C++ function with the stringstream inside. After the call,
24 ** the generated stream material is collected and output to the Java-side
25 ** OutputStream.
26 **/
27
28 // private to the bindings layer
29 #ifndef SWIGJAVA
30 # error This should only be included from the Java bindings layer.
31 #endif /* SWIGJAVA */
32
33 #include <sstream>
34 #include <set>
35 #include <cassert>
36 #include <iostream>
37 #include <string>
38 #include <jni.h>
39
40 #ifndef __CVC4__BINDINGS__JAVA_STREAM_ADAPTERS_H
41 #define __CVC4__BINDINGS__JAVA_STREAM_ADAPTERS_H
42
43 namespace CVC4 {
44
45 class JavaOutputStreamAdapter {
46 std::stringstream d_ss;
47
48 public:
49 JavaOutputStreamAdapter() { }
50
51 std::string toString() { return d_ss.str(); }
52
53 };/* class JavaOutputStreamAdapter */
54
55 class JavaInputStreamAdapter : public std::stringstream {
56 static std::set<JavaInputStreamAdapter*> s_adapters;
57 jobject inputStream;
58
59 JavaInputStreamAdapter& operator=(const JavaInputStreamAdapter&);
60 JavaInputStreamAdapter(const JavaInputStreamAdapter&);
61
62 public:
63 JavaInputStreamAdapter(jobject inputStream) : inputStream(inputStream) {
64 s_adapters.insert(this);
65 }
66
67 ~JavaInputStreamAdapter() {
68 s_adapters.erase(this);
69 }
70
71 static void pullAdapters(JNIEnv* jenv) {
72 for(std::set<JavaInputStreamAdapter*>::iterator i = s_adapters.begin();
73 i != s_adapters.end();
74 ++i) {
75 (*i)->pull(jenv);
76 }
77 }
78
79 jobject getInputStream() const {
80 return inputStream;
81 }
82
83 void pull(JNIEnv* jenv) {
84 if(fail() || eof()) {
85 clear();
86 }
87 jclass clazz = jenv->FindClass("java/io/InputStream");
88 assert(clazz != NULL && jenv->ExceptionOccurred() == NULL);
89 jmethodID method = jenv->GetMethodID(clazz, "available", "()I");
90 assert(method != NULL && jenv->ExceptionOccurred() == NULL);
91 jint available = jenv->CallIntMethod(inputStream, method);
92 assert(jenv->ExceptionOccurred() == NULL);
93 jbyteArray bytes = jenv->NewByteArray(available);
94 assert(bytes != NULL && jenv->ExceptionOccurred() == NULL);
95 method = jenv->GetMethodID(clazz, "read", "([B)I");
96 assert(method != NULL && jenv->ExceptionOccurred() == NULL);
97 jint nread = jenv->CallIntMethod(inputStream, method, bytes);
98 assert(jenv->ExceptionOccurred() == NULL);
99 jbyte* bptr = jenv->GetByteArrayElements(bytes, NULL);
100 assert(jenv->ExceptionOccurred() == NULL);
101 std::copy(bptr, bptr + nread, std::ostream_iterator<char>(*this));
102 *this << std::flush;
103 jenv->ReleaseByteArrayElements(bytes, bptr, 0);
104 assert(jenv->ExceptionOccurred() == NULL);
105 assert(good());
106 assert(!eof());
107 }
108
109 };/* class JavaInputStreamAdapter */
110
111 }/* CVC4 namespace */
112
113 #endif /* __CVC4__BINDINGS__JAVA_STREAM_ADAPTERS_H */