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]

Reply via email to