Discussion:
scoped containers...
Olaf Krische
2009-05-11 17:36:57 UTC
Permalink
Hello,


i have created a caching container for all my singletons:


MutablePicoContainer cachingContainer;
cachingContainer = new PicoBuilder().withCaching().build();
cachingContainer.addComponent(singletonIF1.class, singletonIF1Impl.class);
...



Now i have certain components which needs "runtime arguments", like a user.
At the moment i do something like this:

public I getInstance(Class impl, User user) {
Parameter[] params = new Parameter[]{new ConstantParameter(user)};
MutablePicoContainer instanceContainer = new
PicoBuilder(cachingContainer).build();
instanceContainer.addComponent(UserProviderIF.class, UserProvider.class,
params);
instanceContainer.addComponent(impl);
return instanceContainer.getComponent(impl);
}


This is pretty annoying and costly, that i have to create a new container at
each method call, because i can add Class only, when i have the user
available. I could have a cache to store the container for each user, but
thats overkill as well.

Is there an alternate way of doing this?

I am close to do something like that:


instanceContainer.addComponent(singletonIF1.class, singletonIF1Impl.class);
instanceContainer.addComponent(UserProviderIF.class.class,
ThreadLocalUserProvider.class);
instanceContainer.addComponent(MyIF.class, MyIFImpl.class);


On each getInstance() i will write the user into a thread local variable,
which will then be read by the ThreadLocalUserProvider, when it is being
instantiated.

But anyhow this does not seem to be very clean. No one can assure me, that
the creationg of the UserProvider instance will happen in the same thread as
the caller.

Does someone have another idea?

Big Thanks in advance!
--
View this message in context: http://www.nabble.com/scoped-containers...-tp23488025p23488025.html
Sent from the NanoContainer - PicoContainer - Users mailing list archive at Nabble.com.
Konstantin Priblouda
2009-05-11 18:17:18 UTC
Permalink
Subject: [picocontainer-user] scoped containers...
Date: Monday, May 11, 2009, 8:36 PM
Hello,
.... no objections here ;)
Now i have certain components which needs "runtime
arguments", like a user.
public I getInstance(Class impl, User user) {
Parameter[] params = new Parameter[]{new
ConstantParameter(user)};
MutablePicoContainer instanceContainer = new
PicoBuilder(cachingContainer).build();
instanceContainer.addComponent(UserProviderIF.class,
UserProvider.class,
params);
instanceContainer.addComponent(impl);
return instanceContainer.getComponent(impl);
}
This is pretty annoying and costly, that i have to create a
new container at
each method call, because i can add Class only, when i have
the user
available.
Basically you can add (register) your components, even if here no
dependencies available at the moment. But they have to be present,
when component is about to be instantiated / injected
I could have a cache to store the container for
each user, but
thats overkill as well.
Is there an alternate way of doing this?
Maybe hot-swapping is that what you need?

http://www.picocontainer.org/hiding.html
instanceContainer.addComponent(singletonIF1.class,
singletonIF1Impl.class);
instanceContainer.addComponent(UserProviderIF.class.class,
ThreadLocalUserProvider.class);
instanceContainer.addComponent(MyIF.class, MyIFImpl.class);
On each getInstance() i will write the user into a thread
local variable,
which will then be read by the ThreadLocalUserProvider,
when it is being
instantiated.
But anyhow this does not seem to be very clean. No one can
assure me, that
the creationg of the UserProvider instance will happen in
the same thread as
the caller.
While puprose of pico, is [try] to avoid such clumsy constructions - so having component depending on user provider, is non-picoish way of
doing this. There are also a lot of adapters / behaviours storing
components in awkward places - in thread locals, JNDI, accessing comonents via JMX... Surelythere is something fo you there.

regards,

----[ Konstantin Pribluda http://www.pribluda.de ]----------------
JTec quality components: http://www.pribluda.de/projects/





---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Olaf Krische
2009-05-11 18:54:35 UTC
Permalink
Hello Konstantin, big thanks for the quick answer.
Post by Konstantin Priblouda
Post by Olaf Krische
instanceContainer.addComponent(singletonIF1.class,
singletonIF1Impl.class);
instanceContainer.addComponent(UserProviderIF.class.class,
ThreadLocalUserProvider.class);
instanceContainer.addComponent(MyIF.class, MyIFImpl.class);
On each getInstance() i will write the user into a thread
local variable,
which will then be read by the ThreadLocalUserProvider,
when it is being
instantiated.
But anyhow this does not seem to be very clean. No one can
assure me, that
the creationg of the UserProvider instance will happen in
the same thread as
the caller.
While puprose of pico, is [try] to avoid such clumsy constructions - so
having component depending on user provider, is non-picoish way of
doing this. There are also a lot of adapters / behaviours storing
components in awkward places - in thread locals, JNDI, accessing
comonents via JMX... Surelythere is something fo you there.
Why is it clumsy to depend on user provider? I have my reasons, why i do not
use the user itself in the constructor as parameter. The "User.class" is
already registered to deliver a proper User-Implementation with a completely
different set of parameters. Though i get the idea, but i am not so far with
rewriting the whole app yet.

Ok, let me re-ask my question to a more "best practise" question.

How to write this properly and not clumsy with the help of the pico
container:

User user = users.lookup(id);

without executing:

container = new Container(parentContainer);
container.addComponent(User.class, UserByID.class, new Param[]{id});
container.getComponent(User.class);

on each lookup with a different id?
--
View this message in context: http://www.nabble.com/scoped-containers...-tp23488025p23489308.html
Sent from the NanoContainer - PicoContainer - Users mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Michael Rimov
2009-05-14 07:34:06 UTC
Permalink
Post by Olaf Krische
Ok, let me re-ask my question to a more "best practise" question.
How to write this properly and not clumsy with the help of the pico
User user = users.lookup(id);
container = new Container(parentContainer);
container.addComponent(User.class, UserByID.class, new Param[]{id});
container.getComponent(User.class);
on each lookup with a different id?
To be honest? I don't think it's a particularly good use case for
PicoContainer. (Not that your problem isn't a legitimate one, I just don't
think Pico is too much of a help for instantiating Entities... it's better for
instantiating Value Objects, Services, and Controllers).

Whenever I have something along these lines, I end up creating
an interface that Pico provides the instantiation for, but the implementation
itself does the actual construction of the object.

It's possible that this is exactly what you've been talking about, so if I'm
beating a dead horse, please forgive me :)

Example:

public interface UserFactory {

public User createUserWithId (String id);
}


public class DefaultUserProvider implements UserFactory {

public User createUserWithId (String id) {
return new DefaultUser(id);
}
}



Then where pico becomes useful is decoupling your controllers/services from
DefaultUserProvider:


public class MyController {
private UserFactory userProvider;

public MyController(UserFactory provider) {
this.userProvider = provider;
}

public void doSomething() {
User user = userProvider.createUserById("joe");
/* do something to user object here*/
}
}

And it is wired together like so:

MutablePicoContainer container = new
PicoBuilder().withCaching().withLifecycle().build();
container.addComponent(UserFactory.class, DefaultUserProvider.class)
.addComponent(MyController.class);


Now, at least MyController is abstracted away from the UserProvider
implementation. The user provider implementation is bound to a particular user
implementation, but at least the coupling stops there.

This also tends to follow Eric Evan's logic in his book "Domain Driven Designs"

Entities are created by "factories", and their state is stored
in "repositories".

And pico doesn't really try to replace that kind of model.

Otherwise, I don't think Pico is really meant to handle dynamic dependencies
like what you're asking for.

Is this helping?

-Mike





---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Paul Hammant
2009-05-14 12:12:28 UTC
Permalink
OK, i think the crux of this rests on the "where is the User needed".
I'm going assume an 'action' for a web framework.

class AddressChangeAction extends BaseAction {
public void doAction {
// right here
User user = pico.getComponent(User.class, UserByID.class,
new Param[]{id});
user.setAddressLine1(getRequest().getParam("line1");
user.setCity(getRequest().getParam("city");
user.setAZipCode(getRequest().getParam("zipcode"); // etc

}
}

So do you? interoperate with PicoContainer in the doAction of this
(admitedly crap) web framework? No. DI gives you the user.
Moreover, the container is not holding all users as is, as that would
be unfeasable. A Provider is the right solution for this.

Your action should look like:

class AddressChangeAction extends BaseAction {
User user;
public AddressChangeAction(User user) {
this.user = user;
}
public void doAction {
user.setAddressLine1(getRequest().getParam("line1");
user.setCity(getRequest().getParam("city");
user.setAZipCode(getRequest().getParam("zipcode"); // etc

}
}

And you should have a Provider like so : http://svn.codehaus.org/picocontainer/java/2.x/trunk/web/examples/ajax-email/src/java/org/picocontainer/web/sample/ajaxemail/UserFromCookieProvider.java

Note that it itself has dependencies. In this case a UserStore class
that is, no doubt, application scoped. The user made by this provider
is implicitly scoped for the session, but not actually cached as
such. Its lazily made on each request by invisible invocation of this
provide(..) method.

The big question is then, where are you using this - a web framework ?

Regards,
Post by Olaf Krische
Why is it clumsy to depend on user provider? I have my reasons, why i do not
use the user itself in the constructor as parameter. The
"User.class" is
already registered to deliver a proper User-Implementation with a completely
different set of parameters. Though i get the idea, but i am not so far with
rewriting the whole app yet.
Ok, let me re-ask my question to a more "best practise" question.
How to write this properly and not clumsy with the help of the pico
User user = users.lookup(id);
container = new Container(parentContainer);
container.addComponent(User.class, UserByID.class, new Param[]{id});
container.getComponent(User.class);
on each lookup with a different id?
--
View this message in context: http://www.nabble.com/scoped-containers...-tp23488025p23489308.html
Sent from the NanoContainer - PicoContainer - Users mailing list archive at Nabble.com.
---------------------------------------------------------------------
http://xircles.codehaus.org/manage_email
---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Olaf Krische
2009-05-14 13:38:45 UTC
Permalink
Hello Paul,
Post by Paul Hammant
be unfeasable. A Provider is the right solution for this.
class AddressChangeAction extends BaseAction {
User user;
public AddressChangeAction(User user) {
this.user = user;
}
public void doAction {
user.setAddressLine1(getRequest().getParam("line1");
user.setCity(getRequest().getParam("city");
user.setAZipCode(getRequest().getParam("zipcode"); // etc
}
}
http://svn.codehaus.org/picocontainer/java/2.x/trunk/web/examples/ajax-email/src/java/org/picocontainer/web/sample/ajaxemail/UserFromCookieProvider.java
Yeah, in the end there is this "HttpServletRequest" object, which has to be
injected somehow, the same problem like with my ID. So if iam in a web
framework, i need a container, which reads the HttpServletRequest from
somewhere on "provide".

At the moment i still stick to that ThreadLocal solution. Whenever i want a
component with an ID as parameter, i write it into a ThreadLocal variable.
The "ID provider" then reads it from this variable and provides this ID.

And no, i do not depend on a web framework. i just have many "entities", as
someone before named it. It can be User, Product, Picture, etc etc etc. And
all those parameter can come from files, request, etc etc.
--
View this message in context: http://www.nabble.com/scoped-containers...-tp23488025p23540796.html
Sent from the NanoContainer - PicoContainer - Users mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Paul Hammant
2009-05-18 10:36:31 UTC
Permalink
Olaf,

Here is the smallest posible stub web-technology that uses
PicoContainer and PicoContainer-Web for a DI controlled 'action'
design. Of course its useless as a web technology but you could build
a web framework on top of it.

Three scoped components, one servlet :- http://svn.codehaus.org/picocontainer/java/2.x/trunk/web/examples/stub-webapp/src/java/org/picocontainer/web/sample/stub/

The components have no deps on anything from org.picocontainer.* itself.

Regards,

- Paul
Post by Olaf Krische
Hello Paul,
Post by Paul Hammant
be unfeasable. A Provider is the right solution for this.
class AddressChangeAction extends BaseAction {
User user;
public AddressChangeAction(User user) {
this.user = user;
}
public void doAction {
user.setAddressLine1(getRequest().getParam("line1");
user.setCity(getRequest().getParam("city");
user.setAZipCode(getRequest().getParam("zipcode"); // etc
}
}
http://svn.codehaus.org/picocontainer/java/2.x/trunk/web/examples/ajax-email/src/java/org/picocontainer/web/sample/ajaxemail/UserFromCookieProvider.java
Yeah, in the end there is this "HttpServletRequest" object, which has to be
injected somehow, the same problem like with my ID. So if iam in a web
framework, i need a container, which reads the HttpServletRequest from
somewhere on "provide".
At the moment i still stick to that ThreadLocal solution. Whenever i want a
component with an ID as parameter, i write it into a ThreadLocal variable.
The "ID provider" then reads it from this variable and provides this ID.
And no, i do not depend on a web framework. i just have many
"entities", as
someone before named it. It can be User, Product, Picture, etc etc etc. And
all those parameter can come from files, request, etc etc.
--
View this message in context: http://www.nabble.com/scoped-containers...-tp23488025p23540796.html
Sent from the NanoContainer - PicoContainer - Users mailing list archive at Nabble.com.
---------------------------------------------------------------------
http://xircles.codehaus.org/manage_email
---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Konstantin Priblouda
2009-05-13 19:10:45 UTC
Permalink
Post by Olaf Krische
Why is it clumsy to depend on user provider? I have my
reasons, why i do not
use the user itself in the constructor as parameter.
Well, as always, it depends on your use case. UserProvider is a kind of
factory, and pico tries to eliminate them. Basic idea of dependency injection ist that user ( nor User, but user of User.class ) does not
care where it comes from and how it is managed. It just has one
( or not )

But depending on use case, such factory dependency may be justified.
Post by Olaf Krische
Ok, let me re-ask my question to a more "best practise"
question.
How to write this properly and not clumsy with the help of
the pico
User user = users.lookup(id);
   container = new
Container(parentContainer);
   container.addComponent(User.class,
UserByID.class, new Param[]{id});
   container.getComponent(User.class);
on each lookup with a different id?
Your example does not make much of usefull use case for pico container (yet). You are regstering user implementation, which is to be instantiated and injected with something found under key ID ( possibly in parent)
And as you are registering this impl by interface, there will be only one instance of user out of this container.

Let's imagine more interesting use case:
- I like to specify dependency on concrete user, using its ID as parameter and have it injected by pico container for my objects.

This can be done by wrapping your user factory in pico container
( just interface, immutable etc - relatively easy) with simple functionality - if someone asks for ID, return user with id or delegate to parent if there is none. Then you could do like this:

PicoContainer parent = new ...:
// ... rig it up ...
PicoContainer userContainer = new UserFactoryPicoContainer(parent);

PicoContainer child = new MutablePicoContainer(userContainer)

// here fun starts

child.addComponent("needUserWithId239",NeedAUser.class,new Param[]{ 239 });
...

Then if you ask for "needUserWithIde239", dependeny lookup will be delegated to userContainer, which will provide user with correct id for injection.


regards,
----[ Konstantin Pribluda http://www.pribluda.de ]----------------
JTec quality components: http://www.pribluda.de/projects/





---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Olaf Krische
2009-05-13 19:46:28 UTC
Permalink
Hello Konstantin,
Post by Konstantin Priblouda
- I like to specify dependency on concrete user, using its ID as
parameter and have it injected by pico container for my objects.
This can be done by wrapping your user factory in pico container
( just interface, immutable etc - relatively easy) with simple
functionality - if someone asks for ID, return user with id or delegate
// ... rig it up ...
PicoContainer userContainer = new UserFactoryPicoContainer(parent);
PicoContainer child = new MutablePicoContainer(userContainer)
// here fun starts
child.addComponent("needUserWithId239",NeedAUser.class,new Param[]{ 239 });
...
Then if you ask for "needUserWithIde239", dependeny lookup will be
delegated to userContainer, which will provide user with correct id for
injection.
But this is exactly the thing, that i wanted to avoid. I have millions of
IDs. I can not add all "IDs" in advance to the child. Nor i wanna create a
child, registering an ID and then asking for a component with the ID, since
all the dependencies must be resolved then, which i can imagine is a kind of
"expensive" operation.

Hm.
--
View this message in context: http://www.nabble.com/scoped-containers...-tp23488025p23528647.html
Sent from the NanoContainer - PicoContainer - Users mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Jörg Schaible
2009-05-14 15:48:12 UTC
Permalink
Post by Olaf Krische
Hello Konstantin,
Post by Konstantin Priblouda
- I like to specify dependency on concrete user, using its ID as
parameter and have it injected by pico container for my objects.
This can be done by wrapping your user factory in pico container
( just interface, immutable etc - relatively easy) with simple
functionality - if someone asks for ID, return user with id or delegate
// ... rig it up ...
PicoContainer userContainer = new UserFactoryPicoContainer(parent);
PicoContainer child = new MutablePicoContainer(userContainer)
// here fun starts
child.addComponent("needUserWithId239",NeedAUser.class,new Param[]{ 239 });
...
Then if you ask for "needUserWithIde239", dependeny lookup will be
delegated to userContainer, which will provide user with correct id for
injection.
But this is exactly the thing, that i wanted to avoid. I have millions of
IDs. I can not add all "IDs" in advance to the child. Nor i wanna create a
child, registering an ID and then asking for a component with the ID,
since all the dependencies must be resolved then, which i can imagine is a
kind of "expensive" operation.
In that case you can register the services depending on the user id also
using a threadlocal cache instead of a standard cache. Mixing services with
standard cache behaviour and threadlocal cache behaviour is completely
transparent for the individual services and you can register them in the
same container at once.

- Jörg
Post by Olaf Krische
Hm.
---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Konstantin Priblouda
2009-05-14 06:07:35 UTC
Permalink
Post by Olaf Krische
But this is exactly the thing, that i wanted to avoid. I
have millions of
IDs. I can not add all "IDs" in advance to the child. Nor i
wanna create a
child, registering an ID and then asking for a component
with the ID, since
all the dependencies must be resolved then, which i can
imagine is a kind of
"expensive" operation.
Hm.
I must admit, that I do not fully grok your use case. What (and where to)
do you like to have injected or instantiated?

regards,
----[ Konstantin Pribluda http://www.pribluda.de ]----------------
JTec quality components: http://www.pribluda.de/projects/






---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Olaf Krische
2009-05-14 13:04:11 UTC
Permalink
Hello Konstantin,
Post by Konstantin Priblouda
Post by Olaf Krische
But this is exactly the thing, that i wanted to avoid. I
have millions of
IDs. I can not add all "IDs" in advance to the child. Nor i
wanna create a
child, registering an ID and then asking for a component
with the ID, since
all the dependencies must be resolved then, which i can
imagine is a kind of
"expensive" operation.
I must admit, that I do not fully grok your use case. What (and where to)
do you like to have injected or instantiated?
Nonetheless, i thank you for still following this. :-)

Little objects like User will be instantiated:

user = new UserImpl1(ID id);

This will happen very often, when creating user from IDs in a file or from a
request.

But then again, i like to change the constructor to:

user = new UserImpl2(SomeOtherClass some, ID id);

Here i would like to take profit from injection.

One way to do this is to create a new child container, adding either
UserImpl1 or UserImpl2 with its runtime parameter, as you have shown me.
This works perfectly, but is a very expensive operation compared to the
little object i want to have instantiated.

Another idea would be to add UserImpl to the container as well as adding a
"placeholder" or "shadow parameter" ID. Then i ask the container to compile
me a function for getting a component of a "UserImpl" and the function will
have this "placeholder" as parameter:

Maybe like this:

container.addComponent(User.class, UserImpl.class, ID.class);
Function<ID, User> function = container.getComponentFunction(UserImpl.class,
ID.class);

and then later:

ID id = ...;
User user = function.getComponent(id);

I can re-use this function. Each time i will call getComponent(id), it will
instantiate (light weight) the User. No complicated dependencies resolving
is necessary anymore, since this path has been compiled already once within
this function.

Something like that.

But you might be right also, maybe this is not, what i should do with pico
container. It probably destroys as well all the neat features that can be
dynamically added to the container and such.

Bye!
--
View this message in context: http://www.nabble.com/scoped-containers...-tp23488025p23540154.html
Sent from the NanoContainer - PicoContainer - Users mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Continue reading on narkive:
Loading...