Merge branch 'master' of github.com:tiliang/CVC4
[cvc5.git] / src / bindings / java_stream_adapters.h
1 /********************* */
2 /*! \file java_stream_adapters.h
3 ** \verbatim
4 ** Original author: Morgan Deters
5 ** Major contributors: none
6 ** Minor contributors (to current version): none
7 ** This file is part of the CVC4 project.
8 ** Copyright (c) 2009-2013 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 : public std::ostringstream {
46 public:
47 std::string toString() { return str(); }
48 };/* class JavaOutputStreamAdapter */
49
50 class JavaInputStreamAdapter : public std::stringstream {
51 static std::set<JavaInputStreamAdapter*> s_adapters;
52 jobject inputStream;
53
54 JavaInputStreamAdapter& operator=(const JavaInputStreamAdapter&);
55 JavaInputStreamAdapter(const JavaInputStreamAdapter&);
56
57 public:
58 JavaInputStreamAdapter(jobject inputStream) : inputStream(inputStream) {
59 s_adapters.insert(this);
60 }
61
62 ~JavaInputStreamAdapter() {
63 s_adapters.erase(this);
64 }
65
66 static void pullAdapters(JNIEnv* jenv) {
67 for(std::set<JavaInputStreamAdapter*>::iterator i = s_adapters.begin();
68 i != s_adapters.end();
69 ++i) {
70 (*i)->pull(jenv);
71 }
72 }
73
74 jobject getInputStream() const {
75 return inputStream;
76 }
77
78 void pull(JNIEnv* jenv) {
79 if(fail() || eof()) {
80 clear();
81 }
82 jclass clazz = jenv->FindClass("java/io/InputStream");
83 assert(clazz != NULL && jenv->ExceptionOccurred() == NULL);
84 jmethodID method = jenv->GetMethodID(clazz, "available", "()I");
85 assert(method != NULL && jenv->ExceptionOccurred() == NULL);
86 jint available = jenv->CallIntMethod(inputStream, method);
87 assert(jenv->ExceptionOccurred() == NULL);
88 jbyteArray bytes = jenv->NewByteArray(available);
89 assert(bytes != NULL && jenv->ExceptionOccurred() == NULL);
90 method = jenv->GetMethodID(clazz, "read", "([B)I");
91 assert(method != NULL && jenv->ExceptionOccurred() == NULL);
92 jint nread = jenv->CallIntMethod(inputStream, method, bytes);
93 assert(jenv->ExceptionOccurred() == NULL);
94 jbyte* bptr = jenv->GetByteArrayElements(bytes, NULL);
95 assert(jenv->ExceptionOccurred() == NULL);
96 std::copy(bptr, bptr + nread, std::ostream_iterator<char>(*this));
97 *this << std::flush;
98 jenv->ReleaseByteArrayElements(bytes, bptr, 0);
99 assert(jenv->ExceptionOccurred() == NULL);
100 assert(good());
101 assert(!eof());
102 }
103
104 };/* class JavaInputStreamAdapter */
105
106 }/* CVC4 namespace */
107
108 #endif /* __CVC4__BINDINGS__JAVA_STREAM_ADAPTERS_H */