[ 
https://issues.apache.org/jira/browse/IGNITE-14496?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Sergey Chugunov updated IGNITE-14496:
-------------------------------------
    Description: 
h3. Problem

In this issue we need to move all API from *ignite-configuration* module into 
*ignite-api*. This comes at a price, we can't just move our classes. The 
problem is that code generator generates (in principal) two thing:
 * schema-based general interfaces:
 ** {{*View}}
 ** {{*Change}}
 ** {{*Configuration}}
 * schema-based implementations:
 ** {{*Node}}
 ** {{*ConfigurationImpl}}

First set of interfaces depends on +other interfaces only+. This is good and 
pretty much all we need in resulting *ignite-api* sources.

Second set of classes requires us to have classes like {{InnerNode}} or 
{{ConfigurationChanger}} in compile-time dependencies, which is clearly wrong 
for API. These 2 classes must be in another Java module and that's a problem.

There are two approaches to solve the problem, I'll try my best to describe 
both.
h3. Common problem for both solutions

*ignite-configuration-annotation-processor* clearly depends on *ignite-api* in 
our case AND at the same time *ignite-api* should use annotation processing. We 
have cycling dependency. Right way of resolving it is to create module 
*ignite-configuration-api*. This shows us that having +all+ API in one module 
is probably not the best idea.
h3. Solution 1 - split annotation processor into 2

There's no doubt that we need processor that will generate first set of 
interfaces. We already have it. We could create a second annotation processor 
that will generate implementations into other modules, let's call it 
*impl-processor*. But Java annotation processing API can't do that directly. If 
we compile module *B* that depends on module *A*, only classes from *B* will be 
passed into environment of *impl-processor*. We have two options of how to 
resolve it:
 * use libraries like [classgraph|https://github.com/classgraph/classgraph], 
having *ignite-api* as hardcoded compiler dependency in annotation processor. 
Works in theory BUT there are issues:
 ** there's no clear way of distinguishing schemas that you should process in 
current module from those that you shouldn't;
 ** *ignite-api* dependency is hardcoded as an optional source of schemas, 
which is a questionable thing.
 * include package with desired schemas using maven helper plugin. This 
approach also has issues:
 ** now we understand how to configure it, but such configuration will require 
more manual steps and either separate package for modules schemas or 
include/exclude list in helper plugin configuration;
 ** we will have several identical **.class* files in target directories of 
different modules.

h3. Solution 2 - leave only one annotation processor and generate everything 
else at runtime

This approach requires 0 additional configuration. {{Node}} and 
{{ConfigurationImpl}} can be generated from schemas when you register new root 
key. We already have *bytecode* module so there's no need for additional 
libraries in dependencies. I assume that writing tests will be much easier with 
runtime code generation. Also classes like {{InnerNode}} will probably become 
package-private. The problems are:
 * potential problems during debugging. I don't see it as a problem. Given that 
we'll cover everything with tests, generator code will be pretty stable;
 * generating code requires time. Doesn't look like it really needs a 
significant amount of time though;
 * we can start several nodes in a single JVM so there might be collisions of 
other issues. The problem is purely technical.

 

IMHO, second solution is better. The fact that API usage becomes better 
overweights the fact that we would need to generate different parts of 
configuration code using different tools.

  was:
h3. Problem

In this issue we need to move all API from *ignite-configuration* module into 
*ignite-api*. This comes with a price, we can't just move our classes. The 
problem is that code generator generates (in principal) two thing:
 * schema-based general interfaces:
 ** {{*View}}
 ** {{*Change}}
 ** {{*Configuration}}
 * schema-based implementations:
 ** {{*Node}}
 ** {{*ConfigurationImpl}}

First set of interfaces depends on +other interfaces only+. This is good and 
pretty much all we need in resulting *ignite-api* sources.

Second set of classes requires us to have classes like {{InnerNode}} or 
{{ConfigurationChanger}} in compile-time dependencies, which is clearly wrong 
for API. These 2 classes must be in another Java module and that's a problem.

There are two approaches to solve the problem, I'll try my best to describe 
both.
h3. Common problem for both solutions

*ignite-configuration-annotation-processor* clearly depends on *ignite-api* in 
our case AND at the same time *ignite-api* should use annotation processing. We 
have cycling dependency. Right way of resolving it is to create module 
*ignite-configuration-api*. This shows us that having +all+ API in one module 
is probably not the best idea.
h3. Solution 1 - split annotation processor into 2

There's no doubt that we need processor that will generate first set of 
interfaces. We already have it. We could create a second annotation processor 
that will generate implementations into other modules, let's call it 
*impl-processor*. But Java annotation processing API can't do that directly. If 
we compile module *B* that depends on module *A*, only classes from *B* will be 
passed into environment of *impl-processor*. We have to options of how to 
resolve it:
 * use libraries like [classgraph|https://github.com/classgraph/classgraph], 
having *ignite-api* as hardcoded compiler dependency in annotation processor. 
Works in theory BUT there are issues:
 ** there's no clear way of distinguishing schemas that you should process in 
current module from those that you shouldn't;
 ** *ignite-api* dependency is hardcoded as an optional source of schemas, 
which is a questionable thing.
 * include package with desired schemas using maven helper plugin. This 
approach also has issues:
 ** now we understand how to configure it, but such configuration will require 
more manual steps and either separate package for modules schemas or 
include/exclude list in helper plugin configuration;
 ** we will have several identical **.class* files in target directories of 
different modules.

h3. Solution 2 - leave only one annotation processor and generate everything 
else at runtime

This approach requires 0 additional configuration. {{Node}} and 
{{ConfigurationImpl}} can be generated from schemas when you register new root 
key. We already have *bytecode* module so there's no need for additional 
libraries in dependencies. I assume that writing tests will be much easier with 
runtime code generation. Also classes like {{InnerNode}} will probably become 
package-private. The problems are:
 * potential problems during debugging. I don't see it as a problem. Given that 
we'll cover everything with tests, generator code will be pretty stable;
 * generating code requires time. Doesn't look like it really needs a 
significant amount of time though;
 * we can start several nodes in a single JVM so there might be collisions of 
other issues. The problem is purely technical.

 

IMHO, second solution is better. The fact that API usage becomes better 
overweights the fact that we would need to generate different parts of 
configuration code using different tools.


> Move configuration schemas and configuration annotations to ignite-api
> ----------------------------------------------------------------------
>
>                 Key: IGNITE-14496
>                 URL: https://issues.apache.org/jira/browse/IGNITE-14496
>             Project: Ignite
>          Issue Type: Sub-task
>            Reporter: Semyon Danilov
>            Assignee: Ivan Bessonov
>            Priority: Major
>
> h3. Problem
> In this issue we need to move all API from *ignite-configuration* module into 
> *ignite-api*. This comes at a price, we can't just move our classes. The 
> problem is that code generator generates (in principal) two thing:
>  * schema-based general interfaces:
>  ** {{*View}}
>  ** {{*Change}}
>  ** {{*Configuration}}
>  * schema-based implementations:
>  ** {{*Node}}
>  ** {{*ConfigurationImpl}}
> First set of interfaces depends on +other interfaces only+. This is good and 
> pretty much all we need in resulting *ignite-api* sources.
> Second set of classes requires us to have classes like {{InnerNode}} or 
> {{ConfigurationChanger}} in compile-time dependencies, which is clearly wrong 
> for API. These 2 classes must be in another Java module and that's a problem.
> There are two approaches to solve the problem, I'll try my best to describe 
> both.
> h3. Common problem for both solutions
> *ignite-configuration-annotation-processor* clearly depends on *ignite-api* 
> in our case AND at the same time *ignite-api* should use annotation 
> processing. We have cycling dependency. Right way of resolving it is to 
> create module *ignite-configuration-api*. This shows us that having +all+ API 
> in one module is probably not the best idea.
> h3. Solution 1 - split annotation processor into 2
> There's no doubt that we need processor that will generate first set of 
> interfaces. We already have it. We could create a second annotation processor 
> that will generate implementations into other modules, let's call it 
> *impl-processor*. But Java annotation processing API can't do that directly. 
> If we compile module *B* that depends on module *A*, only classes from *B* 
> will be passed into environment of *impl-processor*. We have two options of 
> how to resolve it:
>  * use libraries like [classgraph|https://github.com/classgraph/classgraph], 
> having *ignite-api* as hardcoded compiler dependency in annotation processor. 
> Works in theory BUT there are issues:
>  ** there's no clear way of distinguishing schemas that you should process in 
> current module from those that you shouldn't;
>  ** *ignite-api* dependency is hardcoded as an optional source of schemas, 
> which is a questionable thing.
>  * include package with desired schemas using maven helper plugin. This 
> approach also has issues:
>  ** now we understand how to configure it, but such configuration will 
> require more manual steps and either separate package for modules schemas or 
> include/exclude list in helper plugin configuration;
>  ** we will have several identical **.class* files in target directories of 
> different modules.
> h3. Solution 2 - leave only one annotation processor and generate everything 
> else at runtime
> This approach requires 0 additional configuration. {{Node}} and 
> {{ConfigurationImpl}} can be generated from schemas when you register new 
> root key. We already have *bytecode* module so there's no need for additional 
> libraries in dependencies. I assume that writing tests will be much easier 
> with runtime code generation. Also classes like {{InnerNode}} will probably 
> become package-private. The problems are:
>  * potential problems during debugging. I don't see it as a problem. Given 
> that we'll cover everything with tests, generator code will be pretty stable;
>  * generating code requires time. Doesn't look like it really needs a 
> significant amount of time though;
>  * we can start several nodes in a single JVM so there might be collisions of 
> other issues. The problem is purely technical.
>  
> IMHO, second solution is better. The fact that API usage becomes better 
> overweights the fact that we would need to generate different parts of 
> configuration code using different tools.



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to