]> rtime.felk.cvut.cz Git - orte.git/blob - orte/libjorte/JORTESubscriptionCreate.c
JORTE: document hack that 'bypasses' erratic bug in liborte
[orte.git] / orte / libjorte / JORTESubscriptionCreate.c
1 /* JORTESubscriptionCreate.c  */
2
3 /**
4   * This code provides conversion between JAVA a C environments.
5   * The C functions are calling here and results are send to JAVA
6   * native functions. It uses the header pregenerated by JAVA
7   * (by command 'javah -jni class_with_native_function')
8   *
9   * @author Lukas Pokorny (lukas_pokorny@centrum.cz)
10   * @author CTU FEE Prague - Department of Control Engineering (dce.felk.cvut.cz)
11   * @author Project ORTE - OCERA Real Time Ethernet (www.ocera.org)
12   * @author dedication to Kj
13   * @version 0.1
14   *
15   *
16   * This program is free software; you can redistribute it and/or modify
17   * it under the terms of the GNU General Public License as published by
18   * the Free Software Foundation; either version 2 of the License, or
19   * (at your option) any later version.
20   *
21   * This program is distributed in the hope that it will be useful,
22   * but WITHOUT ANY WARRANTY; without even the implied warranty of
23   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24   * GNU General Public License for more details.
25   *
26   */
27
28
29 #include <stdlib.h>
30 #include <inttypes.h>
31 #include <string.h>
32
33 // library header file's path
34 #include "orte_all.h"
35 // pregenerated header
36 #include "jorte/org_ocera_orte_Subscription.h"
37 // enable TEST_STAGE run level
38 #include "jorte/4all.h"
39 // new data types
40 #include "jorte/jorte_typedefs_defines.h"
41 #include "jorte/jorte_protos_api.h"
42
43 /* ****************************************************************** *
44  *                           CallBack function                        *
45  * ****************************************************************** */
46
47 void
48 recvCallBack(const ORTERecvInfo *info, void *vinstance, void *recvCallBackParam)
49 {
50   // jni varialbles
51   JavaVM          *jvm = 0;
52   JNIEnv          *env = 0;
53   jobject          obj_bo = 0;
54
55   JORTECallbackContext_t   *callback_cont;
56
57   // HACK: if the subscriber has been destroyed, return
58   if ((*(JORTECallbackContext_t **)recvCallBackParam) == 0)
59     return;
60
61   callback_cont = *((JORTECallbackContext_t **)recvCallBackParam);
62
63   #ifdef TEST_STAGE
64   printf("\n\n:c: --------------- recvCallBack called.. --------------- \n");
65   #endif
66
67   do {
68     // set local variables from struct
69     jvm = callback_cont->jvm;
70     // get env
71     if((*jvm)->AttachCurrentThread(jvm,
72                                 #ifdef __ANDROID__
73                                 &env,
74                                 #else
75                                 (void **)&env,
76                                 #endif
77                                 NULL) != JNI_OK)
78     {
79       #ifdef TEST_STAGE
80       printf(":!c: recvCallBack: AttachCurrentThread() failed \n");
81       #endif
82       return;
83     }
84
85     // set byte order only if it differs from that currently set
86     if (info->data_endian != callback_cont->cur_endian) {
87       if (info->data_endian == BigEndian) {
88         obj_bo = callback_cont->obj_BO_BE;
89         callback_cont->cur_endian = BigEndian;
90       } else {
91         obj_bo = callback_cont->obj_BO_LE;
92         callback_cont->cur_endian = LittleEndian;
93       }
94
95       // set byte order to ByteBuffer
96       (*env)->CallObjectMethod(env, callback_cont->obj_buf, callback_cont->mid_order, obj_bo);
97     }
98
99       #ifdef TEST_STAGE
100     printf(":c: #0 \n");
101     printf(":c: env = %#" PRIxPTR ", obj_msg = %#" PRIxPTR " \n", (intptr_t)env, (intptr_t)callback_cont->msg);
102       #endif
103
104     ////////////////////////////////////////////////////
105     memcpy(callback_cont->info_buf, (void*)info, sizeof(ORTERecvInfo));
106     ////////////////////////////////////////////////////
107
108     // control print - only in TEST_STAGE
109     #ifdef TEST_STAGE
110     printf(":c: rinfo created :] \n");
111     printf(":c:----- ORTERecvInfo members  ------ \n");
112     printf(":c:    recvStatus: %#x \n", info->status);
113     printf(":c:    senderGuid: hid = %#" PRIx32 ", aid = %#" PRIx32 ", oid = %#" PRIx32 " \n",
114            info->senderGUID.hid, info->senderGUID.aid, info->senderGUID.oid);
115     printf(":c:         topic: %s \n", info->topic);
116     printf(":c:          type: %s \n", info->type);
117     printf(":c: localTimeRecv: sec = %" PRId32 ", fract = %" PRIu32 " \n",
118            info->localTimeReceived.seconds, info->localTimeReceived.fraction);
119     printf(":c: remoteTimePub: sec = %" PRId32 ", fract = %" PRIu32 " \n",
120            info->remoteTimePublished.seconds, info->remoteTimePublished.fraction);
121     printf(":c:         seqNr: high = %" PRId32 ", low = %" PRIu32 " \n", info->sn.high, info->sn.low);
122     printf(":c:---------------------------------- \n");
123     #endif
124     ////////////////////////////////////////////////////
125     // update MessageData instance
126     // call method
127     (*env)->CallVoidMethod(env,
128                            callback_cont->msg,
129                            callback_cont->mid_read);
130
131     /* *************************** *
132      *  call JAVA CallBack method  *
133      * *************************** */
134     #ifdef TEST_STAGE
135     printf(":c: volam callback metodu.. halo jsi tam?? \n");
136     #endif
137     // call object's method
138     (*env)->CallVoidMethod(env,
139                            callback_cont->obj, /*obj*/
140                            callback_cont->mid_callback,
141                            callback_cont->rinfo,
142                            callback_cont->msg);
143   } while (0);
144
145   // detach current thread
146   if ((*jvm)->DetachCurrentThread(jvm) != JNI_OK)
147     printf(":c!: DetachCurrentThread failed! \n");
148   //
149   #ifdef TEST_STAGE
150   printf(":c: ------------ thats all from recvCallBack ------------ \n\n");
151   #endif
152 }
153
154 /* ****************************************************************** *
155  *                            native method                           *
156  * ****************************************************************** */
157 JNIEXPORT jlong JNICALL
158 Java_org_ocera_orte_Subscription_jORTESubscriptionCreate
159   (JNIEnv   *env,
160   jobject   obj,
161   jlong     dhandle,  // appDomain handle
162   jint      jsmode,   // subs mode
163   jint      jstype,   // subs type
164   jstring   jtopic,   // subs topic
165   jstring   jtname,   // subs typeName
166   jobject   jinstance, // direct ByteBuffer
167   jint      jbyteOrder, // byte order of ByteBuffer
168   jobject   obj_msg,  // messageData instance
169   jobject   jdeadline,
170   jobject   jminSeparation,
171   jobject   obj_callback,
172   jlong     j_multicastIP)
173 {
174   // jni variables
175   JavaVM                 *jvm;
176   jfieldID                fid;
177   jclass                  cls;
178   jmethodID           mid;
179   jobject                obj_info_buffer;
180   // orte variables
181   ORTESubscription       *s = 0;
182   ORTEDomain             *d;
183   SubscriptionMode        smode;
184   SubscriptionType        stype;
185   NtpTime                 deadline;
186   NtpTime                 minSeparation;
187   // jorte variable
188   JORTECallbackContext_t *callback_cont;
189   JORTECallbackContext_t **callback_cont_ptr;
190
191   // standart variables
192   const char             *topic = 0;
193   const char             *typename = 0;
194   void                   *buffer;
195   int                     flag_ok = 0;
196
197   /* HACK: allocate space for callback context structure and than for a pointer to it */
198
199   // memory alocation
200   // don't forget use free() funct.!!
201   callback_cont = (JORTECallbackContext_t *)malloc(sizeof(JORTECallbackContext_t));
202   callback_cont_ptr = (JORTECallbackContext_t **)malloc(sizeof(JORTECallbackContext_t *));
203   *callback_cont_ptr = callback_cont;
204
205   do {
206
207     // get direct ByteBuffer pointer from Java
208     buffer = (*env)->GetDirectBufferAddress(env, jinstance);
209     // check obj_callback
210     if (obj_callback == 0) {
211       #ifdef TEST_STAGE
212       printf(":!c: obj_callback = NULL \n");
213       #endif
214       break;
215     }
216     // get jvm
217     jint b = (*env)->GetJavaVM(env, &jvm);
218     if (b == JNI_OK) {
219       #ifdef TEST_STAGE
220       printf(":c: getJavaVM succesfull.. \n");
221       #endif
222     }
223     else {
224       #ifdef TEST_STAGE
225       printf(":!c: getJavaVM() failed! \n");
226       #endif
227       break;
228     }
229     callback_cont->jvm = jvm;
230     callback_cont->cur_endian = (CDR_Endianness)jbyteOrder;
231     // create global references
232     callback_cont->obj = (*env)->NewGlobalRef(env, obj_callback);
233     //
234     if (callback_cont->obj == 0) {
235       #ifdef TEST_STAGE
236       printf(":c: global reference not created! \n");
237       #endif
238       break;
239     }
240     // get ReceiveCallback class
241     cls = (*env)->GetObjectClass(env, callback_cont->obj);
242     if (cls == 0) {
243       #ifdef TEST_STAGE
244       printf(":!c: cls = NULL \n");
245       #endif
246       break;
247     }
248     // get callback method ID
249     callback_cont->mid_callback = (*env)->GetMethodID(env,
250                               cls,
251                               "callback",
252                               "(Lorg/ocera/orte/types/RecvInfo;Lorg/ocera/orte/types/MessageData;)V");
253     if (callback_cont->mid_callback == 0) {
254       #ifdef TEST_STAGE
255       printf(":!c: mid_callback = NULL \n");
256       #endif
257       break;
258     }
259     // create global references
260     callback_cont->obj_buf = (*env)->NewGlobalRef(env, jinstance);
261     //
262     if (callback_cont->obj_buf == 0) {
263       #ifdef TEST_STAGE
264       printf(":c: global reference not created! \n");
265       #endif
266       break;
267     }
268     // create global references
269     callback_cont->msg = (*env)->NewGlobalRef(env, obj_msg);
270     //
271     if (callback_cont->msg == 0) {
272       #ifdef TEST_STAGE
273       printf(":c: global reference not created! \n");
274       #endif
275       break;
276     }
277     // get MessageData class
278     cls = (*env)->GetObjectClass(env, callback_cont->msg);
279     if (cls == 0) {
280       #ifdef TEST_STAGE
281       printf(":!c: cls_msg = NULL \n");
282       #endif
283       break;
284     }
285     /////////////////////////////////////////////////////
286     // methodID - read()
287     callback_cont->mid_read = (*env)->GetMethodID(env,
288                               cls,
289                               "read",
290                               "()V");
291     if (callback_cont->mid_read == 0) {
292       #ifdef TEST_STAGE
293       printf(":!c: mid_read = NULL \n");
294       #endif
295       break;
296     }
297     // init RecvInfo pointer
298     // find cls
299     cls = findClass(env, "org.ocera.orte.types.RecvInfo");
300     if (cls == 0) {
301         #ifdef TEST_STAGE
302         printf(":!c: cls = NULL \n");
303         #endif
304         break;
305     }
306     // call object constructor
307     mid = (*env)->GetMethodID(env, cls, "<init>", "()V");
308     if (mid == 0) {
309         #ifdef TEST_STAGE
310         printf(":!c: constructor failed! \n");
311         #endif
312         break;
313     }
314     // create new object
315     callback_cont->rinfo = (*env)->NewObject(env, cls, mid);
316     if (callback_cont->rinfo == 0) {
317         #ifdef TEST_STAGE
318         printf(":!c: rinfo = NULL \n");
319         #endif
320         break;
321     }
322     // create global reference
323     callback_cont->rinfo = (*env)->NewGlobalRef(env, callback_cont->rinfo);
324     if (callback_cont->rinfo == 0) {
325         #ifdef TEST_STAGE
326         printf(":!c: callback_cont->rinfo = NULL \n");
327         #endif
328         break;
329     }
330     // lookup getBuffer() ID
331     mid = (*env)->GetMethodID(env, cls, "getBuffer", "()Ljava/nio/ByteBuffer;");
332     if (mid == 0) {
333         #ifdef TEST_STAGE
334         printf(":!c: getBuffer() failed! \n");
335         #endif
336         break;
337     }
338     // get ByteBuffer reference
339     obj_info_buffer = (*env)->CallObjectMethod(env, callback_cont->rinfo, mid);
340     callback_cont->info_buf = (*env)->GetDirectBufferAddress(env, obj_info_buffer);
341     // create global references for ByteOrders
342     cls = (*env)->FindClass(env, "java/nio/ByteOrder");
343     fid = (*env)->GetStaticFieldID(env,
344                                    cls,
345                                    "BIG_ENDIAN",
346                                    "Ljava/nio/ByteOrder;");
347     callback_cont->obj_BO_BE = (*env)->GetStaticObjectField(env, cls, fid);
348     callback_cont->obj_BO_BE = (*env)->NewGlobalRef(env, callback_cont->obj_BO_BE);
349     fid = (*env)->GetStaticFieldID(env,
350                                    cls,
351                                    "LITTLE_ENDIAN",
352                                    "Ljava/nio/ByteOrder;");
353     callback_cont->obj_BO_LE = (*env)->GetStaticObjectField(env, cls, fid);
354     callback_cont->obj_BO_LE = (*env)->NewGlobalRef(env, callback_cont->obj_BO_LE);
355     // get methodID - order(ByteOrder)
356     cls = (*env)->GetObjectClass(env, callback_cont->obj_buf);
357     callback_cont->mid_order = (*env)->GetMethodID(env,
358                                                    cls,
359                                                    "order",
360                                                    "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;");
361     //
362     cls = (*env)->GetObjectClass(env, obj);
363     if (cls == 0) {
364       #ifdef TEST_STAGE
365       printf(":!c: cls = NULL \n");
366       #endif
367       break;
368     }
369     // fieldID - callbackContextHandle
370     fid = (*env)->GetFieldID(env,
371                              cls,
372                              "callbackContextHandle",
373                              "J");
374     if (fid == 0) {
375       #ifdef TEST_STAGE
376       printf(":!c: fid = NULL \n");
377       #endif
378       break;
379     }
380     (*env)->SetLongField(env,
381                          obj,
382                          fid,
383                          (jlong)callback_cont_ptr);
384     #ifdef TEST_STAGE
385     printf(":c: ORTESubscriptionCreate() calling..\n");
386     #endif
387     //
388     d = (ORTEDomain *)dhandle;
389     if (d == 0) {
390       #ifdef TEST_STAGE
391       printf(":!c: d = NULL [bad domain handle] \n");
392       #endif
393       break;
394     }
395     //
396     smode = (SubscriptionMode)jsmode;
397     stype = (SubscriptionType)jstype;
398     topic = (*env)->GetStringUTFChars(env, jtopic, 0);
399     typename = (*env)->GetStringUTFChars(env, jtname, 0);
400     deadline = getNtpTime(env, jdeadline); //
401     minSeparation = getNtpTime(env, jminSeparation); //
402     // call ORTE function
403     s = ORTESubscriptionCreate(d,
404                                smode,
405                                stype,
406                                topic,
407                                typename,
408                                buffer,
409                                &deadline,
410                                &minSeparation,
411                                recvCallBack,
412                                (void *)callback_cont_ptr,
413                                (uint32_t)j_multicastIP);
414     if (s == 0) {
415       #ifdef TEST_STAGE
416       printf(":!c: s = NULL [subscription not created] \n");
417       #endif
418       break;
419     }
420
421     // set flag
422     flag_ok = 1;
423   } while (0);
424
425   // free memory
426   (*env)->ReleaseStringUTFChars(env, jtopic, topic);
427   (*env)->ReleaseStringUTFChars(env, jtname, typename);
428   // returns handle of new created Subscription
429   if (flag_ok == 0)
430     return 0;
431   return ((jlong)s);
432
433 }