00001 /*---------------------------------------------------------------------------- 00002 Name: XmlBlasterManaged.cpp 00003 Project: xmlBlaster.org 00004 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file 00005 Author: "Marcel Ruff" <xmlBlaster@marcelruff.info> 00006 Note: Managed C++ wrapper around unmanaged C xmlBlaster client library DLL 00007 Todo: Currently only works for one connection as i don't know how to pass 00008 'XmlBlasterAccessM^ xmlBlasterAccess' to myUpdate() function 00009 -----------------------------------------------------------------------------*/ 00010 #ifdef _MANAGED // If /clr flag is set 00011 00012 #include <iostream> 00013 #include "XmlBlasterManaged.h" 00014 #include "XmlBlasterAccessUnparsed.h" 00015 00016 using namespace System; 00017 using namespace System::Text; 00018 using namespace System::Collections; 00019 00020 using namespace org::xmlBlaster::client; 00021 00022 /* Which multibyte string conversion to use, "toAnsi()" or "toUtf8()" */ 00023 #define TO_MBS toAnsi 00024 #define FROM_MBS fromUtf8 00025 00026 00027 static void MarshalString(System::String^ s, std::string& os, const char *prefix=0) { 00028 if (prefix != 0) os = prefix; 00029 using namespace System::Runtime::InteropServices; 00030 const char* chars = 00031 (const char*)(Marshal::StringToHGlobalAnsi(s)).ToPointer(); 00032 os += chars; 00033 Marshal::FreeHGlobal(IntPtr((void*)chars)); 00034 } 00035 00039 static char *toAnsi(System::String^ s, const char *prefix=0) { 00040 std::string os; 00041 MarshalString(s, os, prefix); 00042 return strcpyAlloc(os.c_str()); 00043 } 00044 00045 static System::String^ fromUtf8(const char *encodedBytes) { 00046 std::string s(encodedBytes); 00047 String ^str= gcnew String(s.c_str()); 00048 00049 //System::String^ str; 00050 //str = encodedBytes; 00051 return str; 00052 /* 00053 //System::String^ str(p); 00054 UTF8Encoding^ utf8 = gcnew UTF8Encoding; 00055 const int len = (int)strlen(encodedBytes); 00056 array<Byte>^ arr; 00057 for (int i=0; (encodedBytes+i) != 0; i++) 00058 arr[i] = (Byte)encodedBytes[i]; 00059 System::String^ decodedString = utf8->GetString(arr); 00060 return decodedString; 00061 */ 00062 } 00063 00064 00068 static char *toUtf8(String^ unicodeString, const char *prefix=0) { 00069 UTF8Encoding^ utf8 = gcnew UTF8Encoding; 00070 Console::WriteLine("original=" + unicodeString ); 00071 array<Byte>^encodedBytes = utf8->GetBytes( unicodeString ); 00072 //Console::WriteLine(); 00073 Console::WriteLine( "Encoded bytes:" ); 00074 00075 int prefixLen = (prefix == 0) ? 0 : (int)strlen(prefix); 00076 int len = prefixLen + encodedBytes->Length + 1; 00077 00078 char *mbs = (char *)malloc(len); 00079 *(mbs+len-1) = 0; 00080 if (prefixLen > 0) 00081 strncpy0(mbs, prefix, prefixLen+1); 00082 00083 int i=prefixLen; 00084 IEnumerator^ myEnum = encodedBytes->GetEnumerator(); 00085 while ( myEnum->MoveNext() ) 00086 { 00087 Byte b = safe_cast<Byte>(myEnum->Current); 00088 mbs[i] = b; 00089 Console::Write( "[{0}]", b ); 00090 } 00091 return mbs; 00092 } 00093 00094 00103 static bool myUpdate(::MsgUnitArr *msgUnitArr, void *userData, 00104 ::XmlBlasterException *exception) 00105 { 00106 size_t i; 00107 bool testException = false; 00108 ::XmlBlasterAccessUnparsed *connection_ = (::XmlBlasterAccessUnparsed *)userData; 00109 //Cannot convert an unmanaged type to a managed type 00110 //XmlBlasterAccessM^ xmlBlasterAccess = static_cast<XmlBlasterAccessM^>(connection_->userObject); 00111 00112 for (i=0; i<msgUnitArr->len; i++) { 00113 char *xml = ::messageUnitToXml(&msgUnitArr->msgUnitArr[i]); 00114 printf("[client] CALLBACK update(): Asynchronous message update arrived:%s\n", 00115 xml); 00116 ::xmlBlasterFree(xml); 00117 msgUnitArr->msgUnitArr[i].responseQos = 00118 strcpyAlloc("<qos><state id='OK'/></qos>"); 00119 /* Return QoS: Everything is OK */ 00120 } 00121 return true; 00122 } 00123 00124 XmlBlasterAccessM::XmlBlasterAccessM(Hashtable ^props) { 00125 System::Console::WriteLine("Hello from xmlBlasterClientC CLR"); 00126 00127 int argc = (2*props->Count)+1; 00128 const char ** ptr = (const char **)malloc(argc*sizeof(char *)); 00129 ptr[0] = strcpyAlloc("someClientName"); // TODO 00130 IDictionaryEnumerator^ myEnumerator = props->GetEnumerator(); 00131 int i=1; 00132 while (myEnumerator->MoveNext()) { 00133 //System::Console::WriteLine("\t{0}:\t{1}", myEnumerator->Key, myEnumerator->Value); 00134 ptr[i] = TO_MBS((System::String ^)myEnumerator->Key, "-"); 00135 printf("key='%s'\n", ptr[i]); 00136 i++; 00137 ptr[i] = TO_MBS((System::String ^)myEnumerator->Value); 00138 printf("value='%s'\n", ptr[i]); 00139 //std::cout << "UTF8 result is " << ptr[i] << std::endl; 00140 i++; 00141 } 00142 00143 this->connection_ = getXmlBlasterAccessUnparsed(argc, (const char* const*)ptr); 00144 // Cannot convert a managed type to an unmanaged type 00145 //this->connection_->userObject = (void *)this; // Transports us to the myUpdate() method 00146 // this->connection_->log = myLogger; // Register our own logging function 00147 // this->connection_->logUserP = this; // Pass ourself to myLogger() 00148 } 00149 00150 XmlBlasterAccessM::~XmlBlasterAccessM() { 00151 shutdown(); 00152 } 00153 00154 String ^XmlBlasterAccessM::connect(String ^connectQos) { 00155 ::XmlBlasterException xmlBlasterException; 00156 check(); 00157 if (connection_->initialize(connection_, (UpdateFp)myUpdate, &xmlBlasterException) == false) { 00158 printf("[client] Connection to xmlBlaster failed," 00159 " please start the server or check your configuration\n"); 00160 shutdown(); 00161 throw gcnew XmlBlasterExceptionM(FROM_MBS(xmlBlasterException.errorCode), FROM_MBS(xmlBlasterException.message)); 00162 } 00163 00164 char *retQos = connection_->connect(connection_, TO_MBS(connectQos), 00165 (UpdateFp)myUpdate, &xmlBlasterException); 00166 if (*xmlBlasterException.errorCode != 0) { 00167 printf("[client] Caught exception during connect errorCode=%s, message=%s\n", 00168 xmlBlasterException.errorCode, xmlBlasterException.message); 00169 shutdown(); 00170 throw gcnew XmlBlasterExceptionM(FROM_MBS(xmlBlasterException.errorCode), FROM_MBS(xmlBlasterException.message)); 00171 } 00172 String^ ret = FROM_MBS(retQos); 00173 xmlBlasterFree(retQos); 00174 printf("[client] Connected to xmlBlaster ...\n"); 00175 return ret; 00176 } 00177 00178 System::Boolean XmlBlasterAccessM::disconnect(String ^qos) { 00179 00180 ::XmlBlasterException xmlBlasterException; 00181 check(); 00182 if (this->connection_->disconnect(this->connection_, TO_MBS(qos), &xmlBlasterException) == false) { 00183 printf("[client] Caught exception in disconnect, errorCode=%s, message=%s\n", 00184 xmlBlasterException.errorCode, xmlBlasterException.message); 00185 shutdown(); 00186 return false; 00187 } 00188 return true; 00189 } 00190 00191 void XmlBlasterAccessM::check() { 00192 if (this->connection_ == 0) { 00193 throw gcnew XmlBlasterExceptionM(L"user.illegalArgument", L"The connection is shutdown, please create another XmlBlasterAccessM instance"); 00194 } 00195 } 00196 00197 void XmlBlasterAccessM::shutdown() { 00198 freeXmlBlasterAccessUnparsed(this->connection_); 00199 this->connection_ = 0; 00200 } 00201 00202 String ^XmlBlasterAccessM::getVersion() { 00203 check(); 00204 const char *version = ::getXmlBlasterVersion(); 00205 return FROM_MBS(version); 00206 } 00207 00208 String ^XmlBlasterAccessM::getUsage() { 00209 check(); 00210 char usage[XMLBLASTER_MAX_USAGE_LEN]; 00211 ::xmlBlasterAccessUnparsedUsage(usage); 00212 return FROM_MBS(usage); 00213 } 00214 00215 #endif // _MANAGED