1 /*----------------------------------------------------------------------------
2 Name: XmlBlasterManaged.cpp
3 Project: xmlBlaster.org
4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
5 Author: "Marcel Ruff" <xmlBlaster@marcelruff.info>
6 Note: Managed C++ wrapper around unmanaged C xmlBlaster client library DLL
7 Todo: Currently only works for one connection as i don't know how to pass
8 'XmlBlasterAccessM^ xmlBlasterAccess' to myUpdate() function
9 -----------------------------------------------------------------------------*/
10 #ifdef _MANAGED // If /clr flag is set
11
12 #include <iostream>
13 #include "XmlBlasterManaged.h"
14 #include "XmlBlasterAccessUnparsed.h"
15
16 using namespace System;
17 using namespace System::Text;
18 using namespace System::Collections;
19
20 using namespace org::xmlBlaster::client;
21
22 /* Which multibyte string conversion to use, "toAnsi()" or "toUtf8()" */
23 #define TO_MBS toAnsi
24 #define FROM_MBS fromUtf8
25
26
27 static void MarshalString(System::String^ s, std::string& os, const char *prefix=0) {
28 if (prefix != 0) os = prefix;
29 using namespace System::Runtime::InteropServices;
30 const char* chars =
31 (const char*)(Marshal::StringToHGlobalAnsi(s)).ToPointer();
32 os += chars;
33 Marshal::FreeHGlobal(IntPtr((void*)chars));
34 }
35
36 /**
37 * @return is malloced, you need to free it
38 */
39 static char *toAnsi(System::String^ s, const char *prefix=0) {
40 std::string os;
41 MarshalString(s, os, prefix);
42 return strcpyAlloc(os.c_str());
43 }
44
45 static System::String^ fromUtf8(const char *encodedBytes) {
46 std::string s(encodedBytes);
47 String ^str= gcnew String(s.c_str());
48
49 //System::String^ str;
50 //str = encodedBytes;
51 return str;
52 /*
53 //System::String^ str(p);
54 UTF8Encoding^ utf8 = gcnew UTF8Encoding;
55 const int len = (int)strlen(encodedBytes);
56 array<Byte>^ arr;
57 for (int i=0; (encodedBytes+i) != 0; i++)
58 arr[i] = (Byte)encodedBytes[i];
59 System::String^ decodedString = utf8->GetString(arr);
60 return decodedString;
61 */
62 }
63
64
65 /**
66 * @return is malloced, you need to free it
67 */
68 static char *toUtf8(String^ unicodeString, const char *prefix=0) {
69 UTF8Encoding^ utf8 = gcnew UTF8Encoding;
70 Console::WriteLine("original=" + unicodeString );
71 array<Byte>^encodedBytes = utf8->GetBytes( unicodeString );
72 //Console::WriteLine();
73 Console::WriteLine( "Encoded bytes:" );
74
75 int prefixLen = (prefix == 0) ? 0 : (int)strlen(prefix);
76 int len = prefixLen + encodedBytes->Length + 1;
77
78 char *mbs = (char *)malloc(len);
79 *(mbs+len-1) = 0;
80 if (prefixLen > 0)
81 strncpy0(mbs, prefix, prefixLen+1);
82
83 int i=prefixLen;
84 IEnumerator^ myEnum = encodedBytes->GetEnumerator();
85 while ( myEnum->MoveNext() )
86 {
87 Byte b = safe_cast<Byte>(myEnum->Current);
88 mbs[i] = b;
89 Console::Write( "[{0}]", b );
90 }
91 return mbs;
92 }
93
94
95 /**
96 * Here we receive the callback messages from xmlBlaster
97 * @param msgUnitArr The received messages
98 * @param userData Is the corresponding XmlBlasterAccessUnparsed * pointer
99 * @param exception An OUT parameter to transport back an exception
100 * @see UpdateFp in XmlBlasterAccessUnparsed.h
101 * @see UpdateFp in CallbackServerUnparsed.h
102 */
103 static bool myUpdate(::MsgUnitArr *msgUnitArr, void *userData,
104 ::XmlBlasterException *exception)
105 {
106 size_t i;
107 bool testException = false;
108 ::XmlBlasterAccessUnparsed *connection_ = (::XmlBlasterAccessUnparsed *)userData;
109 //Cannot convert an unmanaged type to a managed type
110 //XmlBlasterAccessM^ xmlBlasterAccess = static_cast<XmlBlasterAccessM^>(connection_->userObject);
111
112 for (i=0; i<msgUnitArr->len; i++) {
113 char *xml = ::messageUnitToXml(&msgUnitArr->msgUnitArr[i]);
114 printf("[client] CALLBACK update(): Asynchronous message update arrived:%s\n",
115 xml);
116 ::xmlBlasterFree(xml);
117 msgUnitArr->msgUnitArr[i].responseQos =
118 strcpyAlloc("<qos><state id='OK'/></qos>");
119 /* Return QoS: Everything is OK */
120 }
121 return true;
122 }
123
124 XmlBlasterAccessM::XmlBlasterAccessM(Hashtable ^props) {
125 System::Console::WriteLine("Hello from xmlBlasterClientC CLR");
126
127 int argc = (2*props->Count)+1;
128 const char ** ptr = (const char **)malloc(argc*sizeof(char *));
129 ptr[0] = strcpyAlloc("someClientName"); // TODO
130 IDictionaryEnumerator^ myEnumerator = props->GetEnumerator();
131 int i=1;
132 while (myEnumerator->MoveNext()) {
133 //System::Console::WriteLine("\t{0}:\t{1}", myEnumerator->Key, myEnumerator->Value);
134 ptr[i] = TO_MBS((System::String ^)myEnumerator->Key, "-");
135 printf("key='%s'\n", ptr[i]);
136 i++;
137 ptr[i] = TO_MBS((System::String ^)myEnumerator->Value);
138 printf("value='%s'\n", ptr[i]);
139 //std::cout << "UTF8 result is " << ptr[i] << std::endl;
140 i++;
141 }
142
143 this->connection_ = getXmlBlasterAccessUnparsed(argc, (const char* const*)ptr);
144 // Cannot convert a managed type to an unmanaged type
145 //this->connection_->userObject = (void *)this; // Transports us to the myUpdate() method
146 // this->connection_->log = myLogger; // Register our own logging function
147 // this->connection_->logUserP = this; // Pass ourself to myLogger()
148 }
149
150 XmlBlasterAccessM::~XmlBlasterAccessM() {
151 shutdown();
152 }
153
154 String ^XmlBlasterAccessM::connect(String ^connectQos) {
155 ::XmlBlasterException xmlBlasterException;
156 check();
157 if (connection_->initialize(connection_, (UpdateFp)myUpdate, &xmlBlasterException) == false) {
158 printf("[client] Connection to xmlBlaster failed,"
159 " please start the server or check your configuration\n");
160 shutdown();
161 throw gcnew XmlBlasterExceptionM(FROM_MBS(xmlBlasterException.errorCode), FROM_MBS(xmlBlasterException.message));
162 }
163
164 char *retQos = connection_->connect(connection_, TO_MBS(connectQos),
165 (UpdateFp)myUpdate, &xmlBlasterException);
166 if (*xmlBlasterException.errorCode != 0) {
167 printf("[client] Caught exception during connect errorCode=%s, message=%s\n",
168 xmlBlasterException.errorCode, xmlBlasterException.message);
169 shutdown();
170 throw gcnew XmlBlasterExceptionM(FROM_MBS(xmlBlasterException.errorCode), FROM_MBS(xmlBlasterException.message));
171 }
172 String^ ret = FROM_MBS(retQos);
173 xmlBlasterFree(retQos);
174 printf("[client] Connected to xmlBlaster ...\n");
175 return ret;
176 }
177
178 System::Boolean XmlBlasterAccessM::disconnect(String ^qos) {
179
180 ::XmlBlasterException xmlBlasterException;
181 check();
182 if (this->connection_->disconnect(this->connection_, TO_MBS(qos), &xmlBlasterException) == false) {
183 printf("[client] Caught exception in disconnect, errorCode=%s, message=%s\n",
184 xmlBlasterException.errorCode, xmlBlasterException.message);
185 shutdown();
186 return false;
187 }
188 return true;
189 }
190
191 void XmlBlasterAccessM::check() {
192 if (this->connection_ == 0) {
193 throw gcnew XmlBlasterExceptionM(L"user.illegalArgument", L"The connection is shutdown, please create another XmlBlasterAccessM instance");
194 }
195 }
196
197 void XmlBlasterAccessM::shutdown() {
198 freeXmlBlasterAccessUnparsed(this->connection_);
199 this->connection_ = 0;
200 }
201
202 String ^XmlBlasterAccessM::getVersion() {
203 check();
204 const char *version = ::getXmlBlasterVersion();
205 return FROM_MBS(version);
206 }
207
208 String ^XmlBlasterAccessM::getUsage() {
209 check();
210 char usage[XMLBLASTER_MAX_USAGE_LEN];
211 ::xmlBlasterAccessUnparsedUsage(usage);
212 return FROM_MBS(usage);
213 }
214
215 #endif // _MANAGED
syntax highlighted by Code2HTML, v. 0.9.1