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