Discussion:
Singleton Container
Peter Karich
2008-04-17 12:22:29 UTC
Permalink
Hi,

I am relatively new to the 'dependency injection' stuff, but I would
really like to use PicoContainer in my application to make test driven
development easier.
At the moment I use the lookup API of NetBeans, which is easy to use as
a service-locator.

Here is an example of one usage in my application:
ISerializer xs = Lookup.getDefault().lookup(ISerializer.class);
Object obj = xs.fromXML(new FileInputStream("xmlFile"));
where an implementation of ISerializer constructs an object from a xml file:
public interface ISerializer {
void toXML(Object o, OutputStream os) throws IOException;
Object fromXML(InputStream is) throws IOException;
}
to be implemented with the help of e.g. XStream.

Now my questions are:
Can I use PicoContainer as a service-locator like the Lookup API?
If yes, is it recommended to use such a replaceable singleton like the
NetBeans folks did it?
E.g.: MutablePicoContainer pico = Container.getDefault();
I am unsure to use singletons at all, because of this article:
http://www.picocontainer.org/singleton-antipattern.html

But with the singleton approach I need to configure the container only
one time e.g. on startup. Or is this the right way to do it:
http://jaxor.sourceforge.net/?q=pico
(see PicoInstanceFactory)


Regards,
Peter.



PS: Why isn't there a link on the picocontainer homepage to the mailing
list (on the left side)? And to some use cases (real world apps) or to
nanocontainer? Maybe I am to stupid to find the links ...

PSS: Which one is the latest release of PicoContainer? If 2.1 is, then
http://www.picocontainer.org/downloads.html
is out of date.

PSSS: Thanks a lot for all the work on picocontainer and of course on
nanocontainer where I can use Java to set-up the container - this is
really great. You should have mentioned them MegaContainer are sth.else ;-)


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

http://xircles.codehaus.org/manage_email
Jörg Schaible
2008-04-17 13:29:26 UTC
Permalink
Hi Peter,
Post by Peter Karich
Hi,
I am relatively new to the 'dependency injection' stuff, but I would
really like to use PicoContainer in my application to make
test driven
development easier.
At the moment I use the lookup API of NetBeans, which is easy
to use as
a service-locator.
ISerializer xs = Lookup.getDefault().lookup(ISerializer.class);
Object obj = xs.fromXML(new FileInputStream("xmlFile"));
where an implementation of ISerializer constructs an object
public interface ISerializer {
void toXML(Object o, OutputStream os) throws IOException;
Object fromXML(InputStream is) throws IOException; }
to be implemented with the help of e.g. XStream.
Can I use PicoContainer as a service-locator like the Lookup API?
Yes.
Post by Peter Karich
If yes, is it recommended to use such a replaceable singleton
like the
NetBeans folks did it?
Why is it necessary?
Post by Peter Karich
E.g.: MutablePicoContainer pico = Container.getDefault();
http://www.picocontainer.org/singleton-antipattern.html
But with the singleton approach I need to configure the
container only
http://jaxor.sourceforge.net/?q=pico
(see PicoInstanceFactory)
For a standard Java application, you don't need a singleton. You solve this typically by declaring an own ServiceLocator interface and the default implementation has then a main method to start the application and in its ctor it sets up the Pico(Hierarchy) and registers itself. Any component that needs the ServiceLocator can simply declare that dependency as ctor argument. It then depends on your needs wether your ServiceLocator interface provides a generic lookup or individual methods to lookup defined services. That way only your main app references Pico classes at all (well, unless you decide to use Picos Lifecylce, but you can define your own one).
Post by Peter Karich
Regards,
Peter.
PS: Why isn't there a link on the picocontainer homepage to
the mailing
list (on the left side)? And to some use cases (real world
apps) or to
nanocontainer? Maybe I am to stupid to find the links ...
No, you're right. You may find it using the "Project" link and then follow to the "Xircles management page", but that's quite annoying (see also auto-generated footer). Nanocontainer has its own home page at www.nanocontainer.org, but it's even more outdated :(
Post by Peter Karich
PSS: Which one is the latest release of PicoContainer? If 2.1 is, then
http://www.picocontainer.org/downloads.html
is out of date.
Thanks for heads-up. Paul, didn't you had once a check list with TODOs for a new release ?? ;-)
Post by Peter Karich
PSSS: Thanks a lot for all the work on picocontainer and of course on
nanocontainer where I can use Java to set-up the container - this is
really great. You should have mentioned them MegaContainer
are sth.else ;-)
No, no, we like to stay small and under the hood ;-)

- Jörg

BTW: Actually a MacroContainer exists also <g>

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

http://xircles.codehaus.org/manage_email
Konstantin Priblouda
2008-04-18 18:02:16 UTC
Permalink
My second problem is: how can I specify if a
component should be created
on every injection or if it should be a 'singleton'?
by using specific behaviour ( formerly known as
component adapter ) - use caching is you like
singleton, omit it if you like new copy injected
each time ( there is a lot of much more funny adapters
)
And then I have a third problem. Expect the
public interface ILogger {
void log(String str);
}
public class LoggerImpl implements ILogger {
private Logger logger;
public LoggerImpl(Class clazz) {
logger =
Logger.getLogger(clazz.getSimpleName());
}
public void log(String str) {
logger.info(str);
}
}
Now, is it possible to inject LoggerImpl instances
into the following class?
public class EncryptedConnection implements
IConnection {
private ILogger logger;
public EncryptedConnection(ILogger log) {
logger = log;
}
}
For example with a 'tricky parameter' while
configuration that uses
getClass() of the EncryptedConnection class?
No need to be tricky:
container.addComponentInstance(ClassToBeIbjectedToLogger.class);
container.addComponent(LoggerImpl,class);
container.addComponent(EncryptetConnection.class);

container.getComponentINstance(EncryptedConnection.class);

Class for logger is registered as instance,
and will be injected to logger, and logger
will be injected to encrypted connection.
Hope my question are not sooo stupid ;-)
Not at all ;)

regards,


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


____________________________________________________________________________________
Be a better friend, newshound, and
know-it-all with Yahoo! Mobile. Try it now. http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ

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

http://xircles.codehaus.org/manage_email
Paul Hammant
2008-04-18 18:10:29 UTC
Permalink
If you set up Caching as a default,

you can for individual components specify NO_CACHE -> http://www.picocontainer.org/properties.html

- Paul
Post by Konstantin Priblouda
My second problem is: how can I specify if a
component should be created
on every injection or if it should be a 'singleton'?
by using specific behaviour ( formerly known as
component adapter ) - use caching is you like
singleton, omit it if you like new copy injected
each time ( there is a lot of much more funny adapters
)
And then I have a third problem. Expect the
public interface ILogger {
void log(String str);
}
public class LoggerImpl implements ILogger {
private Logger logger;
public LoggerImpl(Class clazz) {
logger =
Logger.getLogger(clazz.getSimpleName());
}
public void log(String str) {
logger.info(str);
}
}
Now, is it possible to inject LoggerImpl instances
into the following class?
public class EncryptedConnection implements
IConnection {
private ILogger logger;
public EncryptedConnection(ILogger log) {
logger = log;
}
}
For example with a 'tricky parameter' while
configuration that uses
getClass() of the EncryptedConnection class?
container.addComponentInstance(ClassToBeIbjectedToLogger.class);
container.addComponent(LoggerImpl,class);
container.addComponent(EncryptetConnection.class);
container.getComponentINstance(EncryptedConnection.class);
Class for logger is registered as instance,
and will be injected to logger, and logger
will be injected to encrypted connection.
Hope my question are not sooo stupid ;-)
Not at all ;)
regards,
----[ Konstantin Pribluda http://www.pribluda.de ]----------------
JTec quality components: http://www.pribluda.de/projects/
____________________________________________________________________________________
Be a better friend, newshound, and
know-it-all with Yahoo! Mobile. Try it now. http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ
---------------------------------------------------------------------
http://xircles.codehaus.org/manage_email
---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Peter Karich
2008-04-19 13:26:50 UTC
Permalink
Hi Paul and Konstantin,

now I understand how to go with caching (and singletons).
Post by Konstantin Priblouda
container.addComponentInstance(ClassToBeIbjectedToLogger.class);
container.addComponent(LoggerImpl,class);
container.addComponent(EncryptetConnection.class);
container.getComponentINstance(EncryptedConnection.class);
But there will be several classes which uses the logger.
In my last mail I was not quite precise, so now I will try again:
Before I discovered picocontainer I used a factory in the classes which
need a logger:
class Bla1 { private final Logger
logger=LoggerFactory.getLogger(Bla1.class); ... }
class Bla2 { private final Logger
logger=LoggerFactory.getLogger(Bla2.class); ... }

Now I would like to use DI for this. Are there better solutions than:
class Bla1 {
private Logger logger;
public Bla1(IServiceLocator sl) { logger = sl.getLogger(Bla1.class); }
}

Regards,
Peter.


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

http://xircles.codehaus.org/manage_email
Konstantin Priblouda
2008-04-20 19:19:38 UTC
Permalink
Post by Peter Karich
Hi Paul and Konstantin,
now I understand how to go with caching (and
singletons).
container.addComponentInstance(ClassToBeIbjectedToLogger.class);
Post by Peter Karich
Post by Konstantin Priblouda
container.addComponent(LoggerImpl,class);
container.addComponent(EncryptetConnection.class);
container.getComponentINstance(EncryptedConnection.class);
Post by Peter Karich
But there will be several classes which uses the
logger.
In my last mail I was not quite precise, so now I
Before I discovered picocontainer I used a factory
in the classes which
class Bla1 { private final Logger
logger=LoggerFactory.getLogger(Bla1.class); ... }
class Bla2 { private final Logger
logger=LoggerFactory.getLogger(Bla2.class); ... }
Now I would like to use DI for this. Are there
class Bla1 {
private Logger logger;
public Bla1(IServiceLocator sl) { logger =
sl.getLogger(Bla1.class); }
}
If ther e is more than one thing of a kind,
you will have to be little more explicit ;)
( adding sane component keys )

In this case, loggers shall be keyed by classes
they become injected in them, and classes by some
other key ( default would be a Class.class ) - why not

FQN?

You could write little nice wrapper, which registers
class and logger on the contaienr at once

regards,

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


____________________________________________________________________________________
Be a better friend, newshound, and
know-it-all with Yahoo! Mobile. Try it now. http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ

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

http://xircles.codehaus.org/manage_email
Peter Karich
2008-04-21 19:12:01 UTC
Permalink
Post by Konstantin Priblouda
Post by Peter Karich
class Bla1 {
private Logger logger;
public Bla1(IServiceLocator sl) { logger =
sl.getLogger(Bla1.class); }
}
If ther e is more than one thing of a kind,
you will have to be little more explicit ;)
( adding sane component keys )
In this case, loggers shall be keyed by classes
they become injected in them, and classes by some
other key ( default would be a Class.class ) - why not
FQN?
Would this work too: leave default key for classes and use fully
qualified name as key for the loggers
?
Post by Konstantin Priblouda
You could write little nice wrapper, which registers
class and logger on the contaienr at once
Hmmh, I tried, but I was not successful. Did you mean adapter (instead
wrapper) like this:
http://www.picocontainer.org/adapters.html

I think the 'logger' problem is very common, so how do you handle them?
In EJB3 they can do:
@Logger

private Log log;


Thanks,
Peter.


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

http://xircles.codehaus.org/manage_email
Paul Hammant
2008-04-21 19:40:55 UTC
Permalink
The ket is that you want a different logger each of these right ? :-

public class Comp1 {
@Inject private Log log;
// constructors and methods
}
public class Comp2 {
@Inject private Log log;
// constructors and methods
}

Pico could happily inject the same log instance to each of them.

What if there were some grammar like:

pico.addAdapter(Log.class, new Provider<Log>() {
public Log provide(Class clazz) {
return LoggerFactory.getLogger(clazz)
}
} );
pico.addComponent(Comp1.class);
pico.addComponent(Comp2.class);

... where Pico somehow called ...

Log log1 = (Log) provide(Comp1.class);

... before injecting Comp1's field after instantiation.

- Paul
Post by Peter Karich
Post by Peter Karich
class Bla1 {
private Logger logger;
public Bla1(IServiceLocator sl) { logger =
sl.getLogger(Bla1.class); }
}
If ther e is more than one thing of a kind, you will have to be
little more explicit ;) ( adding sane component keys ) In this
case, loggers shall be keyed by classes they become injected in
them, and classes by some
other key ( default would be a Class.class ) - why not
FQN?
Would this work too: leave default key for classes and use fully
qualified name as key for the loggers
?
You could write little nice wrapper, which registers class and
logger on the contaienr at once
Hmmh, I tried, but I was not successful. Did you mean adapter
http://www.picocontainer.org/adapters.html
I think the 'logger' problem is very common, so how do you handle
@Logger
private Log log;
Thanks,
Peter.
---------------------------------------------------------------------
http://xircles.codehaus.org/manage_email
Jörg Schaible
2008-04-21 21:22:57 UTC
Permalink
Post by Paul Hammant
The ket is that you want a different logger each of these right ? :-
public class Comp1 {
@Inject private Log log;
// constructors and methods
}
public class Comp2 {
@Inject private Log log;
// constructors and methods
}
Pico could happily inject the same log instance to each of them.
pico.addAdapter(Log.class, new Provider<Log>() {
public Log provide(Class clazz) {
return LoggerFactory.getLogger(clazz)
}
} );
pico.addComponent(Comp1.class);
pico.addComponent(Comp2.class);
... where Pico somehow called ...
Log log1 = (Log) provide(Comp1.class);
... before injecting Comp1's field after instantiation.
Then why not simply implement a new behavior (Logging/LogEnabled)? The
LogEnabled.getComponentInstance() would use reflection and examine the
returned instance from the inner chain for declared Log field members and
inject them accordingly (possible caching should be in the outer chain).

- Jörg


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

http://xircles.codehaus.org/manage_email
Paul Hammant
2008-04-22 14:33:26 UTC
Permalink
Peter,

I have a pending change to PicoContainer. Its something that could
make v2.2 subject to your approval and a modest debate amongst the
committers. See below.

The class Turnip needs Constructor injection AND annotated field
injection. The latter is for 'Swede' but it might as easily be your
@Logger/Log scenario.

In bold are all the bits that serve it. I've made an inner class
extension of a new class 'FactoryAdapter'. What is new is that class
is being handed the class its about to inject into. You'd modify
getComponnentInstance(..) to be somethong that used the logFactory.

Let me know if this would serve your purpose - I think i would.

----

public static interface Swede {
}
public static class Turnip {
@Inject
Swede swede;

private final String foo;

public Turnip(String foo) {
this.foo = foo;
}

public Swede getSwede() {
return swede;
}

public String getFoo() {
return foo;
}
}

@Test public void testThatComponentCanHaveAProvidedDependency() {
MutablePicoContainer container = new DefaultPicoContainer(new
MultiInjection());
container.addComponent(String.class, "foo");
container.addComponent(Turnip.class);

container.addAdapter(new FactoryAdapter<Swede>() {
public Swede getComponentInstance(PicoContainer
container, final Class clazz) throws PicoCompositionException {
return new Swede() {
public String toString() {
return "Swede:" + clazz.getName();
}
};
}
});

Turnip t = container.getComponent(Turnip.class);
assertNotNull(t);
assertEquals("Swede:" + Swede.class.getName(),
t.getSwede().toString());
assertEquals("foo", t.getFoo());

}


- Paul
Konstantin Priblouda
2008-04-22 16:13:16 UTC
Permalink
Post by Peter Karich
Would this work too: leave default key for classes
and use fully
qualified name as key for the loggers
?
basically you could take anything as key,
as long it descends fromobject and provides hascCode
and equals ;)

but default behaviour, is to look for class of
dependency as a key.
regards,

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


____________________________________________________________________________________
Be a better friend, newshound, and
know-it-all with Yahoo! Mobile. Try it now. http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ

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

http://xircles.codehaus.org/manage_email
Peter Karich
2008-04-23 08:56:09 UTC
Permalink
Sorry for the late answer and thanks for your effort.
Post by Paul Hammant
The ket is that you want a different logger each of these right ?
Yes, that's right.
The adapter could satisfy my needs.

But, just in the case I didn't understand you correctly;
is this the pattern I have to call the adapter:

container.addAdapter(new FactoryAdapter<Log>() {
public Log getComponentInstance(PicoContainer container, final Class
clazz) throws PicoCompositionException {
// now clazz is Turnip.class!?
return LoggerFactory.getLogger(clazz);
}
});
Turnip t = container.getComponent(Turnip.class);
assertNotNull(t);
assertEquals("Turnip's-Logger-class:" + Turnip.class,
t.getLog().getClass());


Regards,
Peter.


PS: Why I can't find such a container.getComponentInstance method? I use
pico 2.1


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

http://xircles.codehaus.org/manage_email
Jörg Schaible
2008-04-23 08:28:30 UTC
Permalink
Post by Peter Karich
Sorry for the late answer and thanks for your effort.
Post by Paul Hammant
The ket is that you want a different logger each of these right ?
Yes, that's right. The adapter could satisfy my needs.
But, just in the case I didn't understand you correctly;
container.addAdapter(new FactoryAdapter<Log>() {
public Log getComponentInstance(PicoContainer container,
final Class
clazz) throws PicoCompositionException {
// now clazz is Turnip.class!?
return LoggerFactory.getLogger(clazz);
}
});
Turnip t = container.getComponent(Turnip.class);
assertNotNull(t);
assertEquals("Turnip's-Logger-class:" + Turnip.class,
t.getLog().getClass());
Regards,
Peter.
PS: Why I can't find such a container.getComponentInstance
method? I use
pico 2.1
Because it is a proposal for API change that has not be applied yet even in the head revision. ;-)

- Jörg

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

http://xircles.codehaus.org/manage_email
Paul Hammant
2008-04-23 12:35:56 UTC
Permalink
Peter,

Yes, as Jörg says it - its not committed (or released) yet :-)

Your code as below would work.

With some additional work, it should be OK to use @Logger instead of
@Inject (if that were important to you).

- Paul
Post by Jörg Schaible
Post by Peter Karich
Sorry for the late answer and thanks for your effort.
Post by Paul Hammant
The ket is that you want a different logger each of these right ?
Yes, that's right. The adapter could satisfy my needs.
But, just in the case I didn't understand you correctly;
container.addAdapter(new FactoryAdapter<Log>() {
public Log getComponentInstance(PicoContainer container,
final Class
clazz) throws PicoCompositionException {
// now clazz is Turnip.class!?
return LoggerFactory.getLogger(clazz);
}
});
Turnip t = container.getComponent(Turnip.class);
assertNotNull(t);
assertEquals("Turnip's-Logger-class:" + Turnip.class,
t.getLog().getClass());
Regards,
Peter.
PS: Why I can't find such a container.getComponentInstance
method? I use
pico 2.1
Because it is a proposal for API change that has not be applied yet
even in the head revision. ;-)
- Jörg
---------------------------------------------------------------------
http://xircles.codehaus.org/manage_email
---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Peter Karich
2008-04-23 13:47:26 UTC
Permalink
Hi!
Post by Paul Hammant
Yes, as Jörg says it - its not committed (or released) yet :-)
Okay.
Post by Paul Hammant
Your code as below would work.
@Inject (if that were important to you).
No, it does not matter.

Kind regards,
Peter.


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

http://xircles.codehaus.org/manage_email
Paul Hammant
2008-04-23 13:03:13 UTC
Permalink
OK, I've committed it.

If you want to try it out -

svn co https://svn.codehaus.org/picocontainer/java/2.x/trunk/pico
mvn install

That should make the main pico jar as picocontainer-2.2-SNAPSHOT.jar

'Class info' has been changed to 'Type info' in the version I
committed ..... just cast it to class for your purposes in that inner
class.

- Paul
Post by Peter Karich
Hi!
Post by Paul Hammant
Yes, as Jörg says it - its not committed (or released) yet :-)
Okay.
Post by Paul Hammant
Your code as below would work.
No, it does not matter.
Kind regards,
Peter.
---------------------------------------------------------------------
http://xircles.codehaus.org/manage_email
---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Peter Karich
2008-04-23 17:30:09 UTC
Permalink
Hi all,

thanks a lot for your work and ideas.
Now it works and I am impressed!

Regards,
Peter.

PS: For all who want a running (more or less stupid) example you can
visit: http://www.timefinder.de/files/PicoExample-1.1.zip
Before building it (again) copy dist/lib to lib/


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

http://xircles.codehaus.org/manage_email
Peter Karich
2008-04-23 20:47:40 UTC
Permalink
Hi,

one small info:

container.change(Characteristics.CACHE);
container.addAdapter(new FactoryAdapter<Logger>() {
public Logger getComponentInstance(PicoContainer container,
final Type clazzInfo) throws PicoCompositionException {
return LoggerFactory.getLogger((Class)clazzInfo);
}
});
will let clazzInfo==null. Maybe it would be better to use Object.class
instead? Just to avoid NPE's ...

Peter.
Post by Peter Karich
Hi all,
thanks a lot for your work and ideas.
Now it works and I am impressed!
Regards,
Peter.
---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Peter Karich
2008-04-18 14:26:11 UTC
Permalink
Hi Jörg,

thanks for your answers.

Your solution would require that I have to put *all* the classes (which
will need the servicelocator) into the 'main-container', right?
But then I even need access to package protected classes that implements
a specific public interface?

My second problem is: how can I specify if a component should be created
on every injection or if it should be a 'singleton'?

And then I have a third problem. Expect the following scenario:
public interface ILogger {
void log(String str);
}
public class LoggerImpl implements ILogger {
private Logger logger;
public LoggerImpl(Class clazz) {
logger = Logger.getLogger(clazz.getSimpleName());
}
public void log(String str) {
logger.info(str);
}
}
Now, is it possible to inject LoggerImpl instances into the following class?
public class EncryptedConnection implements IConnection {
private ILogger logger;
public EncryptedConnection(ILogger log) {
logger = log;
}
}
For example with a 'tricky parameter' while configuration that uses
getClass() of the EncryptedConnection class?
Or is it better to solve it via 'servicelocator' pattern as I did it in
my simple example [1]?

Hope my question are not sooo stupid ;-)

Regards,
Peter.




[1]
http://www.timefinder.de/files/PicoExample-1.0.zip
To compile the example put the jars in dist/lib to lib/
I would really like to hear your opinion about the design of the example
(if sth. is totally wrong).

PS: Maybe I am wrong but www.microcontainer.org isn't the expected site
for the suggested microcontainer project, right? Or did you mean the
JBoss microcontainer?


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

http://xircles.codehaus.org/manage_email
Loading...