launchpad-dev team mailing list archive
-
launchpad-dev team
-
Mailing list archive
-
Message #03676
Re: Adapters & API
On Mon, 29 Mar 2010 14:59:12 -0400, Leonard Richardson <leonard.richardson@xxxxxxxxxxxxx> wrote:
> Assuming I understand what you're trying to do, the simplest way to
> represent this would be to define an annotation like
> @import_from_adapter() and put @import_from_adapter(IBranchTarget) in
> IProduct and ISourcePackage, while leaving it out of IPerson and
> IProductSeries.
>
> In IBranchTarget you would have an annotation like
> @only_used_in_adaptations that would stop it from being exported as a
> separate entry type. You would publish IBranchTarget.name as
> "branch_target_name" (or whatever you wanted) to avoid colliding with a
> 'name' declared in IProduct or ISourcePackage. The same would hold true
> for IBranchTargetName's named operations. You can choose whatever name
> you want, but if that name conflicts with a name found in the original
> interface, the original interface takes precedence.
>
> The end result would be 'product' and 'source_package' looking like they
> had everything that's @exported in IBranchTarget. Behind the scenes, a
> product or source package would be adapted to IBranchTarget to retrieve
> values like 'branch_target_name'. A PATCH that modified (eg.) both name
> and branch_target_name would make both object modifications within a
> single database transaction.
This just came up again in a different situation, with a couple of
additional requirements.
What we would like to do is avoid registry importing from so many of the
other apps, to avoid the circular dependencies.
To do this we are currently looking at having ISomething interfaces in
the apps (bugs, code, soyuz etc.) that define an interface relevant to
them. This is standard practice for a lot of things, see IBugTarget,
IHasBranches etc.
The implementations of these are then adapters, which isn't usually the
case.
class ProductToBugTarget():
adapts(IProduct)
implements(IBugTarget)
This means that all the bugs-specific code can live in lp.bugs.
This means that we want something similar to before, where some IProduct
methods should be made available over the webservice by adapting the
IProduct and calling the methods on the result.
In order to break the circular dependency we need to stop IProduct from
deriving from IBugTarget as well. In our experimental branch we define
a marker interface in lp.registry for things that can be adapted to bug
targets, which helps with registration etc.
class IProduct(ICanBeBugTarget):
The wrinkle that this has it that it doesn't accomodate the webservice.
Currently in order for IBugTarget methods to be available on IProduct
they have to be available in the interface that IProduct derives from,
currently IBugTarget, which means that bugs code has to be imported in
to the registry.
Using ICanBeBugTarget means that IBugTarget can't add methods to
IProduct right now. Therefore we want a way to annotate that extra
methods should be added from the webservice point of view, but
crucially, we don't want to import the bugs interface in order to do
that.
class ICanBeBugTarget(Interface):
@import_from_adapter(IBugTarget)
requires importing lp.bugs.interfaces.bugtarget.IBugTarget, which gives
us the circular dependencies again.
Would it be possible for us to instead have something like:
class ProductToBugTarget():
@only_used_in_adaptations
@add_things_to(IProduct)
such that the arrow is drawn the other way, and apps can add things to
registry objects without the registry having to import them?
I don't see why this can't be done, except that it means that finding
out the methods on an object is now a global operation, requiring
importing everything and considering the result, rather than just
importing the interface and scanning it.
Thanks,
James
Follow ups
References