David, I have experimented with factory configuration and used it in one case. But what I have not done is used the Extender Pattern with the BundleTracker to initialize services or here configurations. That is a very good point that I wasn't aware of. I can see how this could probably replace those "main' MapData components. Still not sure how well it plays with generics which are heavily used here.
In this case, I probably won't go any further, since this is a refactoring to get us moved over from Eclipse extension points and not a redesign or new services and we need to get done this year and avoid breaking to many things in the process :) I can already see uses for the Extender pattern in another part of the application, great insight. Cheers, Alain On Sun, Aug 12, 2018 at 7:16 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. > > Ok, great! That will make things easier. > > > >> 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). > > I am making a few assumptions here about how your system works, but I > recommend that you read up on the “Extender Pattern”. Essentially, it > allows you to automate the creation of a service. The services need to have > a known structure (which it seems yours do), and have to be configurable > (which again, it seems yours are). > > What you would do using this pattern is output the necessary configuration > to a file, probably one file per configuration. You could put them all in a > “known” folder, and include the folder in a bundle. You would use a > BundleTracker to test for the presence of these configuration files. If a > folder is detected that contains these files, you would load the > configuration, one config for each file. > > Your component would require a configuration and have a known > configurationPid. I think the scope should be PROTOTYPE, but you’ll have to > try it out to be sure, I can’t remember off hand. > > Using the ConfigurationAdmin, you would create a factory configuration, > which would create a new component instance. > > I think this approach would be much nicer than handcrafting a new > component for each generated class, even if you are only doing it once. > > > >> 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. > > To make this approach work, the configured components should contain only > the parts that change. I guess you’d have to carefully pull apart what > changes from what doesn’t. > > > >> 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. > > Well, if it’s one of these things where you invest 2 hours of work, and it > almost never changes, then maybe you’re doing the right thing. If, however, > you need to consistently intervene manually, that can be boring and error > prone. Also, it puts the knowledge into a person, who can forgot or leave > the company. If the knowledge is instead embedded in the build system, then > you can concentrate your energies on other things. But like anything, it’s > always a trade off. YMMV. > > > >> 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; > > That is the effect, but it is done via configuration, not annotation. > > Example: > > ConfigurationAdmin cm = ...; > Configuration config = cm.createFactoryConfiguration( "some.pid", > "?" ); > > Dictionary<String, Object> properties = new Hashtable<>(); > properties.put( "XXX.target", "(some.prop=foo)" ); > > config.update( properties ); > > > The call to config.update(properties) will create a new component with PID > “some.pid” using the provided configuration. > > Cheers, > =David > > >
_______________________________________________ OSGi Developer Mail List osgi-dev@mail.osgi.org https://mail.osgi.org/mailman/listinfo/osgi-dev