David,
You have me lost a bit, See inline for comments/questions

Thanks for your insight

Alain

On Sun, Aug 12, 2018 at 5:26 PM David Leangen <o...@leangen.net> wrote:

>
> Hi Alain,
>
> Since you are annotating classes that are generated, does the generator
> has some configurability?
>
Yes, it is our own.

Is it possible for you to instead generate configurations? The config could
> be a properties file, a JSON, or even a class if necessary.
>
IMHO I am generating the configuration as part of the "main" component that
I showed. What would be the advantage to put those in a file (we do have
those for standard config).

>
> If this is possible, you could for instance use the extender pattern to
> instantiate the services for you, rather than trying to manually build a
> single component for each generated file. Generate the configurations,
> export them to a known folder in a bundle, and when the bundle is deployed,
> read the configs and instantiate the services.
>
> Right now, it sounds like you are making yourself an extension to the
> generator. If you can reduce the manual work by capturing only what varies
> and automating the repetition, perhaps that would be a more elegant
> solution.
>
At which level. The generator generates the "main" mapData class, the
table, record and readers/writers. Some of those might have methods marked
as @notGenerated when manual changes are required. The classes leveraging
this (like the exporter that I showed), are not generated.

>
> One service per generated “class” sounds right to me, but IMO there seems
> to be a bit of a smell to the manual additions to each generated file.
> Think of it from the perspective of your builds. Every time you build a new
> system, you’ll have to do manual work to construct your components. Would
> be better to have an end-to-end build that does not require manual
> intervention. Don’t you think?
>
I don't, there is a fair amount of manual boilerplate involved in the
non-generated classes, but no further manual intervention.

>
> In case you did not now (it was not obvious to me before I first
> discovered it) you can also configure the @References with a “xxx.target”
> configuration property. DS should give you all you need to configure your
> services.
>
Is that different than what I showed with:
@Reference(target=BaModelAssetMapData.TARGET_TABLE_NAME)
    private ExportTable<BaModelAssetMapTable> exportTable;

>
> Now I’m very curious, so please let me know how you end up solving this.
> :-)
>
>
> Cheers,
> =David
>
>
>
>
> On Aug 12, 2018, at 22:00, Alain Picard <pic...@castortech.com> wrote:
>
> Just realized that I could have applied the same pattern to the
> BaseMapData and not use the implementation class there either.
>
> Alain
>
> On Sun, Aug 12, 2018 at 8:58 AM Alain Picard <pic...@castortech.com>
> wrote:
>
>> To David,
>>
>> Your comment got me thinking some more about this. And given that I have
>> about 25 different variations and each has 3 variants, that would mean
>> introducing somewhere like 75 "marker" interfaces.
>>
>> Here's what I did:
>>
>> A number of key classes are generated and sometimes partly modified by
>> hand. So in the "main" such class I have:
>> /**
>>  * This class is generated by Iris-Mapping.
>>  *
>>  * @generated
>>  */
>> @Component(
>>     property = {
>>         IBaseMapData.CONFIG_MAPPING_ID + "=" +
>> "com.castortech.iris.mapping.project.baModel.asset",
>>         IBaseMapData.CONFIG_MAPPING_NAME + "=" +
>> BaModelAssetMapData.TABLE_NAME,
>>         IBaseMapData.CONFIG_MAPPING_XL_READER + "=" +
>> "com.castortech.iris.mapping.maps.project.baModel.asset.BaModelAssetXlReader",
>>         IBaseMapData.CONFIG_MAPPING_XL_WRITER + "=" +
>> "com.castortech.iris.mapping.maps.project.baModel.asset.BaModelAssetXlWriter"
>>     },
>>     service=BaModelAssetMapData.class
>> )
>> public final class BaModelAssetMapData extends
>> BaseMapData<BaModelAssetMapTable, BaModelAssetMapRecord> {
>>   public static final String TABLE_NAME = "Asset"; //$NON-NLS-1$
>>   public static final String PROP_TABLE_NAME =
>> MappingConstants.CONFIG_TABLE_NAME + "=" + TABLE_NAME; //$NON-NLS-1$
>>   public static final String TARGET_TABLE_NAME = "(" +
>> MappingConstants.CONFIG_TABLE_NAME + "=" + TABLE_NAME + ")"; //$NON-NLS-1$
>> //$NON-NLS-2$ //$NON-NLS-3$
>> ...
>>
>> and then I will have:
>> @Component(property=BaModelAssetMapData.PROP_TABLE_NAME)
>> public final class AssetXlExporter implements BaXlExportContent {
>>     @Reference
>>     private BaXlExportUtils<BaModelAssetXlWriter, BaModelAssetMapTable,
>> BaModelAssetMapRecord> exporter;
>>
>>     @Reference(target=BaModelAssetMapData.TARGET_TABLE_NAME)
>>     private ExportTable<BaModelAssetMapTable> exportTable;
>>
>> and in another location where the exporter is used as a reference:
>>     ....
>>     @Reference(target=BaModelAssetMapData.TARGET_TABLE_NAME)
>>     private AssetXlExporter assetXlExporter;
>>     ...
>>
>> To me this avoids the previous issue of exposing the implementation class
>> and using generated constants, allows to have readable code where
>> annotations don't become unreadable.
>>
>> Does it make sense?
>>
>> Alain
>>
>> On Sun, Aug 12, 2018 at 8:22 AM David Leangen <o...@leangen.net> wrote:
>>
>>>
>>> Hi Alain,
>>>
>>> Maybe there is a way of having 25 different interfaces in your API
>>> instead?
>>>
>>> Or, if they are private, maybe you don’t even need to use services?
>>>
>>> Are you able to share your code? Would be helpful to have a little more
>>> information.
>>>
>>>
>>> Cheers,
>>> =David
>>>
>>>
>>>
>>> On Aug 12, 2018, at 6:58, Alain Picard <pic...@castortech.com> wrote:
>>>
>>> On Sat, Aug 11, 2018 at 4:10 PM David Leangen <o...@leangen.net> wrote:
>>>
>>>>
>>>> Hi Alain,
>>>>
>>>> What is it you are trying to accomplish? Is there a reason you are
>>>> exposing the implementation class?
>>>>
>>>> Maybe you know this already, but the “usual” practice is to expose an
>>>> interface in your API (and export the containing package), and to keep the
>>>> implementation private.
>>>>
>>> Yes, absolutely, and that's why I'm asking. I have about 25 different
>>> implementation of the interfaces that are most often referenced directly
>>> from a matching component (i.e. for the same table) and a few cases where
>>> they are invoked generically. Here all of those are in a single bundle so
>>> this is more like a "private" API and the use of a class is not a real
>>> problem. But I didn't feel like using @Reference(target=(tableName=x) for
>>> each case. Hence my question.
>>>
>>> Alain
>>>
>>>>
>>>> Also:
>>>>
>>>> >                Collection<ServiceReference<T>> servRefs =
>>>> bcontext.getServiceReferences(target, props.get("filter"));  //filter to be
>>>> like: "(target
>>>> >         servRef = servRefs.isEmpty() ? null :
>>>> servRefs.iterator().next();
>>>>
>>>> Did some text get cut out of your post?
>>>>
>>>> If you can explain a little more what you are trying to do I think that
>>>> would be helpful.
>>>>
>>>>
>>>> Cheers,
>>>> =David
>>>>
>>>>
>>>> > On Aug 12, 2018, at 1:27, Alain Picard via osgi-dev <
>>>> osgi-dev@mail.osgi.org> wrote:
>>>> >
>>>> > Looking for confirmation or insight in how best to specify components
>>>> and references, so that the same component can be invoked directly or more
>>>> generically through its interface.
>>>> >
>>>> > Let's say that I have some components, 1 per table to do some export
>>>> function:
>>>> >
>>>> > @Component(
>>>> >         property= MappingConstants.CONFIG_TABLE_NAME + "=BigTable",
>>>> >         service= { BigTableXlExporter.class, XlExportContent.class }
>>>> > )
>>>> > public final class BigTableXlExporter implements XlExportContent {...}
>>>> >
>>>> > and in another component I can get a specific reference with:
>>>> > @Component(service=SomeComp.class)
>>>> > public final class SomeComp
>>>> >     @Reference
>>>> >     private BigTableXlExporter exporter;
>>>> >     ...
>>>> > }
>>>> >
>>>> > and in another case i could get a more generic invocation (as part of
>>>> config or through a factory:
>>>> > @Component(service=GenericComp.class)
>>>> > public final class GenericComp
>>>> >    @Activate
>>>> >    private void init(Map<String,Object> props, BundleContext
>>>> bcontext) {
>>>> >      ServiceReference servRef;
>>>> >       try {
>>>> >          Collection<ServiceReference<T>> servRefs =
>>>> bcontext.getServiceReferences(target, props.get("filter"));  //filter to be
>>>> like: "(target
>>>> >         servRef = servRefs.isEmpty() ? null :
>>>> servRefs.iterator().next();
>>>> >         }
>>>> >         catch (InvalidSyntaxException e) {
>>>> >             throw new IllegalArgumentException("Invalid Filter Syntax
>>>> Exception", e);
>>>> >         }
>>>> >
>>>> >         //do something with ref....
>>>> >    }
>>>> > }
>>>> >
>>>> > Does this make sense or are there better ways to do this.
>>>> >
>>>> > Alain
>>>> >
>>>> > _______________________________________________
>>>> > OSGi Developer Mail List
>>>> > osgi-dev@mail.osgi.org
>>>> > https://mail.osgi.org/mailman/listinfo/osgi-dev
>>>>
>>>>
>>>
>
_______________________________________________
OSGi Developer Mail List
osgi-dev@mail.osgi.org
https://mail.osgi.org/mailman/listinfo/osgi-dev

Reply via email to