On Fri, May 30, 2008 at 6:02 PM, Sérgio Gomes <[EMAIL PROTECTED]> wrote: >> I think we don't need to care whether it is abstract or not. The >> polymorphism can occur for any complex type. (that any where complex >> content extension goes). So we should not assume it happens only to >> abstract types. > > I completely agree, I won't assume that at all. I'll also have to make > sure this works with multiple levels of inheritance. I was just trying > to make a strong case of why this is needed ;-) > > > Regarding your suggestions, Carl, Dimuthu, thanks for the help. I've > been thinking about this quite a bit, and I think I have an approach > too. Like it was suggested, I was thinking of making two global "flat" > functions (either in the stubs or in a separate file, that's just a > matter of preference) that would be used for all serialization and > deserialization. > > Now, here's where it differs: each type would retain its own > serialization and deserialization functions exactly as they are, but > change the name to something like *_serialize_impl and > *_deserialize_impl. Also, for compatibility purposes, and to reduce > the amount of changes needed, they would also have *_serialize and > *_deserialize functions, but they would just be wrappers that would > call the "global" functions. > > Now, these "global" functions would know all the types, and would be > able to call the appropriate *_impl functions for them. For > serialization to work, we need to store the type name in every > structure, per Carl's suggestion. For deserialization to work, we > would need to check the type name (xsi:Type) in the node. > > So, in terms of code, this would be, as suggested: > > struct adbType > { > axis2_char_t property_Type[64]; > } > > and of course, for other types, e.g. A1: > > struct adb_A1 > { > axis2_char_t property_Type[64]; > ... > } > > So, the global serialization function could be: > > axiom_node_t* AXIS2_CALL > adb_serialize( > adbType_t* _element, > const axutil_env_t *env, axiom_node_t *parent, > axiom_element_t *parent_element, int parent_tag_closed, axutil_hash_t > *namespaces, int *next_ns_index) > { > if (strcmp(struct->property_Type, "adb_A") == 0) { > return adb_A_serialize_impl((adb_A_t *)_element, > env, parent, parent_element, parent_tag_closed, > namespaces, next_ns_index); > } > > if (strcmp(struct->property_Type, "adb_A1") == 0) { > return adb_A1_serialize_impl((adb_A1_t *)_element, > env, parent, parent_element, parent_tag_closed, > namespaces, next_ns_index); > } > ... > } > > Note that A is also listed as a type, even though it's abstract. > Admittedly, not an ideal solution, but necessary to make sure that you > could instance a pure A object if it weren't abstract. > > The global deserialization function: > > axis2_status_t AXIS2_CALL > adb_deserialize( > adbType_t* _element, > const axutil_env_t *env, > axiom_node_t **dp_parent, > axis2_bool_t *dp_is_early_node_valid, > axis2_bool_t dont_care_minoccurs) > { > if (/* is xsi:Type == "A" ? */) { > return adb_A_deserialize_impl((adb_A_t *)_element, > env, dp_parent, dp_is_early_node_valid, > dont_care_minoccurs); > } > > if (/* is xsi:Type == "A1" ? */) { > return adb_A1_deserialize_impl((adb_A1_t *)_element, > env, dp_parent, dp_is_early_node_valid, > dont_care_minoccurs); > } > ... > } > > The wrapper functions would simply look like this: > > axiom_node_t* AXIS2_CALL > adb_A_serialize( > adb_A_t* _A, > const axutil_env_t *env, axiom_node_t *parent, > axiom_element_t *parent_element, int parent_tag_closed, axutil_hash_t > *namespaces, int *next_ns_index) > { > return adb_serialize((adbType_t *)_A, > env, parent, parent_element, parent_tag_closed, > namespaces, next_ns_index); > } > > axis2_status_t AXIS2_CALL > adb_deserialize( > adb_A_t* _A, > const axutil_env_t *env, > axiom_node_t **dp_parent, > axis2_bool_t *dp_is_early_node_valid, > axis2_bool_t dont_care_minoccurs) > { > return adb_deserialize((adbType_t *)_A, > env, dp_parent, dp_is_early_node_valid, dont_care_minoccurs); > } > > This approach is very similar to what Dimuthu suggested, but it would > have the benefit of "plugging into" the existing infrastructure, and > would require no changes to the complex code inside the > serialization/deserialization functions. Probably not as elegant, > though. Overall, I think Dimuthu's suggestion is better, but scarier > ;-) I'm just putting mine forward to get your opinions.
Yea, your suggestion is better. It avoids the use of tricky function pointers. > > Neither of these would assure that you could only instance objects of > the specific type hierarchy you're expecting, however. Where would > this get done, and does it matter if it isn't? I don't think it is a matter. +1 for use of adb_type_t (which i think union of all the adb types for complex types). Anyway this reminded me we have to do some API change (getters/setters) too. For an example take the following function, axis2_status_t AXIS2_CALL adb_matrixAdd_set_matrixAdd( adb_matrixAdd_t* _matrixAdd, const axutil_env_t *env, adb_matrixAddType_t* arg_matrixAdd); we can give another function that can set any adb_type axis2_status_t AXIS2_CALL adb_matrixAdd_setany_matrixAdd( adb_matrixAdd_t* _matrixAdd, const axutil_env_t *env, adb_type_t* arg_matrixAdd); simmilarly we can give getany function keeping the get_matrixAdd function as it is. If in any case it wants to return some non adb_matrixAddType_t* we can return NULL, may be with a log message. BTW setany and getany names are just suggestions. but it is better we have names without any underscores(_s), since although they are rarely used, we have to put it in every complex type adb objects. Thanks Dimuthu > > > Cheers, > Sérgio > > --- > On Fri, May 30, 2008 at 5:17 AM, Dimuthu Gamage <[EMAIL PROTECTED]> wrote: >> On Thu, May 29, 2008 at 8:02 PM, Lefrancois, Carl >> <[EMAIL PROTECTED]> wrote: >>>>>I'm developing a patch against the ADB C code generator to allow it to >>> handle polymorphism correctly... >>> >>>>>Say you have a complexType A, which is abstract. Then there are >>> complexTypes A1 and A2, which extend A and are not abstract. >>> >>>>>The second case, however, is quite problematic. The only way to know >>> which type is being returned is, of course, during runtime, by looking >>> at the xsi:type property. This is relatively easy to do with Axiom, but >>> the problem is how to invoke the right create method, but the problem is >>> that for this to work correctly, it's necessary to invoke the "create" >>> and "deserialize" methods for the right subtype (the ones for A won't >>> do, as they aren't aware of the specific properties of A1 and A2). I >>> thought of creating one global hash table with the create/deserialize >>> methods for all types when generating the stub for the service, but it >>> doesn't strike me as a particularly elegant solution. Does anyone have >>> any other suggestions? >>> >>>>>It's at times like these I wish C had classes and I could just let the >>> language handle the issue itself ;-) >>> >>>>>Cheers, >>>>>Sérgio >>> >>> >>> >>> Hi Sérgio, >>> >>> As Dimuthu suggested in an earlier post, you can change the structure of >>> each subtype to start with a char array, then casting the object to a >>> char * will give you the contents of this char array. >>> >>> E.g. The source file for type A1 will contain >>> >>> struct adb_A1 >>> { >>> ... >>> } >>> >>> If we change this to: >>> struct adb_A1 >>> { >>> axis2_char_t property_Type[64]; >>> ... >>> } >>> >>> And in the adb_A1_create, add >>> strcpy(_A1->property_Type, "adb_A1"); >>> >>> >>> In the same way, adb_A2.c contains >>> >>> struct adb_A2 >>> { >>> axis2_char_t property_Type[64]; >>> ... >>> } >>> >>> in adb_A2_create >>> strcpy(_A2->property_Type, "adb_A2"); >>> >>> >>> So now consider an ADB object C that contains an element of base type A. >>> in adb_C.c you will have >>> >>> >>> adb_C_set_A(C_t *C, env, A_t *A) >>> { >>> ... >>> } >>> >>> Change this to >>> adb_C_set_A(C_t *C, env, void *A) >>> >>> The void * will be correctly stored in the property or array list. >>> >>> During serialization, you can use the following: >>> >>> if (strcmp((char *)element, "adb_A1") == 0) { >>> >>> if(!adb_A1_is_particle()) >>> { >>> axutil_stream_write(stream, env, start_input_str, >>> start_input_str_len); >>> } >>> >>> adb_A1_serialize((adb_A1_t*)element, >>> env, >>> current_node, parent_element, >>> >>> adb_A1_is_particle() || AXIS2_FALSE, namespaces, next_ns_index); >>> >>> if(!adb_A1_is_particle()) >>> { >>> axutil_stream_write(stream, env, end_input_str, >>> end_input_str_len); >>> } >>> } >>> >>> And repeat for A2, etc. >>> >>> Now the final usage pattern looks like this: >>> >>> Adb_C = adb_C_create(env); >>> Adb_A1 = adb_A1_create(env); >>> Adb_C_set_A(Adb_C, env, Adb_A1); >>> >>> And the C will correctly serialize the element as an A1. >>> >>> >>> I hope this helps your work. I am really interested in seeing this >>> implemented in WSDL2C. >>> >>> Carl >> >> Hi Carl, >> >> Here 'A' have to aware of the fact A1 and A2 are inheriting from it. >> In current codegen implementation it is bit hard to implement. (need >> to change the codegen engine implementation). The best thing is let >> the mapping to do from external file, (some corresponding file to >> 'ExtensionMapper.java'). So I will change your suggested code to >> something like this.. >> >> void adb_A_serialize(void *element, ....) >> { >> >> /* serialize 'A' s element first */ >> if(!adb_A_is_particle()) >> { >> axutil_stream_write(stream, env, start_input_str, >> start_input_str_len); >> } >> >> serialize_content_func = >> axis2_extension_mapper_get_serialize_content_func(element); >> >> serialize_content_func(element, >> env, >> current_node, parent_element, >> adb_A1_is_particle() || AXIS2_FALSE, namespaces, next_ns_index); >> >> >> if(!adb_A_is_particle()) >> { >> axutil_stream_write(stream, env, end_input_str, >> end_input_str_len); >> } >> >> } >> >> And some external file like axis2_extension_mapper.c we have the >> mapping function. It returns the correct serialize function for the >> element >> >> /* for example for serialize_content function */ >> >> typedef void (*ret_func_ptr)(void *element, axutil_env_t *env, ..); >> >> ret_func_ptr axis2_extension_mapper_get_serialize_content_func(void *element) >> { >> if(strcmp((axis2_char_t*)(element), "A1")) >> { >> return adb_A1_serialize_content; >> } >> if(strcmp((axis2_char_t*)(element), "A2")) >> { >> return adb_A2_serialize_content; >> } >> } >> >> >> Thanks >> Dimuthu >> >>> _____ >>> >>> "Ce message est confidentiel, à l'usage exclusif du destinataire >>> ci-dessus et son contenu ne représente en aucun cas un engagement de la >>> part de AXA, sauf en cas de stipulation expresse et par écrit de la part >>> de AXA. Toute publication, utilisation ou diffusion, même partielle, >>> doit être autorisée préalablement. Si vous n'êtes pas destinataire de ce >>> message, merci d'en avertir immédiatement l'expéditeur." >>> >>> "This e-mail message is confidential, for the exclusive use of the >>> addressee and its contents shall not constitute a commitment by AXA, >>> except as otherwise specifically provided in writing by AXA. Any >>> unauthorized disclosure, use or dissemination, either whole or partial, >>> is prohibited. If you are not the intended recipient of the message, >>> please notify the sender immediately." >>> >>> --------------------------------------------------------------------- >>> To unsubscribe, e-mail: [EMAIL PROTECTED] >>> For additional commands, e-mail: [EMAIL PROTECTED] >>> >>> >> >> --------------------------------------------------------------------- >> To unsubscribe, e-mail: [EMAIL PROTECTED] >> For additional commands, e-mail: [EMAIL PROTECTED] >> >> > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [EMAIL PROTECTED] > For additional commands, e-mail: [EMAIL PROTECTED] > > --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]