Discussion:
Unnecessary type check?
Tim Peierls
2011-01-19 14:01:05 UTC
Permalink
Most recent trunk has defensive code in Finder that looks like it was left
over from when targetClass was Class<?>:

public static Finder createFinder(
Class<? extends ServerResource> targetClass,
Class<? extends Finder> finderClass, Context context, Logger
logger) {
Finder result = null;

*if (ServerResource.class.isAssignableFrom(targetClass)) {*
...
} else {
// Log with this warning: "Cannot create a Finder for the given
target class, since
// it is neither a subclass of Resource nor a subclass of
ServerResource."
}

return result;
}

That isAssignableFrom check should always be true now. If it isn't,
someone's trying to subvert the type system. You could either leave out the
check, turn it into an assertion, or at least log it with more severity than
a warning.

--tim

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699086
Tim Peierls
2011-01-19 19:43:43 UTC
Permalink
Two more items, one a minor nit, one a *long *proposal. Add these to the
previous observation about unnecessary type check in Finder, and I guess
each of them could be considered a potential issue, but I'm unsure of the
protocol here: Do I just create 3 issues or wait for the official go-ahead?

Anyway, here's the nit:

How about expressing deprecated Application.setClientRoot in terms of
setOutboundRoot rather than the other way around? That way when the
deprecated method is eventually removed, you don't have to change anything
else.

The proposal takes up the rest of this message.

-----

The Guice extension in Restlet's incubator is working fine but is still
unsatisfying to use. You have to write things like this:

// Have to pass in finderFactory from somewhere...
router.attach("/path/to/resource",
finderFactory.finder(MyServerResource.class));

when you'd rather have all the finderFactory machinery taken care of by a
single call at startup so you could just write this:

router.attach("/path/to/resource", MyServerResource.class);

There are several Restlet subclasses besides Router that have methods taking
a targetClass argument of type Class<? extends ServerResource> (or nextClass
or in(/out)boundRootClass), and we'd rather not have to use an explicit
FinderFactory instance for any of them.

These methods are all implemented by turning target/next/rootClass into a
Finder and then calling the corresponding method that takes a Restlet
argument instead of a Class<? extends ServerResource>. They go about
obtaining a Finder from a resource type in several subtly different ways:

Application uses Finder.createFinder(rootClass, finderClass, context,
logger), where finderClass, context, and logger are all properties of the
Application. When finderClass is null (as it is by default for
Applications), Finder.createFinder returns new Finder(context, rootClass).

Router and its subclasses InternalRouter and VirtualHost use
Router.createFinder(targetClass), which by default calls Finder.createFinder
the same way Application does. Note that finderClass is not a general
Restlet property; it is declared separately in Application and Router. By
default finderClass is Finder.class for Routers, and in that case
Finder.createFinder constructs an instance of the given Finder (sub)class
with the context and targetClass arguments. This ends up being equivalent to
new Finder(context, targetClass) in the default case.

Server, Filter, and ServerList use new Finder(context, nextClass), where
context is Context.getCurrent() for Server and getContext() for Filter and
ServerList.

So in the default case all of these classes end up using new Finder(context,
targetClass). When handling requests, Finder.handle calls
Finder.find(request, response), which unless overridden calls
Finder.create(request, response), which unless overridden calls
Finder.create(targetClass, request, response), which just returns
targetClass.newInstance.

It all seems very flexible (if complicated to explain!). Trouble is that for
Guice (or any JSR-330-compliant framework) to perform constructor injection
of server resources, which is the whole point of the extension, the
framework has to do the constructing, not Class.newInstance.

How can this be accomplished? Let me count the ways:

1) You can override Router.createFinder to return an instance of a Finder
subclass that knows how to do the dependency injection. That works for
Router, but not for InternalRouter and VirtualHost, both of which already
override createFinder to set a child context. You could override
createFinder for both of those types, too, duplicating the child context
logic, but that's already starting to get ugly, and in any event it means
remembering to use InjectingRouter, InjectingInternalRouter, and
InjectingVirtualHost instead of the vanilla types (and remembering to
setInternalRouter to the extended type in Application.createOutboundRoot,
and Component.setDefaultHost ...)

2) You can remember to call setFinderClass on every instance of Application,
Router, InternalRouter, and VirtualHost that you deal with. You'll have no
warning that you missed one until newInstance is called for a class that
doesn't have a no-arg constructor.

3) Server, Filter, and ServerList: Nothing you can do here except override
the setNext(Class<? extends ServerResource>) method. That goes for all
subtypes of Filter, including Authenticator, Authorizer, Extractor, Route,
and Validator.

Summary: There is currently no practical way to replace the default behavior
of using new Finder(context, targetClass).

I propose that Restlet adopt one of the following two approaches:


1) Add Engine-level configurability of the way Finders are obtained from
Class<? extends ServerResource> in all of these classes.

A straightforward implementation would be to change Finder.createFinder to
check whether a FinderCreator has been registered with the Engine, where
FinderCreator looks like this:

public interface FinderCreator {
Finder createFinder(Context context, Class<? extends ServerResource>
targetClass);
}

If a FinderCreator has been registered with the Engine, use
finderCreator.createFinder(context, targetClass) to create the Finder
instead of constructor.newInstance(context, targetClass). The wrinkle here
is that we'd want people to be able to defeat this logic on a case-by-case
basis, say by passing in a non-null finderClass value. (That would mean that
the default Router.createFinder logic would pass null if its finderClass was
null *or equal to Finder.class*. (Or just change the default finderClass for
Router, if that wouldn't break code.)

Replace new Finder(context, nextClass) in Server, Filter, and ServerList
with Finder.createFinder(nextClass, null, context, logger) -- would have to
find a logger appropriate to ServerList -- so they get the same benefit.
Overriding this behavior would be harder -- maybe these classes could have a
finderClass property, too?

Then a Guice (or Spring) extension would simply register a Guice-aware (or
Spring-aware) FinderCreator with the Engine.


2) Add Engine-level configurability of the way Finder itself creates
resource instances.

To implement this approach, change the 3 argument Finder.create to check for
a ServerResourceCreator registered with the Engine:

public interface ServerResourceCreator {
<T> T create(Class<? extends ServerResource> targetClass);
}

If such a thing is registered, use it instead of targetClass.newInstance.
(Alternatively, ensure that a default ServerResourceCreator is registered
with the Engine and prevent registration of a null ServerResourceCreator.
This default creator would just use targetClass.newInstance.)

Then a Guice (or Spring) extension would register a Guice-aware (or
Spring-aware) ServerResourceCreator with the Engine.


The second approach involves less code change, but it also means that every
resource construction has to do an Engine lookup, which seems awkward. The
first approach gets all Engine-related stuff out of the way at startup time,
but means a little more code change.

What do you think?

-----

--tim
Post by Tim Peierls
Most recent trunk has defensive code in Finder that looks like it was left
public static Finder createFinder(
Class<? extends ServerResource> targetClass,
Class<? extends Finder> finderClass, Context context, Logger
logger) {
Finder result = null;
*if (ServerResource.class.isAssignableFrom(targetClass)) {*
...
} else {
// Log with this warning: "Cannot create a Finder for the given
target class, since
// it is neither a subclass of Resource nor a subclass of
ServerResource."
}
return result;
}
That isAssignableFrom check should always be true now. If it isn't,
someone's trying to subvert the type system. You could either leave out the
check, turn it into an assertion, or at least log it with more severity than
a warning.
--tim
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699138
Thierry Boileau
2011-01-20 17:45:47 UTC
Permalink
Hello Tim,

regarding the nit (is that word pejorative?), I'm not sure to fully understand it, because of my level of english. I notice, in the source code, that the deprecated method "setClientRoute" mentions already the "setOutbound" one. Is that your suggestion?

Regarding your excellent proposal, I've entered an RFE (http://restlet.tigris.org/issues/show_bug.cgi?id=1230).

Best regards,
Thierry Boileau

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699404
Tim Peierls
2011-01-20 17:58:05 UTC
Permalink
On Thu, Jan 20, 2011 at 12:45 PM, Thierry Boileau <
Post by Thierry Boileau
regarding the nit (is that word pejorative?), I'm not sure to fully
understand it, because of my level of english.
Diminutive, not pejorative. Comes from "nit-picking":
http://en.wikipedia.org/wiki/Nitpicking

I was trying to imply that this was a _very_ minor issue.
Post by Thierry Boileau
I notice, in the source code, that the deprecated method "setClientRoute"
mentions already the "setOutbound" one. Is that your suggestion?
Application.setOutboundRoot(Class<? extends ServerResource>) calls
deprecated setClientRoot, when it could call setOutboundRoot(Restlet)
directly (and setClientRoot could call setOutboundRoot(Class<? extends
ServerResource>)).
Post by Thierry Boileau
Regarding your excellent proposal, I've entered an RFE (
http://restlet.tigris.org/issues/show_bug.cgi?id=1230).
Thanks!

--tim

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699406
Jerome Louvel
2011-01-21 07:48:06 UTC
Permalink
Hi Tim,



This is a great analysis indeed of both the situation and the goal to achieve: using a DI framework shouldn’t change the way resource classes are attached to Restlet routing chain.



My main remark is that using Guice or Spring or the default mechanism or something else shouldn’t be an engine wide choice. Each application contained in a component should be able to use a different mechanism. It should also be possible to use DI to configure the component itself.



For discussion purpose, we could have:



component 1 : Guice DI

+-- application A : Spring DI

+-- application B : Default behavior

+-- 




I’m wondering if the Context shouldn’t be the place to implement one of the solutions you evoked.



BTW, I’ve fixed the setClientRoot/setOutboundRoot implementation as suggested in SVN trunk.



Best regards,
Jerome
--
Restlet ~ Founder and Technical Lead ~ <http://www.restlet.org/> http://www.restlet.o​rg
Noelios Technologies ~ <http://www.noelios.com/> http://www.noelios.com









De : tpeierls-***@public.gmane.org [mailto:tpeierls-***@public.gmane.org] De la part de Tim Peierls
Envoyé : jeudi 20 janvier 2011 18:58
À : code-s0N/mLB9wL+***@public.gmane.org
Objet : Re: Re: Unnecessary type check?



On Thu, Jan 20, 2011 at 12:45 PM, Thierry Boileau <***@noelios.com> wrote:

regarding the nit (is that word pejorative?), I'm not sure to fully understand it, because of my level of english.



Diminutive, not pejorative. Comes from "nit-picking": http://en.wikipedia.org/wiki/Nitpicking



I was trying to imply that this was a _very_ minor issue.





I notice, in the source code, that the deprecated method "setClientRoute" mentions already the "setOutbound" one. Is that your suggestion?



Application.setOutboundRoot(Class<? extends ServerResource>) calls deprecated setClientRoot, when it could call setOutboundRoot(Restlet) directly (and setClientRoot could call setOutboundRoot(Class<? extends ServerResource>)).





Regarding your excellent proposal, I've entered an RFE (http://restlet.tigris.org/issues/show_bug.cgi?id=1230).



Thanks!



--tim

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699534
Tim Peierls
2011-01-21 17:22:40 UTC
Permalink
Post by Jerome Louvel
My main remark is that using Guice or Spring or the default mechanism or
something else shouldn’t be an engine wide choice. Each application
contained in a component should be able to use a different mechanism. It
should also be possible to use DI to configure the component itself.
component 1 : Guice DI
+-- application A : Spring DI
+-- application B : Default behavior
+-- 

Remember that DI is *not* analogous to the concept of "service". It's a
global aspect, much like the choice of Engine. You should never have to say
things like "that's a Spring app" or "that's a Guice app". That's the
motivation for JSR 330: It lets you specify injection points in a standard
way without committing to a particular DI framework. In your example, the
application A author might have developed the application using Spring, but
by expressing dependencies entirely with JSR 330 annotations, the
application can be used without change in a Guice environment.

Of course if there are internal dependencies that rely on framework-specific
bindings they can be encapsulated in one place and exposed in a way that
users can invoke from other DI frameworks. For example, Guice can import
bindings from Spring through the SpringIntegration class:

http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/spring/SpringIntegration.html

There's probably something similar to adapt a Guice injector as a Spring
bean factory.
Post by Jerome Louvel
I’m wondering if the Context shouldn’t be the place to implement one of the
solutions you evoked.
The trouble is that context can be overridden down the Restlet tree, and
that could end up unintentionally orphaning a whole subtree from the global
DI.

But there might be cases where an Application writer would want to be able
to override the use of global DI, and Context could be used there. For
example (assuming approach #1 of my earlier e-mail), if you added a
finderCreator property to Context, defaulting to null, the logic in
Finder.createFinder could be as follows:

1. Check to see if the given finderClass is non-null (and not ==
Finder.class). If so, use it.
2. Check to see if the given context has a non-null finderCreator
property. If so, use it.
3. Check to see if the Engine has a registered finderCreator. If so, use
it.
4. Otherwise, use new Finder(...).

In reverse order, going from the general to the specific:

Case 4 is when no one has done anything special; it's what we have today.
Applications written to use DI won't work in this case.

Case 3 is when the component or embedding environment wants to support
applications that require DI (using JSR 330 annotations). The engine is
told, in effect: The system is using such-and-such Spring application
context (or such-and-such Guice injector).

Case 2 is for an application that explicitly disclaims an interest in the
global DI and wants to handle things separately, possibly by using its own
private DI mechanism throughout the application.

And case 1 is for overriding finder creation for a Router (or Application)
instance without affecting finder creation for other Restlets within the
same Application.

--tim

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699678
Tal Liron
2011-01-21 19:03:09 UTC
Permalink
Echoing Jerome's question about the Context --


A very common use case for me is to inject data right from the Context.
In fact, it was Tim who, more than a year ago, promised me that it was
the "Restlet way" to initialize resource instances. I guess this was
before he started making babies with Guice. ;)


So, I'm wondering if Restlet could provide a standard mechanism for
injection from the Context, without reliance on external DI tools, and
with no integration beyond the "inelegant" extensions as they exist now.


Example:


package org.happy;


class CustomerResource extends ServerResource {

@InjectFromContext

public CustomerResource(CustomerProcessor processor, LogManager log) {

...

}

}


Where the Context attributes will be expected to be named
"org.happy.CustomerResource.processor" and
"org.happy.CustomerResource.log" and to be in the types specified.


That's "DI lite", but very much in tune with the "Restlet way."


-Tal
On Fri, Jan 21, 2011 at 2:48 AM, Jerome Louvel
My main remark is that using Guice or Spring or the default
mechanism or something else shouldn’t be an engine wide choice.
Each application contained in a component should be able to use a
different mechanism. It should also be possible to use DI to
configure the component itself.
component 1 : Guice DI
+-- application A : Spring DI
+-- application B : Default behavior
+-- …
Remember that DI is *not* analogous to the concept of "service". It's
a global aspect, much like the choice of Engine. You should never have
to say things like "that's a Spring app" or "that's a Guice
app". That's the motivation for JSR 330: It lets you specify injection
points in a standard way without committing to a particular DI
framework. In your example, the application A author might have
developed the application using Spring, but by expressing dependencies
entirely with JSR 330 annotations, the application can be used without
change in a Guice environment.
Of course if there are internal dependencies that rely on
framework-specific bindings they can be encapsulated in one place and
exposed in a way that users can invoke from other DI frameworks. For
example, Guice can import bindings from Spring through the
http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/spring/SpringIntegration.html
There's probably something similar to adapt a Guice injector as a
Spring bean factory.
I’m wondering if the Context shouldn’t be the place to implement
one of the solutions you evoked.
The trouble is that context can be overridden down the Restlet tree,
and that could end up unintentionally orphaning a whole subtree from
the global DI.
But there might be cases where an Application writer would want to be
able to override the use of global DI, and Context could be used
there. For example (assuming approach #1 of my earlier e-mail), if you
added a finderCreator property to Context, defaulting to null, the
1. Check to see if the given finderClass is non-null (and not ==
Finder.class). If so, use it.
2. Check to see if the given context has a non-null finderCreator
property. If so, use it.
3. Check to see if the Engine has a registered finderCreator. If
so, use it.
4. Otherwise, use new Finder(...).
Case 4 is when no one has done anything special; it's what we have
today. Applications written to use DI won't work in this case.
Case 3 is when the component or embedding environment wants to support
applications that require DI (using JSR 330 annotations). The engine
is told, in effect: The system is using such-and-such Spring
application context (or such-and-such Guice injector).
Case 2 is for an application that explicitly disclaims an interest in
the global DI and wants to handle things separately, possibly by using
its own private DI mechanism throughout the application.
And case 1 is for overriding finder creation for a Router (or
Application) instance without affecting finder creation for other
Restlets within the same Application.
--tim
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699698
Tim Peierls
2011-01-21 23:10:02 UTC
Permalink
Tal,

How about this?

public class DillFinder extends Finder {
public DillFinder(Context context, Class<? extends ServerResource>
targetClass) {
super(context, targetClass);
}

@Override public ServerResource create(
Class<? extends ServerResource> targetClass,
Request request,
Response response)
{
for (Constructor ctor : targetClass.getConstructors()) {
if (ctor.getAnnotation(Inject.class) != null) {
@SuppressWarnings("unchecked")
Constructor<? extends ServerResource> c =
(Constructor<? extends ServerResource>) ctor;
return create(c);
}
}

// No constructor with Inject found, use default.
return super.create(targetClass, request, response);
}

private ServerResource create(Constructor<? extends ServerResource>
ctor) {
try {
Map<String, Object> attrs = getContext().getAttributes();
Class<?>[] paramTypes = ctor.getParameterTypes();
Object[] params = new Object[paramTypes.length];
for (int i = 0; i < paramTypes.length; ++i) {
Class<?> paramType = paramTypes[i];
String paramTypeName = paramType.getName();
Object paramValue = attrs.get(paramTypeName);
if (paramType.isInstance(paramValue)) {
params[i] = paramValue;
}
}
return ctor.newInstance(params);
} catch (InstantiationException ex) {
throw new ResourceException(ex);
} catch (IllegalAccessException ex) {
throw new ResourceException(ex);
} catch (InvocationTargetException ex) {
throw new ResourceException(ex);
}
}
}

Dill is an acronym: *D*epencency *I*njection *L*ite al *L*iron. :-)

But Guice is <700K, so if you don't mind adding that jar and you're willing
to try the incubator's Guice extension, you can get this behavior without
the limits of DillFinder (and it is pretty limited) and without having to
buy any further into full-fledged DI. It would look like this in your
application's createInboundRoot:

FinderFactory finderFactory = new RestletGuice.Module() {
@Provides CustomerProcessor provideCustomerProcessor(Context context)
{
return (CustomerProcessor) context.getAttributes()
.get("org.happy.CustomerResource.processor");
}
@Provides LogManager provideLogManager(Context context) {
return (LogManager) context.getAttributes()
.get("org.happy.CustomerResource.log");
}
}

Your customer resource's constructor would be annotated with @Inject. For
the moment, you can use the Guice extension in its current incubator state
when routing to the resource:

router.attach("/customer/{id}/",
finderFactory.finder(CustomerResource.class));

where finderFactory would need to be passed in somehow. If the enhancements
I've proposed (including the improvement suggested by Jerome) are
implemented, you'd be able to say:

router.attach("/customer/{id}/", CustomerResource.class);

--tim
Post by Tal Liron
Echoing Jerome's question about the Context --
A very common use case for me is to inject data right from the Context.
In fact, it was Tim who, more than a year ago, promised me that it was
the "Restlet way" to initialize resource instances. I guess this was
before he started making babies with Guice. ;)
So, I'm wondering if Restlet could provide a standard mechanism for
injection from the Context, without reliance on external DI tools, and
with no integration beyond the "inelegant" extensions as they exist now.
package org.happy;
class CustomerResource extends ServerResource {
@InjectFromContext
public CustomerResource(CustomerProcessor processor, LogManager log) {
...
}
}
Where the Context attributes will be expected to be named
"org.happy.CustomerResource.processor" and
"org.happy.CustomerResource.log" and to be in the types specified.
That's "DI lite", but very much in tune with the "Restlet way."
-Tal
On Fri, Jan 21, 2011 at 2:48 AM, Jerome Louvel
My main remark is that using Guice or Spring or the default
mechanism or something else shouldn’t be an engine wide choice.
Each application contained in a component should be able to use a
different mechanism. It should also be possible to use DI to
configure the component itself.
component 1 : Guice DI
+-- application A : Spring DI
+-- application B : Default behavior
+-- 

Remember that DI is *not* analogous to the concept of "service". It's
a global aspect, much like the choice of Engine. You should never have
to say things like "that's a Spring app" or "that's a Guice
app". That's the motivation for JSR 330: It lets you specify injection
points in a standard way without committing to a particular DI
framework. In your example, the application A author might have
developed the application using Spring, but by expressing dependencies
entirely with JSR 330 annotations, the application can be used without
change in a Guice environment.
Of course if there are internal dependencies that rely on
framework-specific bindings they can be encapsulated in one place and
exposed in a way that users can invoke from other DI frameworks. For
example, Guice can import bindings from Spring through the
http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/spring/SpringIntegration.html
There's probably something similar to adapt a Guice injector as a
Spring bean factory.
I’m wondering if the Context shouldn’t be the place to implement
one of the solutions you evoked.
The trouble is that context can be overridden down the Restlet tree,
and that could end up unintentionally orphaning a whole subtree from
the global DI.
But there might be cases where an Application writer would want to be
able to override the use of global DI, and Context could be used
there. For example (assuming approach #1 of my earlier e-mail), if you
added a finderCreator property to Context, defaulting to null, the
1. Check to see if the given finderClass is non-null (and not ==
Finder.class). If so, use it.
2. Check to see if the given context has a non-null finderCreator
property. If so, use it.
3. Check to see if the Engine has a registered finderCreator. If
so, use it.
4. Otherwise, use new Finder(...).
Case 4 is when no one has done anything special; it's what we have
today. Applications written to use DI won't work in this case.
Case 3 is when the component or embedding environment wants to support
applications that require DI (using JSR 330 annotations). The engine
is told, in effect: The system is using such-and-such Spring
application context (or such-and-such Guice injector).
Case 2 is for an application that explicitly disclaims an interest in
the global DI and wants to handle things separately, possibly by using
its own private DI mechanism throughout the application.
And case 1 is for overriding finder creation for a Router (or
Application) instance without affecting finder creation for other
Restlets within the same Application.
--tim
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699698
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699727
Tal Liron
2011-01-21 23:39:31 UTC
Permalink
Dill is not my favorite herb, but it does add some flavor. :)


Your implementation of DillFinder is fine! What I was trying to suggest
is to merge such code or something very similar into Restlet's core
Finder and perhaps solve 90% of people's DI needs when it comes to
ServerResource. And it's such lighweight and little code, isn't it?


I know 700k isn't enormous, but it's always the struggle between the
desire to keep things minimal and to add dependencies. It's not just
700k: it's adhering to the library's patterns and integrating them into
your library's culture, it's keeping up with progress there, etc. The
cost of dependency is uncertainty and headaches and lock-ins. Jerome's
decision to keep support for all these dependencies as extensions is
important. I know that for you and many others Guice is worth all those
costs, but I would be upset if using Restlet would *practically* require
some kind of external DI library for it to run properly.


Sigh. I guess even more than having DillFinder-like functionality, I
would appreciate an alternative to the Finder/ServerResource system
entirely. I know that the idea of "one ServerResource instance per
request" has certain advantages in terms of ease of handling state, and
also in terms of performance, but it's always been a headache in terms
of initialization. And it's difficult to program -- a kick in the head
for how most of us understand OOP and its relationship to Java. When it
comes down to it, you still have to do the hard concurrency programming
to handle shared state between resources (which is part of what
"initialization" via the Context does). So, I wonder how much we've
really made things easier.


In my opinion, it would be most comfortable if there were a
ResourceRestlet class inheriting from Restlet, such that you would be
able to do things like this:


router.attach("/customer/{id}/", new MyResource(arg1, arg2));


You would have to make sure that MyResource is thread-safe, of course,
but it would much more sense to most programmers, and also flow better
with the rest of the Restlet API. No need for DI (unless you want it, of
course), and definitely no need to integrate DI into the framework. I'm
sure this approach has been tried and abandoned in Restlet's history.
Perhaps it's worth trying again, now that Restlet is mature and we have
so many concurrency gurus onboard?


Argh. I want to rewrite Restlet in Clojure so we can do away with all
these painful concurrency tradeoffs. Maybe that will be my project for
next year. Who wants to help? Hmm, now where would be a good place to
find experts on JVM concurrency... ;)


-Tal
Post by Tim Peierls
Tal,
How about this?
public class DillFinder extends Finder {
public DillFinder(Context context, Class<? extends ServerResource>
targetClass) {
super(context, targetClass);
}
@Override public ServerResource create(
Class<? extends ServerResource> targetClass,
Request request,
Response response)
{
for (Constructor ctor : targetClass.getConstructors()) {
if (ctor.getAnnotation(Inject.class) != null) {
@SuppressWarnings("unchecked")
Constructor<? extends ServerResource> c =
(Constructor<? extends ServerResource>) ctor;
return create(c);
}
}
// No constructor with Inject found, use default.
return super.create(targetClass, request, response);
}
private ServerResource create(Constructor<? extends
ServerResource> ctor) {
try {
Map<String, Object> attrs = getContext().getAttributes();
Class<?>[] paramTypes = ctor.getParameterTypes();
Object[] params = new Object[paramTypes.length];
for (int i = 0; i < paramTypes.length; ++i) {
Class<?> paramType = paramTypes[i];
String paramTypeName = paramType.getName();
Object paramValue = attrs.get(paramTypeName);
if (paramType.isInstance(paramValue)) {
params[i] = paramValue;
}
}
return ctor.newInstance(params);
} catch (InstantiationException ex) {
throw new ResourceException(ex);
} catch (IllegalAccessException ex) {
throw new ResourceException(ex);
} catch (InvocationTargetException ex) {
throw new ResourceException(ex);
}
}
}
Dill is an acronym: *D*epencency *I*njection *L*ite al *L*iron. :-)
But Guice is <700K, so if you don't mind adding that jar and you're
willing to try the incubator's Guice extension, you can get this
behavior without the limits of DillFinder (and it is pretty limited)
and without having to buy any further into full-fledged DI. It would
FinderFactory finderFactory = new RestletGuice.Module() {
@Provides CustomerProcessor provideCustomerProcessor(Context
context) {
return (CustomerProcessor) context.getAttributes()
.get("org.happy.CustomerResource.processor");
}
@Provides LogManager provideLogManager(Context context) {
return (LogManager) context.getAttributes()
.get("org.happy.CustomerResource.log");
}
}
For the moment, you can use the Guice extension in its current
router.attach("/customer/{id}/",
finderFactory.finder(CustomerResource.class));
where finderFactory would need to be passed in somehow. If the
enhancements I've proposed (including the improvement suggested by
router.attach("/customer/{id}/", CustomerResource.class);
--tim
On Fri, Jan 21, 2011 at 2:03 PM, Tal Liron
Echoing Jerome's question about the Context --
A very common use case for me is to inject data right from the Context.
In fact, it was Tim who, more than a year ago, promised me that it was
the "Restlet way" to initialize resource instances. I guess this was
before he started making babies with Guice. ;)
So, I'm wondering if Restlet could provide a standard mechanism for
injection from the Context, without reliance on external DI tools, and
with no integration beyond the "inelegant" extensions as they exist now.
package org.happy;
class CustomerResource extends ServerResource {
@InjectFromContext
public CustomerResource(CustomerProcessor processor, LogManager log) {
...
}
}
Where the Context attributes will be expected to be named
"org.happy.CustomerResource.processor" and
"org.happy.CustomerResource.log" and to be in the types specified.
That's "DI lite", but very much in tune with the "Restlet way."
-Tal
On Fri, Jan 21, 2011 at 2:48 AM, Jerome Louvel
My main remark is that using Guice or Spring or the default
mechanism or something else shouldn’t be an engine wide choice.
Each application contained in a component should be able to
use a
different mechanism. It should also be possible to use DI to
configure the component itself.
component 1 : Guice DI
+-- application A : Spring DI
+-- application B : Default behavior
+-- …
Remember that DI is *not* analogous to the concept of "service".
It's
a global aspect, much like the choice of Engine. You should
never have
to say things like "that's a Spring app" or "that's a Guice
app". That's the motivation for JSR 330: It lets you specify
injection
points in a standard way without committing to a particular DI
framework. In your example, the application A author might have
developed the application using Spring, but by expressing
dependencies
entirely with JSR 330 annotations, the application can be used
without
change in a Guice environment.
Of course if there are internal dependencies that rely on
framework-specific bindings they can be encapsulated in one
place and
exposed in a way that users can invoke from other DI frameworks. For
example, Guice can import bindings from Spring through the
http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/spring/SpringIntegration.html
There's probably something similar to adapt a Guice injector as a
Spring bean factory.
I’m wondering if the Context shouldn’t be the place to implement
one of the solutions you evoked.
The trouble is that context can be overridden down the Restlet tree,
and that could end up unintentionally orphaning a whole subtree from
the global DI.
But there might be cases where an Application writer would want
to be
able to override the use of global DI, and Context could be used
there. For example (assuming approach #1 of my earlier e-mail),
if you
added a finderCreator property to Context, defaulting to null, the
1. Check to see if the given finderClass is non-null (and not ==
Finder.class). If so, use it.
2. Check to see if the given context has a non-null finderCreator
property. If so, use it.
3. Check to see if the Engine has a registered finderCreator. If
so, use it.
4. Otherwise, use new Finder(...).
Case 4 is when no one has done anything special; it's what we have
today. Applications written to use DI won't work in this case.
Case 3 is when the component or embedding environment wants to
support
applications that require DI (using JSR 330 annotations). The engine
is told, in effect: The system is using such-and-such Spring
application context (or such-and-such Guice injector).
Case 2 is for an application that explicitly disclaims an
interest in
the global DI and wants to handle things separately, possibly by
using
its own private DI mechanism throughout the application.
And case 1 is for overriding finder creation for a Router (or
Application) instance without affecting finder creation for other
Restlets within the same Application.
--tim
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699698
<http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699698>
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699729
Tim Peierls
2011-01-22 16:58:55 UTC
Permalink
No one wants to see the Restlet core take on too much. Trouble with
DillFinder, light as it is, is that it falls short of implementing the
official standard, JSR 330. That might not bother you, but it would
complicate the story: "You can use built-in DI lite, which has the following
idiosyncrasies, or you can use full JSR 330 without the idiosyncrasies but
with an extension jar." What's more, the next person is going to ask for
Provider support in the core, and recursive injection of objects, and scope,
and ... By the time you've added all that in to Restlet, you've got what
amounts to small DI framework that is now too big to fit comfortably in core
Restlet. I don't see clear criteria for drawing the line anywhere but the
extremes, which is why I proposed that the core have only enough
configurability to *support *JSR-330-compliant extensions, without trying to
do any DI, even poor man's DI, on its own.

Hmm, just noticed a simple framework for injection that claims to be
JSR-330-compliant and is an order of magnitude smaller than Guice:

http://code.google.com/p/java-simple-utils/wiki/Injection

Is 70K within the threshold of acceptability?

Regarding the use of the factory pattern for resources: I can't speak for
Noelios, but I imagine the original motivation was not so much to reduce
concurrency issues, but to accurately reflect the distinction between
stateful/OOP/Restlet to stateless/ROP/resource. I think it was a brilliant
design choice. It forced me to confront the fact that resource != object and
that resource is more closely analogous to class. The only thing missing was
a way to let my resources participate in DI, and now I have that, too --
although I'm hoping it can be made a bit prettier and more consistent.

It's true that the factory pattern doesn't solve the problem of sharing data
safely between resource handlers, but at least it clarifies where the
problem is. The resource instance is ephemeral so you *must* get all your
state from somewhere else. If it wasn't, it would be all too tempting to try
to associate state with the resource, and before you know it, whoops, you've
essentially got servlets and sessions.

And I know you weren't being entirely serious about Clojure, but I don't
think we need to look for help from other languages. Clojure / functional
programming doesn't eliminate concurrency issues any more than garbage
collection eliminates memory leaks. There are plenty of great tools in Java
to help manage the concurrency burden. Guava MapMaker is a terrific example.
(Incidentally, I recently
ranted<http://groups.google.com/group/guava-discuss/browse_thread/thread/278dd6a99214d91a/92f14996f69b179d?hl=en\f14996f69b179d#>about
the fallacy of FP solving all concurrency problems on the Guava
discussion list.)

--tim
Post by Tal Liron
Dill is not my favorite herb, but it does add some flavor. :)
Your implementation of DillFinder is fine! What I was trying to suggest
is to merge such code or something very similar into Restlet's core
Finder and perhaps solve 90% of people's DI needs when it comes to
ServerResource. And it's such lighweight and little code, isn't it?
I know 700k isn't enormous, but it's always the struggle between the
desire to keep things minimal and to add dependencies. It's not just
700k: it's adhering to the library's patterns and integrating them into
your library's culture, it's keeping up with progress there, etc. The
cost of dependency is uncertainty and headaches and lock-ins. Jerome's
decision to keep support for all these dependencies as extensions is
important. I know that for you and many others Guice is worth all those
costs, but I would be upset if using Restlet would *practically* require
some kind of external DI library for it to run properly.
Sigh. I guess even more than having DillFinder-like functionality, I
would appreciate an alternative to the Finder/ServerResource system
entirely. I know that the idea of "one ServerResource instance per
request" has certain advantages in terms of ease of handling state, and
also in terms of performance, but it's always been a headache in terms
of initialization. And it's difficult to program -- a kick in the head
for how most of us understand OOP and its relationship to Java. When it
comes down to it, you still have to do the hard concurrency programming
to handle shared state between resources (which is part of what
"initialization" via the Context does). So, I wonder how much we've
really made things easier.
In my opinion, it would be most comfortable if there were a
ResourceRestlet class inheriting from Restlet, such that you would be
router.attach("/customer/{id}/", new MyResource(arg1, arg2));
You would have to make sure that MyResource is thread-safe, of course,
but it would much more sense to most programmers, and also flow better
with the rest of the Restlet API. No need for DI (unless you want it, of
course), and definitely no need to integrate DI into the framework. I'm
sure this approach has been tried and abandoned in Restlet's history.
Perhaps it's worth trying again, now that Restlet is mature and we have
so many concurrency gurus onboard?
Argh. I want to rewrite Restlet in Clojure so we can do away with all
these painful concurrency tradeoffs. Maybe that will be my project for
next year. Who wants to help? Hmm, now where would be a good place to
find experts on JVM concurrency... ;)
-Tal
Post by Tim Peierls
Tal,
How about this?
public class DillFinder extends Finder {
public DillFinder(Context context, Class<? extends ServerResource>
targetClass) {
super(context, targetClass);
}
@Override public ServerResource create(
Class<? extends ServerResource> targetClass,
Request request,
Response response)
{
for (Constructor ctor : targetClass.getConstructors()) {
if (ctor.getAnnotation(Inject.class) != null) {
@SuppressWarnings("unchecked")
Constructor<? extends ServerResource> c =
(Constructor<? extends ServerResource>) ctor;
return create(c);
}
}
// No constructor with Inject found, use default.
return super.create(targetClass, request, response);
}
private ServerResource create(Constructor<? extends
ServerResource> ctor) {
try {
Map<String, Object> attrs = getContext().getAttributes();
Class<?>[] paramTypes = ctor.getParameterTypes();
Object[] params = new Object[paramTypes.length];
for (int i = 0; i < paramTypes.length; ++i) {
Class<?> paramType = paramTypes[i];
String paramTypeName = paramType.getName();
Object paramValue = attrs.get(paramTypeName);
if (paramType.isInstance(paramValue)) {
params[i] = paramValue;
}
}
return ctor.newInstance(params);
} catch (InstantiationException ex) {
throw new ResourceException(ex);
} catch (IllegalAccessException ex) {
throw new ResourceException(ex);
} catch (InvocationTargetException ex) {
throw new ResourceException(ex);
}
}
}
Dill is an acronym: *D*epencency *I*njection *L*ite al *L*iron. :-)
But Guice is <700K, so if you don't mind adding that jar and you're
willing to try the incubator's Guice extension, you can get this
behavior without the limits of DillFinder (and it is pretty limited)
and without having to buy any further into full-fledged DI. It would
FinderFactory finderFactory = new RestletGuice.Module() {
@Provides CustomerProcessor provideCustomerProcessor(Context
context) {
return (CustomerProcessor) context.getAttributes()
.get("org.happy.CustomerResource.processor");
}
@Provides LogManager provideLogManager(Context context) {
return (LogManager) context.getAttributes()
.get("org.happy.CustomerResource.log");
}
}
For the moment, you can use the Guice extension in its current
router.attach("/customer/{id}/",
finderFactory.finder(CustomerResource.class));
where finderFactory would need to be passed in somehow. If the
enhancements I've proposed (including the improvement suggested by
router.attach("/customer/{id}/", CustomerResource.class);
--tim
On Fri, Jan 21, 2011 at 2:03 PM, Tal Liron
Echoing Jerome's question about the Context --
A very common use case for me is to inject data right from the Context.
In fact, it was Tim who, more than a year ago, promised me that it
was
Post by Tim Peierls
the "Restlet way" to initialize resource instances. I guess this was
before he started making babies with Guice. ;)
So, I'm wondering if Restlet could provide a standard mechanism for
injection from the Context, without reliance on external DI tools,
and
Post by Tim Peierls
with no integration beyond the "inelegant" extensions as they exist now.
package org.happy;
class CustomerResource extends ServerResource {
@InjectFromContext
public CustomerResource(CustomerProcessor processor, LogManager log) {
...
}
}
Where the Context attributes will be expected to be named
"org.happy.CustomerResource.processor" and
"org.happy.CustomerResource.log" and to be in the types specified.
That's "DI lite", but very much in tune with the "Restlet way."
-Tal
On Fri, Jan 21, 2011 at 2:48 AM, Jerome Louvel
My main remark is that using Guice or Spring or the default
mechanism or something else shouldn’t be an engine wide choice.
Each application contained in a component should be able to
use a
different mechanism. It should also be possible to use DI to
configure the component itself.
component 1 : Guice DI
+-- application A : Spring DI
+-- application B : Default behavior
+-- 

Remember that DI is *not* analogous to the concept of "service".
It's
a global aspect, much like the choice of Engine. You should
never have
to say things like "that's a Spring app" or "that's a Guice
app". That's the motivation for JSR 330: It lets you specify
injection
points in a standard way without committing to a particular DI
framework. In your example, the application A author might have
developed the application using Spring, but by expressing
dependencies
entirely with JSR 330 annotations, the application can be used
without
change in a Guice environment.
Of course if there are internal dependencies that rely on
framework-specific bindings they can be encapsulated in one
place and
exposed in a way that users can invoke from other DI frameworks.
For
Post by Tim Peierls
example, Guice can import bindings from Spring through the
http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/spring/SpringIntegration.html
Post by Tim Peierls
There's probably something similar to adapt a Guice injector as a
Spring bean factory.
I’m wondering if the Context shouldn’t be the place to
implement
Post by Tim Peierls
one of the solutions you evoked.
The trouble is that context can be overridden down the Restlet
tree,
Post by Tim Peierls
and that could end up unintentionally orphaning a whole subtree
from
Post by Tim Peierls
the global DI.
But there might be cases where an Application writer would want
to be
able to override the use of global DI, and Context could be used
there. For example (assuming approach #1 of my earlier e-mail),
if you
added a finderCreator property to Context, defaulting to null, the
1. Check to see if the given finderClass is non-null (and not ==
Finder.class). If so, use it.
2. Check to see if the given context has a non-null
finderCreator
Post by Tim Peierls
property. If so, use it.
3. Check to see if the Engine has a registered finderCreator. If
so, use it.
4. Otherwise, use new Finder(...).
Case 4 is when no one has done anything special; it's what we have
today. Applications written to use DI won't work in this case.
Case 3 is when the component or embedding environment wants to
support
applications that require DI (using JSR 330 annotations). The
engine
Post by Tim Peierls
is told, in effect: The system is using such-and-such Spring
application context (or such-and-such Guice injector).
Case 2 is for an application that explicitly disclaims an
interest in
the global DI and wants to handle things separately, possibly by
using
its own private DI mechanism throughout the application.
And case 1 is for overriding finder creation for a Router (or
Application) instance without affecting finder creation for other
Restlets within the same Application.
--tim
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699698
Post by Tim Peierls
<
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699698
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699729
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699830
Tal Liron
2011-01-22 19:35:00 UTC
Permalink
I see your point about DillFinder potentially growing too big, but
actually the code you wrote was pretty much good enough for me. If I
have to manually inject the Context with what I need, so be it. I have
no expectation for Restlet helping me with that.


Restlet has numerous curious architectural pattern decisions: the
factory pattern for resources, and the lack of interfaces, that may have
the advantage of encouraging certain programming styles. To me, this has
always felt like a mistake: encouragement is not enforcement, definitely
not at a code level. It ends up feeling heavy handed, rather than free.
In its place, I would hope for more real-world examples showing how to
manage complex state in Restlet. These would create best practices,
rather than a awkward API (which I consider the Finder to be).


Moreover -- I think you're overstating (pun!) the state issue. I do not
think it's correct to talk about a resource being "stateless" (in any
case, encapsulation is just one of three OO principles, such that a
Resource with state is still not quite an "object"). Remember that
Fielding's dissertation called the chapter Representaional State
Transfer, and not "a resource-oriented architecture". Look at the name:
it's not "representations of state," but "representational state." It's
definitely state. The point that Fielding tried to emphasize in many
different ways was that the web was exactly *not* uselessly stateless,
as so many programmers thought, but that in fact it is exactly stateful
in a specific matter that is useful. In other words, the web is *an*
application -- instead of building applications "on top" of it, we
should be treating it as the application layer itself, and work within
its state semantics, which he then elaborated.


The qualifier -- "representational" state -- as opposed to, say,
"actual" state, means that the expectations of human and other users of
the web-as-an-application is that they access (see, alter) the state
subjectively, within terms and conditions true to capabilities,
location, time, etc., of the moment. Thus a browser loads a page -- and
all web users know they can refresh the page and possibly see a new
representation of the application's state. Or not: caching of
representation becomes possible (a crucial REST concept not yet handled
by Restlet) as does massive scalability. Point is that this expectation
allows for representations to be manipulated along the way (the
"transfer") as pure things-in-themselves with no strings attached. (This
is somewhat analogous to the notion of pure functions in functional
programming.) In other words, it's not resources that are stateless, but
representations.


Your Restlet resources definitely have state, except that you might have
decided not to store them in ServerResource instances, and instead in an
application context. But that's your own architectural decision, albeit
one that is somewhat encouraged by Restlet right now. But I don't see
anything immediately wrong with storing state in a ServerResource, if
that's where it logically belongs. For example, it might store a
connection pool to a database it uses. If only one URI pattern uses that
pool, why have to put it elsewhere? This is actually a common design for
URI spaces. And if the same resource class is re-used for numerous URIs,
each instance can hold its own relevant state. That's good OOP
re-usability that has nothing to do with REST per se.


I'll have to disagree with your take on functional programming in the
Guava list, too. Clojure's transactional memory (via Refs) is an
innovative and simple way to share state without bringing "the whole
multiprocessor down." Persistent data structures can be used outside of
functional programming (indeed, Clojure's all implement the standard JVM
interfaces) but are so much more elegantly expressed (purely)
functionally. And that's the difference I was trying to point out
earlier: Clojure *does* enforce coding patterns at the code level, in a
way Restlet (as a Java library) never can -- Refs can only be used in a
transaction, otherwise an exception is thrown. Functional programming is
already the best practice for using persistent data structures.
Moreover, I see the mechanism of transactional memory fitting quite well
with the architectural notion of representational state. Per transaction
(user request) you can get a snapshot of very complex state.


In summary, I was quite serious about the potential of a Clojure rewrite
of Restlet. Not so serious about actually doing it, though...


-Tal
Post by Tim Peierls
No one wants to see the Restlet core take on too much. Trouble with
DillFinder, light as it is, is that it falls short of implementing the
official standard, JSR 330. That might not bother you, but it would
complicate the story: "You can use built-in DI lite, which has the
following idiosyncrasies, or you can use full JSR 330 without the
idiosyncrasies but with an extension jar." What's more, the next
person is going to ask for Provider support in the core, and recursive
injection of objects, and scope, and ... By the time you've added
all that in to Restlet, you've got what amounts to small DI framework
that is now too big to fit comfortably in core Restlet. I don't see
clear criteria for drawing the line anywhere but the extremes, which
is why I proposed that the core have only enough configurability to
*support *JSR-330-compliant extensions, without trying to do any DI,
even poor man's DI, on its own.
Hmm, just noticed a simple framework for injection that claims to be
http://code.google.com/p/java-simple-utils/wiki/Injection
Is 70K within the threshold of acceptability?
Regarding the use of the factory pattern for resources: I can't speak
for Noelios, but I imagine the original motivation was not so much to
reduce concurrency issues, but to accurately reflect the distinction
between stateful/OOP/Restlet to stateless/ROP/resource. I think it was
a brilliant design choice. It forced me to confront the fact that
resource != object and that resource is more closely analogous to
class. The only thing missing was a way to let my resources
participate in DI, and now I have that, too -- although I'm hoping it
can be made a bit prettier and more consistent.
It's true that the factory pattern doesn't solve the problem of
sharing data safely between resource handlers, but at least it
clarifies where the problem is. The resource instance is ephemeral so
you *must* get all your state from somewhere else. If it wasn't, it
would be all too tempting to try to associate state with the resource,
and before you know it, whoops, you've essentially got servlets and
sessions.
And I know you weren't being entirely serious about Clojure, but I
don't think we need to look for help from other languages. Clojure /
functional programming doesn't eliminate concurrency issues any more
than garbage collection eliminates memory leaks. There are plenty of
great tools in Java to help manage the concurrency burden. Guava
MapMaker is a terrific example. (Incidentally, I recently ranted
<http://groups.google.com/group/guava-discuss/browse_thread/thread/278dd6a99214d91a/92f14996f69b179d?hl=en%5Cf14996f69b179d#>
about the fallacy of FP solving all concurrency problems on the Guava
discussion list.)
--tim
On Fri, Jan 21, 2011 at 6:39 PM, Tal Liron
Dill is not my favorite herb, but it does add some flavor. :)
Your implementation of DillFinder is fine! What I was trying to suggest
is to merge such code or something very similar into Restlet's core
Finder and perhaps solve 90% of people's DI needs when it comes to
ServerResource. And it's such lighweight and little code, isn't it?
I know 700k isn't enormous, but it's always the struggle between the
desire to keep things minimal and to add dependencies. It's not just
700k: it's adhering to the library's patterns and integrating them into
your library's culture, it's keeping up with progress there, etc. The
cost of dependency is uncertainty and headaches and lock-ins. Jerome's
decision to keep support for all these dependencies as extensions is
important. I know that for you and many others Guice is worth all those
costs, but I would be upset if using Restlet would *practically* require
some kind of external DI library for it to run properly.
Sigh. I guess even more than having DillFinder-like functionality, I
would appreciate an alternative to the Finder/ServerResource system
entirely. I know that the idea of "one ServerResource instance per
request" has certain advantages in terms of ease of handling state, and
also in terms of performance, but it's always been a headache in terms
of initialization. And it's difficult to program -- a kick in the head
for how most of us understand OOP and its relationship to Java. When it
comes down to it, you still have to do the hard concurrency programming
to handle shared state between resources (which is part of what
"initialization" via the Context does). So, I wonder how much we've
really made things easier.
In my opinion, it would be most comfortable if there were a
ResourceRestlet class inheriting from Restlet, such that you would be
router.attach("/customer/{id}/", new MyResource(arg1, arg2));
You would have to make sure that MyResource is thread-safe, of course,
but it would much more sense to most programmers, and also flow better
with the rest of the Restlet API. No need for DI (unless you want it, of
course), and definitely no need to integrate DI into the
framework. I'm
sure this approach has been tried and abandoned in Restlet's history.
Perhaps it's worth trying again, now that Restlet is mature and we have
so many concurrency gurus onboard?
Argh. I want to rewrite Restlet in Clojure so we can do away with all
these painful concurrency tradeoffs. Maybe that will be my project for
next year. Who wants to help? Hmm, now where would be a good place to
find experts on JVM concurrency... ;)
-Tal
Post by Tim Peierls
Tal,
How about this?
public class DillFinder extends Finder {
public DillFinder(Context context, Class<? extends
ServerResource>
Post by Tim Peierls
targetClass) {
super(context, targetClass);
}
@Override public ServerResource create(
Class<? extends ServerResource> targetClass,
Request request,
Response response)
{
for (Constructor ctor : targetClass.getConstructors()) {
if (ctor.getAnnotation(Inject.class) != null) {
@SuppressWarnings("unchecked")
Constructor<? extends ServerResource> c =
(Constructor<? extends ServerResource>) ctor;
return create(c);
}
}
// No constructor with Inject found, use default.
return super.create(targetClass, request, response);
}
private ServerResource create(Constructor<? extends
ServerResource> ctor) {
try {
Map<String, Object> attrs =
getContext().getAttributes();
Post by Tim Peierls
Class<?>[] paramTypes = ctor.getParameterTypes();
Object[] params = new Object[paramTypes.length];
for (int i = 0; i < paramTypes.length; ++i) {
Class<?> paramType = paramTypes[i];
String paramTypeName = paramType.getName();
Object paramValue = attrs.get(paramTypeName);
if (paramType.isInstance(paramValue)) {
params[i] = paramValue;
}
}
return ctor.newInstance(params);
} catch (InstantiationException ex) {
throw new ResourceException(ex);
} catch (IllegalAccessException ex) {
throw new ResourceException(ex);
} catch (InvocationTargetException ex) {
throw new ResourceException(ex);
}
}
}
Dill is an acronym: *D*epencency *I*njection *L*ite al *L*iron. :-)
But Guice is <700K, so if you don't mind adding that jar and you're
willing to try the incubator's Guice extension, you can get this
behavior without the limits of DillFinder (and it is pretty limited)
and without having to buy any further into full-fledged DI. It would
FinderFactory finderFactory = new RestletGuice.Module() {
@Provides CustomerProcessor provideCustomerProcessor(Context
context) {
return (CustomerProcessor) context.getAttributes()
.get("org.happy.CustomerResource.processor");
}
@Provides LogManager provideLogManager(Context context) {
return (LogManager) context.getAttributes()
.get("org.happy.CustomerResource.log");
}
}
Your customer resource's constructor would be annotated with
@Inject.
Post by Tim Peierls
For the moment, you can use the Guice extension in its current
router.attach("/customer/{id}/",
finderFactory.finder(CustomerResource.class));
where finderFactory would need to be passed in somehow. If the
enhancements I've proposed (including the improvement suggested by
router.attach("/customer/{id}/", CustomerResource.class);
--tim
On Fri, Jan 21, 2011 at 2:03 PM, Tal Liron
Echoing Jerome's question about the Context --
A very common use case for me is to inject data right from the Context.
In fact, it was Tim who, more than a year ago, promised me
that it was
Post by Tim Peierls
the "Restlet way" to initialize resource instances. I guess
this was
Post by Tim Peierls
before he started making babies with Guice. ;)
So, I'm wondering if Restlet could provide a standard
mechanism for
Post by Tim Peierls
injection from the Context, without reliance on external DI
tools, and
Post by Tim Peierls
with no integration beyond the "inelegant" extensions as they
exist now.
package org.happy;
class CustomerResource extends ServerResource {
@InjectFromContext
public CustomerResource(CustomerProcessor processor,
LogManager
Post by Tim Peierls
log) {
...
}
}
Where the Context attributes will be expected to be named
"org.happy.CustomerResource.processor" and
"org.happy.CustomerResource.log" and to be in the types
specified.
Post by Tim Peierls
That's "DI lite", but very much in tune with the "Restlet way."
-Tal
On Fri, Jan 21, 2011 at 2:48 AM, Jerome Louvel
My main remark is that using Guice or Spring or the default
mechanism or something else shouldn’t be an engine wide
choice.
Post by Tim Peierls
Each application contained in a component should be able to
use a
different mechanism. It should also be possible to use DI to
configure the component itself.
component 1 : Guice DI
+-- application A : Spring DI
+-- application B : Default behavior
+-- …
Remember that DI is *not* analogous to the concept of "service".
It's
a global aspect, much like the choice of Engine. You should
never have
to say things like "that's a Spring app" or "that's a Guice
app". That's the motivation for JSR 330: It lets you specify
injection
points in a standard way without committing to a particular DI
framework. In your example, the application A author might have
developed the application using Spring, but by expressing
dependencies
entirely with JSR 330 annotations, the application can be used
without
change in a Guice environment.
Of course if there are internal dependencies that rely on
framework-specific bindings they can be encapsulated in one
place and
exposed in a way that users can invoke from other DI
frameworks. For
Post by Tim Peierls
example, Guice can import bindings from Spring through the
http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/spring/SpringIntegration.html
Post by Tim Peierls
There's probably something similar to adapt a Guice injector as a
Spring bean factory.
I’m wondering if the Context shouldn’t be the place to
implement
Post by Tim Peierls
one of the solutions you evoked.
The trouble is that context can be overridden down the Restlet
tree,
Post by Tim Peierls
and that could end up unintentionally orphaning a whole
subtree from
Post by Tim Peierls
the global DI.
But there might be cases where an Application writer would want
to be
able to override the use of global DI, and Context could be used
there. For example (assuming approach #1 of my earlier e-mail),
if you
added a finderCreator property to Context, defaulting to null, the
1. Check to see if the given finderClass is non-null (and
not ==
Post by Tim Peierls
Finder.class). If so, use it.
2. Check to see if the given context has a non-null
finderCreator
Post by Tim Peierls
property. If so, use it.
3. Check to see if the Engine has a registered
finderCreator. If
Post by Tim Peierls
so, use it.
4. Otherwise, use new Finder(...).
Case 4 is when no one has done anything special; it's what we have
today. Applications written to use DI won't work in this case.
Case 3 is when the component or embedding environment wants to
support
applications that require DI (using JSR 330 annotations). The
engine
Post by Tim Peierls
is told, in effect: The system is using such-and-such Spring
application context (or such-and-such Guice injector).
Case 2 is for an application that explicitly disclaims an
interest in
the global DI and wants to handle things separately, possibly by
using
its own private DI mechanism throughout the application.
And case 1 is for overriding finder creation for a Router (or
Application) instance without affecting finder creation for other
Restlets within the same Application.
--tim
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699698
<http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699698>
<http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699698
<http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699698>>
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699729
<http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699729>
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699839
Tim Peierls
2011-01-22 19:40:54 UTC
Permalink
We're way off topic, so I'll respond privately when I get a chance. (Which
might not be for quite a while -- things got busy here.)

--tim
Post by Tal Liron
I see your point about DillFinder potentially growing too big, but
actually the code you wrote was pretty much good enough for me. If I
have to manually inject the Context with what I need, so be it. I have
no expectation for Restlet helping me with that.
Restlet has numerous curious architectural pattern decisions: the
factory pattern for resources, and the lack of interfaces, that may have
the advantage of encouraging certain programming styles. To me, this has
always felt like a mistake: encouragement is not enforcement, definitely
not at a code level. It ends up feeling heavy handed, rather than free.
In its place, I would hope for more real-world examples showing how to
manage complex state in Restlet. These would create best practices,
rather than a awkward API (which I consider the Finder to be).
Moreover -- I think you're overstating (pun!) the state issue. I do not
think it's correct to talk about a resource being "stateless" (in any
case, encapsulation is just one of three OO principles, such that a
Resource with state is still not quite an "object"). Remember that
Fielding's dissertation called the chapter Representaional State
it's not "representations of state," but "representational state." It's
definitely state. The point that Fielding tried to emphasize in many
different ways was that the web was exactly *not* uselessly stateless,
as so many programmers thought, but that in fact it is exactly stateful
in a specific matter that is useful. In other words, the web is *an*
application -- instead of building applications "on top" of it, we
should be treating it as the application layer itself, and work within
its state semantics, which he then elaborated.
The qualifier -- "representational" state -- as opposed to, say,
"actual" state, means that the expectations of human and other users of
the web-as-an-application is that they access (see, alter) the state
subjectively, within terms and conditions true to capabilities,
location, time, etc., of the moment. Thus a browser loads a page -- and
all web users know they can refresh the page and possibly see a new
representation of the application's state. Or not: caching of
representation becomes possible (a crucial REST concept not yet handled
by Restlet) as does massive scalability. Point is that this expectation
allows for representations to be manipulated along the way (the
"transfer") as pure things-in-themselves with no strings attached. (This
is somewhat analogous to the notion of pure functions in functional
programming.) In other words, it's not resources that are stateless, but
representations.
Your Restlet resources definitely have state, except that you might have
decided not to store them in ServerResource instances, and instead in an
application context. But that's your own architectural decision, albeit
one that is somewhat encouraged by Restlet right now. But I don't see
anything immediately wrong with storing state in a ServerResource, if
that's where it logically belongs. For example, it might store a
connection pool to a database it uses. If only one URI pattern uses that
pool, why have to put it elsewhere? This is actually a common design for
URI spaces. And if the same resource class is re-used for numerous URIs,
each instance can hold its own relevant state. That's good OOP
re-usability that has nothing to do with REST per se.
I'll have to disagree with your take on functional programming in the
Guava list, too. Clojure's transactional memory (via Refs) is an
innovative and simple way to share state without bringing "the whole
multiprocessor down." Persistent data structures can be used outside of
functional programming (indeed, Clojure's all implement the standard JVM
interfaces) but are so much more elegantly expressed (purely)
functionally. And that's the difference I was trying to point out
earlier: Clojure *does* enforce coding patterns at the code level, in a
way Restlet (as a Java library) never can -- Refs can only be used in a
transaction, otherwise an exception is thrown. Functional programming is
already the best practice for using persistent data structures.
Moreover, I see the mechanism of transactional memory fitting quite well
with the architectural notion of representational state. Per transaction
(user request) you can get a snapshot of very complex state.
In summary, I was quite serious about the potential of a Clojure rewrite
of Restlet. Not so serious about actually doing it, though...
-Tal
Post by Tim Peierls
No one wants to see the Restlet core take on too much. Trouble with
DillFinder, light as it is, is that it falls short of implementing the
official standard, JSR 330. That might not bother you, but it would
complicate the story: "You can use built-in DI lite, which has the
following idiosyncrasies, or you can use full JSR 330 without the
idiosyncrasies but with an extension jar." What's more, the next
person is going to ask for Provider support in the core, and recursive
injection of objects, and scope, and ... By the time you've added
all that in to Restlet, you've got what amounts to small DI framework
that is now too big to fit comfortably in core Restlet. I don't see
clear criteria for drawing the line anywhere but the extremes, which
is why I proposed that the core have only enough configurability to
*support *JSR-330-compliant extensions, without trying to do any DI,
even poor man's DI, on its own.
Hmm, just noticed a simple framework for injection that claims to be
http://code.google.com/p/java-simple-utils/wiki/Injection
Is 70K within the threshold of acceptability?
Regarding the use of the factory pattern for resources: I can't speak
for Noelios, but I imagine the original motivation was not so much to
reduce concurrency issues, but to accurately reflect the distinction
between stateful/OOP/Restlet to stateless/ROP/resource. I think it was
a brilliant design choice. It forced me to confront the fact that
resource != object and that resource is more closely analogous to
class. The only thing missing was a way to let my resources
participate in DI, and now I have that, too -- although I'm hoping it
can be made a bit prettier and more consistent.
It's true that the factory pattern doesn't solve the problem of
sharing data safely between resource handlers, but at least it
clarifies where the problem is. The resource instance is ephemeral so
you *must* get all your state from somewhere else. If it wasn't, it
would be all too tempting to try to associate state with the resource,
and before you know it, whoops, you've essentially got servlets and
sessions.
And I know you weren't being entirely serious about Clojure, but I
don't think we need to look for help from other languages. Clojure /
functional programming doesn't eliminate concurrency issues any more
than garbage collection eliminates memory leaks. There are plenty of
great tools in Java to help manage the concurrency burden. Guava
MapMaker is a terrific example. (Incidentally, I recently ranted
<
http://groups.google.com/group/guava-discuss/browse_thread/thread/278dd6a99214d91a/92f14996f69b179d?hl=en%5Cf14996f69b179d#
Post by Tim Peierls
about the fallacy of FP solving all concurrency problems on the Guava
discussion list.)
--tim
On Fri, Jan 21, 2011 at 6:39 PM, Tal Liron
Dill is not my favorite herb, but it does add some flavor. :)
Your implementation of DillFinder is fine! What I was trying to suggest
is to merge such code or something very similar into Restlet's core
Finder and perhaps solve 90% of people's DI needs when it comes to
ServerResource. And it's such lighweight and little code, isn't it?
I know 700k isn't enormous, but it's always the struggle between the
desire to keep things minimal and to add dependencies. It's not just
700k: it's adhering to the library's patterns and integrating them into
your library's culture, it's keeping up with progress there, etc. The
cost of dependency is uncertainty and headaches and lock-ins.
Jerome's
Post by Tim Peierls
decision to keep support for all these dependencies as extensions is
important. I know that for you and many others Guice is worth all those
costs, but I would be upset if using Restlet would *practically* require
some kind of external DI library for it to run properly.
Sigh. I guess even more than having DillFinder-like functionality, I
would appreciate an alternative to the Finder/ServerResource system
entirely. I know that the idea of "one ServerResource instance per
request" has certain advantages in terms of ease of handling state, and
also in terms of performance, but it's always been a headache in
terms
Post by Tim Peierls
of initialization. And it's difficult to program -- a kick in the
head
Post by Tim Peierls
for how most of us understand OOP and its relationship to Java. When it
comes down to it, you still have to do the hard concurrency programming
to handle shared state between resources (which is part of what
"initialization" via the Context does). So, I wonder how much we've
really made things easier.
In my opinion, it would be most comfortable if there were a
ResourceRestlet class inheriting from Restlet, such that you would be
router.attach("/customer/{id}/", new MyResource(arg1, arg2));
You would have to make sure that MyResource is thread-safe, of
course,
Post by Tim Peierls
but it would much more sense to most programmers, and also flow
better
Post by Tim Peierls
with the rest of the Restlet API. No need for DI (unless you want it, of
course), and definitely no need to integrate DI into the
framework. I'm
sure this approach has been tried and abandoned in Restlet's history.
Perhaps it's worth trying again, now that Restlet is mature and we have
so many concurrency gurus onboard?
Argh. I want to rewrite Restlet in Clojure so we can do away with all
these painful concurrency tradeoffs. Maybe that will be my project
for
Post by Tim Peierls
next year. Who wants to help? Hmm, now where would be a good place to
find experts on JVM concurrency... ;)
-Tal
Post by Tim Peierls
Tal,
How about this?
public class DillFinder extends Finder {
public DillFinder(Context context, Class<? extends
ServerResource>
Post by Tim Peierls
targetClass) {
super(context, targetClass);
}
@Override public ServerResource create(
Class<? extends ServerResource> targetClass,
Request request,
Response response)
{
for (Constructor ctor : targetClass.getConstructors()) {
if (ctor.getAnnotation(Inject.class) != null) {
@SuppressWarnings("unchecked")
Constructor<? extends ServerResource> c =
(Constructor<? extends ServerResource>) ctor;
return create(c);
}
}
// No constructor with Inject found, use default.
return super.create(targetClass, request, response);
}
private ServerResource create(Constructor<? extends
ServerResource> ctor) {
try {
Map<String, Object> attrs =
getContext().getAttributes();
Post by Tim Peierls
Class<?>[] paramTypes = ctor.getParameterTypes();
Object[] params = new Object[paramTypes.length];
for (int i = 0; i < paramTypes.length; ++i) {
Class<?> paramType = paramTypes[i];
String paramTypeName = paramType.getName();
Object paramValue = attrs.get(paramTypeName);
if (paramType.isInstance(paramValue)) {
params[i] = paramValue;
}
}
return ctor.newInstance(params);
} catch (InstantiationException ex) {
throw new ResourceException(ex);
} catch (IllegalAccessException ex) {
throw new ResourceException(ex);
} catch (InvocationTargetException ex) {
throw new ResourceException(ex);
}
}
}
Dill is an acronym: *D*epencency *I*njection *L*ite al *L*iron. :-)
But Guice is <700K, so if you don't mind adding that jar and you're
willing to try the incubator's Guice extension, you can get this
behavior without the limits of DillFinder (and it is pretty
limited)
Post by Tim Peierls
Post by Tim Peierls
and without having to buy any further into full-fledged DI. It
would
Post by Tim Peierls
Post by Tim Peierls
FinderFactory finderFactory = new RestletGuice.Module() {
@Provides CustomerProcessor provideCustomerProcessor(Context
context) {
return (CustomerProcessor) context.getAttributes()
.get("org.happy.CustomerResource.processor");
}
@Provides LogManager provideLogManager(Context context) {
return (LogManager) context.getAttributes()
.get("org.happy.CustomerResource.log");
}
}
Your customer resource's constructor would be annotated with
@Inject.
Post by Tim Peierls
For the moment, you can use the Guice extension in its current
router.attach("/customer/{id}/",
finderFactory.finder(CustomerResource.class));
where finderFactory would need to be passed in somehow. If the
enhancements I've proposed (including the improvement suggested by
router.attach("/customer/{id}/", CustomerResource.class);
--tim
On Fri, Jan 21, 2011 at 2:03 PM, Tal Liron
Echoing Jerome's question about the Context --
A very common use case for me is to inject data right from the
Context.
In fact, it was Tim who, more than a year ago, promised me
that it was
Post by Tim Peierls
the "Restlet way" to initialize resource instances. I guess
this was
Post by Tim Peierls
before he started making babies with Guice. ;)
So, I'm wondering if Restlet could provide a standard
mechanism for
Post by Tim Peierls
injection from the Context, without reliance on external DI
tools, and
Post by Tim Peierls
with no integration beyond the "inelegant" extensions as they
exist now.
package org.happy;
class CustomerResource extends ServerResource {
@InjectFromContext
public CustomerResource(CustomerProcessor processor,
LogManager
Post by Tim Peierls
log) {
...
}
}
Where the Context attributes will be expected to be named
"org.happy.CustomerResource.processor" and
"org.happy.CustomerResource.log" and to be in the types
specified.
Post by Tim Peierls
That's "DI lite", but very much in tune with the "Restlet way."
-Tal
On Fri, Jan 21, 2011 at 2:48 AM, Jerome Louvel
My main remark is that using Guice or Spring or the default
mechanism or something else shouldn’t be an engine wide
choice.
Post by Tim Peierls
Each application contained in a component should be able to
use a
different mechanism. It should also be possible to use DI to
configure the component itself.
component 1 : Guice DI
+-- application A : Spring DI
+-- application B : Default behavior
+-- 

Remember that DI is *not* analogous to the concept of "service".
It's
a global aspect, much like the choice of Engine. You should
never have
to say things like "that's a Spring app" or "that's a Guice
app". That's the motivation for JSR 330: It lets you specify
injection
points in a standard way without committing to a particular DI
framework. In your example, the application A author might have
developed the application using Spring, but by expressing
dependencies
entirely with JSR 330 annotations, the application can be used
without
change in a Guice environment.
Of course if there are internal dependencies that rely on
framework-specific bindings they can be encapsulated in one
place and
exposed in a way that users can invoke from other DI
frameworks. For
Post by Tim Peierls
example, Guice can import bindings from Spring through the
http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/spring/SpringIntegration.html
Post by Tim Peierls
Post by Tim Peierls
There's probably something similar to adapt a Guice injector as a
Spring bean factory.
I’m wondering if the Context shouldn’t be the place to
implement
Post by Tim Peierls
one of the solutions you evoked.
The trouble is that context can be overridden down the Restlet
tree,
Post by Tim Peierls
and that could end up unintentionally orphaning a whole
subtree from
Post by Tim Peierls
the global DI.
But there might be cases where an Application writer would want
to be
able to override the use of global DI, and Context could be used
there. For example (assuming approach #1 of my earlier e-mail),
if you
added a finderCreator property to Context, defaulting to null,
the
Post by Tim Peierls
Post by Tim Peierls
1. Check to see if the given finderClass is non-null (and
not ==
Post by Tim Peierls
Finder.class). If so, use it.
2. Check to see if the given context has a non-null
finderCreator
Post by Tim Peierls
property. If so, use it.
3. Check to see if the Engine has a registered
finderCreator. If
Post by Tim Peierls
so, use it.
4. Otherwise, use new Finder(...).
Case 4 is when no one has done anything special; it's what we
have
Post by Tim Peierls
Post by Tim Peierls
today. Applications written to use DI won't work in this case.
Case 3 is when the component or embedding environment wants to
support
applications that require DI (using JSR 330 annotations). The
engine
Post by Tim Peierls
is told, in effect: The system is using such-and-such Spring
application context (or such-and-such Guice injector).
Case 2 is for an application that explicitly disclaims an
interest in
the global DI and wants to handle things separately, possibly by
using
its own private DI mechanism throughout the application.
And case 1 is for overriding finder creation for a Router (or
Application) instance without affecting finder creation for other
Restlets within the same Application.
--tim
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699698
Post by Tim Peierls
<
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699698
Post by Tim Peierls
<
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699698
Post by Tim Peierls
<
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699698
Post by Tim Peierls
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699729
Post by Tim Peierls
<
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699729
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699839
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699841
Jerome Louvel
2011-07-29 22:12:35 UTC
Permalink
Hi Tim,



I’ve read the thread again and prefer to wait post 2.1 to make decisions. Some thoughts for now:

· As javax.inject isn’t part of Java SE (yet?), we can’t add a dependency on it directly from org.restlet.jar

· We could however add support for it via an org.restlet.ext.inject extension

· In addition to passing shared objects via Context.attributes, it is also possible to directly access the parent Application and its custom properties via ServerResource#getApplication(). It should be overridden to return the proper instance of your Application subclass



Regarding the ServerResource pattern, I would say that the main reason is that there can be any number of URIs/resources in a REST system, at no design cost. Think about a REST API exposing billions of GPS points as resources with separate URIs. It is obvious that you can’t pre-instantiate all of them like a graph of objects.



Therefore, you need a way to manage groups/classes of resources and the easiest criteria is to use URI path templates including variable parts and query parameters. Then, you need a way to create/discard resource instances on a per call basis.



Note that for resource classes limited in number of instances, it is in theory possible to preinstantiate them. This is the purpose of the Finder class and its find(Request,Response):ServerResource method, to reuse existing ServerResource instances. However, as ServerResource acts as a wrapper of a Request/Response couple, it doesn’t work in practice




Best regards,
Jerome
--
Restlet ~ Founder and Technical Lead ~ <http://www.restlet.org/> http://www.restlet.o​rg
Noelios Technologies ~ <http://www.noelios.com/> http://www.noelios.com







De : tpeierls-***@public.gmane.org [mailto:tpeierls-***@public.gmane.org] De la part de Tim Peierls
Envoyé : samedi 22 janvier 2011 20:41
À : code-s0N/mLB9wL+***@public.gmane.org
Objet : Re: Unnecessary type check?



We're way off topic, so I'll respond privately when I get a chance. (Which might not be for quite a while -- things got busy here.)



--tim



On Sat, Jan 22, 2011 at 2:35 PM, Tal Liron <tal.liron-KRbUgwfp4vGAiRqxG6I7vAC/***@public.gmane.org> wrote:

I see your point about DillFinder potentially growing too big, but
actually the code you wrote was pretty much good enough for me. If I
have to manually inject the Context with what I need, so be it. I have
no expectation for Restlet helping me with that.


Restlet has numerous curious architectural pattern decisions: the
factory pattern for resources, and the lack of interfaces, that may have
the advantage of encouraging certain programming styles. To me, this has
always felt like a mistake: encouragement is not enforcement, definitely
not at a code level. It ends up feeling heavy handed, rather than free.
In its place, I would hope for more real-world examples showing how to
manage complex state in Restlet. These would create best practices,
rather than a awkward API (which I consider the Finder to be).


Moreover -- I think you're overstating (pun!) the state issue. I do not
think it's correct to talk about a resource being "stateless" (in any
case, encapsulation is just one of three OO principles, such that a
Resource with state is still not quite an "object"). Remember that
Fielding's dissertation called the chapter Representaional State
Transfer, and not "a resource-oriented architecture". Look at the name:
it's not "representations of state," but "representational state." It's
definitely state. The point that Fielding tried to emphasize in many
different ways was that the web was exactly *not* uselessly stateless,
as so many programmers thought, but that in fact it is exactly stateful
in a specific matter that is useful. In other words, the web is *an*
application -- instead of building applications "on top" of it, we
should be treating it as the application layer itself, and work within
its state semantics, which he then elaborated.


The qualifier -- "representational" state -- as opposed to, say,
"actual" state, means that the expectations of human and other users of
the web-as-an-application is that they access (see, alter) the state
subjectively, within terms and conditions true to capabilities,
location, time, etc., of the moment. Thus a browser loads a page -- and
all web users know they can refresh the page and possibly see a new
representation of the application's state. Or not: caching of
representation becomes possible (a crucial REST concept not yet handled
by Restlet) as does massive scalability. Point is that this expectation
allows for representations to be manipulated along the way (the
"transfer") as pure things-in-themselves with no strings attached. (This
is somewhat analogous to the notion of pure functions in functional
programming.) In other words, it's not resources that are stateless, but
representations.


Your Restlet resources definitely have state, except that you might have
decided not to store them in ServerResource instances, and instead in an
application context. But that's your own architectural decision, albeit
one that is somewhat encouraged by Restlet right now. But I don't see
anything immediately wrong with storing state in a ServerResource, if
that's where it logically belongs. For example, it might store a
connection pool to a database it uses. If only one URI pattern uses that
pool, why have to put it elsewhere? This is actually a common design for
URI spaces. And if the same resource class is re-used for numerous URIs,
each instance can hold its own relevant state. That's good OOP
re-usability that has nothing to do with REST per se.


I'll have to disagree with your take on functional programming in the
Guava list, too. Clojure's transactional memory (via Refs) is an
innovative and simple way to share state without bringing "the whole
multiprocessor down." Persistent data structures can be used outside of
functional programming (indeed, Clojure's all implement the standard JVM
interfaces) but are so much more elegantly expressed (purely)
functionally. And that's the difference I was trying to point out
earlier: Clojure *does* enforce coding patterns at the code level, in a
way Restlet (as a Java library) never can -- Refs can only be used in a
transaction, otherwise an exception is thrown. Functional programming is
already the best practice for using persistent data structures.
Moreover, I see the mechanism of transactional memory fitting quite well
with the architectural notion of representational state. Per transaction
(user request) you can get a snapshot of very complex state.


In summary, I was quite serious about the potential of a Clojure rewrite
of Restlet. Not so serious about actually doing it, though...


-Tal
Post by Tim Peierls
No one wants to see the Restlet core take on too much. Trouble with
DillFinder, light as it is, is that it falls short of implementing the
official standard, JSR 330. That might not bother you, but it would
complicate the story: "You can use built-in DI lite, which has the
following idiosyncrasies, or you can use full JSR 330 without the
idiosyncrasies but with an extension jar." What's more, the next
person is going to ask for Provider support in the core, and recursive
injection of objects, and scope, and ... By the time you've added
all that in to Restlet, you've got what amounts to small DI framework
that is now too big to fit comfortably in core Restlet. I don't see
clear criteria for drawing the line anywhere but the extremes, which
is why I proposed that the core have only enough configurability to
*support *JSR-330-compliant extensions, without trying to do any DI,
even poor man's DI, on its own.
Hmm, just noticed a simple framework for injection that claims to be
http://code.google.com/p/java-simple-utils/wiki/Injection
Is 70K within the threshold of acceptability?
Regarding the use of the factory pattern for resources: I can't speak
for Noelios, but I imagine the original motivation was not so much to
reduce concurrency issues, but to accurately reflect the distinction
between stateful/OOP/Restlet to stateless/ROP/resource. I think it was
a brilliant design choice. It forced me to confront the fact that
resource != object and that resource is more closely analogous to
class. The only thing missing was a way to let my resources
participate in DI, and now I have that, too -- although I'm hoping it
can be made a bit prettier and more consistent.
It's true that the factory pattern doesn't solve the problem of
sharing data safely between resource handlers, but at least it
clarifies where the problem is. The resource instance is ephemeral so
you *must* get all your state from somewhere else. If it wasn't, it
would be all too tempting to try to associate state with the resource,
and before you know it, whoops, you've essentially got servlets and
sessions.
And I know you weren't being entirely serious about Clojure, but I
don't think we need to look for help from other languages. Clojure /
functional programming doesn't eliminate concurrency issues any more
than garbage collection eliminates memory leaks. There are plenty of
great tools in Java to help manage the concurrency burden. Guava
MapMaker is a terrific example. (Incidentally, I recently ranted
<http://groups.google.com/group/guava-discuss/browse_thread/thread/278dd6a99214d91a/92f14996f69b179d?hl=en%5Cf14996f69b179d# <http://groups.google.com/group/guava-discuss/browse_thread/thread/278dd6a99214d91a/92f14996f69b179d?hl=en%5Cf14996f69b179d> >
about the fallacy of FP solving all concurrency problems on the Guava
discussion list.)
--tim
On Fri, Jan 21, 2011 at 6:39 PM, Tal Liron
Dill is not my favorite herb, but it does add some flavor. :)
Your implementation of DillFinder is fine! What I was trying to suggest
is to merge such code or something very similar into Restlet's core
Finder and perhaps solve 90% of people's DI needs when it comes to
ServerResource. And it's such lighweight and little code, isn't it?
I know 700k isn't enormous, but it's always the struggle between the
desire to keep things minimal and to add dependencies. It's not just
700k: it's adhering to the library's patterns and integrating them into
your library's culture, it's keeping up with progress there, etc. The
cost of dependency is uncertainty and headaches and lock-ins. Jerome's
decision to keep support for all these dependencies as extensions is
important. I know that for you and many others Guice is worth all those
costs, but I would be upset if using Restlet would *practically* require
some kind of external DI library for it to run properly.
Sigh. I guess even more than having DillFinder-like functionality, I
would appreciate an alternative to the Finder/ServerResource system
entirely. I know that the idea of "one ServerResource instance per
request" has certain advantages in terms of ease of handling state, and
also in terms of performance, but it's always been a headache in terms
of initialization. And it's difficult to program -- a kick in the head
for how most of us understand OOP and its relationship to Java. When it
comes down to it, you still have to do the hard concurrency programming
to handle shared state between resources (which is part of what
"initialization" via the Context does). So, I wonder how much we've
really made things easier.
In my opinion, it would be most comfortable if there were a
ResourceRestlet class inheriting from Restlet, such that you would be
router.attach("/customer/{id}/", new MyResource(arg1, arg2));
You would have to make sure that MyResource is thread-safe, of course,
but it would much more sense to most programmers, and also flow better
with the rest of the Restlet API. No need for DI (unless you want it, of
course), and definitely no need to integrate DI into the
framework. I'm
sure this approach has been tried and abandoned in Restlet's history.
Perhaps it's worth trying again, now that Restlet is mature and we have
so many concurrency gurus onboard?
Argh. I want to rewrite Restlet in Clojure so we can do away with all
these painful concurrency tradeoffs. Maybe that will be my project for
next year. Who wants to help? Hmm, now where would be a good place to
find experts on JVM concurrency... ;)
-Tal
Post by Tim Peierls
Tal,
How about this?
public class DillFinder extends Finder {
public DillFinder(Context context, Class<? extends
ServerResource>
Post by Tim Peierls
targetClass) {
super(context, targetClass);
}
@Override public ServerResource create(
Class<? extends ServerResource> targetClass,
Request request,
Response response)
{
for (Constructor ctor : targetClass.getConstructors()) {
if (ctor.getAnnotation(Inject.class) != null) {
@SuppressWarnings("unchecked")
Constructor<? extends ServerResource> c =
(Constructor<? extends ServerResource>) ctor;
return create(c);
}
}
// No constructor with Inject found, use default.
return super.create(targetClass, request, response);
}
private ServerResource create(Constructor<? extends
ServerResource> ctor) {
try {
Map<String, Object> attrs =
getContext().getAttributes();
Post by Tim Peierls
Class<?>[] paramTypes = ctor.getParameterTypes();
Object[] params = new Object[paramTypes.length];
for (int i = 0; i < paramTypes.length; ++i) {
Class<?> paramType = paramTypes[i];
String paramTypeName = paramType.getName();
Object paramValue = attrs.get(paramTypeName);
if (paramType.isInstance(paramValue)) {
params[i] = paramValue;
}
}
return ctor.newInstance(params);
} catch (InstantiationException ex) {
throw new ResourceException(ex);
} catch (IllegalAccessException ex) {
throw new ResourceException(ex);
} catch (InvocationTargetException ex) {
throw new ResourceException(ex);
}
}
}
Dill is an acronym: *D*epencency *I*njection *L*ite al *L*iron. :-)
But Guice is <700K, so if you don't mind adding that jar and you're
willing to try the incubator's Guice extension, you can get this
behavior without the limits of DillFinder (and it is pretty limited)
and without having to buy any further into full-fledged DI. It would
FinderFactory finderFactory = new RestletGuice.Module() {
@Provides CustomerProcessor provideCustomerProcessor(Context
context) {
return (CustomerProcessor) context.getAttributes()
.get("org.happy.CustomerResource.processor");
}
@Provides LogManager provideLogManager(Context context) {
return (LogManager) context.getAttributes()
.get("org.happy.CustomerResource.log");
}
}
Your customer resource's constructor would be annotated with
@Inject.
Post by Tim Peierls
For the moment, you can use the Guice extension in its current
router.attach("/customer/{id}/",
finderFactory.finder(CustomerResource.class));
where finderFactory would need to be passed in somehow. If the
enhancements I've proposed (including the improvement suggested by
router.attach("/customer/{id}/", CustomerResource.class);
--tim
On Fri, Jan 21, 2011 at 2:03 PM, Tal Liron
Echoing Jerome's question about the Context --
A very common use case for me is to inject data right from the Context.
In fact, it was Tim who, more than a year ago, promised me
that it was
Post by Tim Peierls
the "Restlet way" to initialize resource instances. I guess
this was
Post by Tim Peierls
before he started making babies with Guice. ;)
So, I'm wondering if Restlet could provide a standard
mechanism for
Post by Tim Peierls
injection from the Context, without reliance on external DI
tools, and
Post by Tim Peierls
with no integration beyond the "inelegant" extensions as they
exist now.
package org.happy;
class CustomerResource extends ServerResource {
@InjectFromContext
public CustomerResource(CustomerProcessor processor,
LogManager
Post by Tim Peierls
log) {
...
}
}
Where the Context attributes will be expected to be named
"org.happy.CustomerResource.processor" and
"org.happy.CustomerResource.log" and to be in the types
specified.
Post by Tim Peierls
That's "DI lite", but very much in tune with the "Restlet way."
-Tal
On Fri, Jan 21, 2011 at 2:48 AM, Jerome Louvel
My main remark is that using Guice or Spring or the default
mechanism or something else shouldn’t be an engine wide
choice.
Post by Tim Peierls
Each application contained in a component should be able to
use a
different mechanism. It should also be possible to use DI to
configure the component itself.
component 1 : Guice DI
+-- application A : Spring DI
+-- application B : Default behavior
+-- 

Remember that DI is *not* analogous to the concept of "service".
It's
a global aspect, much like the choice of Engine. You should
never have
to say things like "that's a Spring app" or "that's a Guice
app". That's the motivation for JSR 330: It lets you specify
injection
points in a standard way without committing to a particular DI
framework. In your example, the application A author might have
developed the application using Spring, but by expressing
dependencies
entirely with JSR 330 annotations, the application can be used
without
change in a Guice environment.
Of course if there are internal dependencies that rely on
framework-specific bindings they can be encapsulated in one
place and
exposed in a way that users can invoke from other DI
frameworks. For
Post by Tim Peierls
example, Guice can import bindings from Spring through the
http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/spring/SpringIntegration.html
Post by Tim Peierls
There's probably something similar to adapt a Guice injector as a
Spring bean factory.
I’m wondering if the Context shouldn’t be the place to
implement
Post by Tim Peierls
one of the solutions you evoked.
The trouble is that context can be overridden down the Restlet
tree,
Post by Tim Peierls
and that could end up unintentionally orphaning a whole
subtree from
Post by Tim Peierls
the global DI.
But there might be cases where an Application writer would want
to be
able to override the use of global DI, and Context could be used
there. For example (assuming approach #1 of my earlier e-mail),
if you
added a finderCreator property to Context, defaulting to null, the
1. Check to see if the given finderClass is non-null (and
not ==
Post by Tim Peierls
Finder.class). If so, use it.
2. Check to see if the given context has a non-null
finderCreator
Post by Tim Peierls
property. If so, use it.
3. Check to see if the Engine has a registered
finderCreator. If
Post by Tim Peierls
so, use it.
4. Otherwise, use new Finder(...).
Case 4 is when no one has done anything special; it's what we have
today. Applications written to use DI won't work in this case.
Case 3 is when the component or embedding environment wants to
support
applications that require DI (using JSR 330 annotations). The
engine
Post by Tim Peierls
is told, in effect: The system is using such-and-such Spring
application context (or such-and-such Guice injector).
Case 2 is for an application that explicitly disclaims an
interest in
the global DI and wants to handle things separately, possibly by
using
its own private DI mechanism throughout the application.
And case 1 is for overriding finder creation for a Router (or
Application) instance without affecting finder creation for other
Restlets within the same Application.
--tim
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458 <http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699698> &dsMessageId=2699698
<http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458 <http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699698> &dsMessageId=2699698>
<http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458 <http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699698> &dsMessageId=2699698
<http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458 <http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699698> &dsMessageId=2699698>>
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458 <http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699729> &dsMessageId=2699729
<http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458 <http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699729> &dsMessageId=2699729>
------------------------------------------------------

http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458 <http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699839> &dsMessageId=2699839

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2806031
Tim Peierls
2011-07-29 23:25:39 UTC
Permalink
Post by Jerome Louvel
I’ve read the thread again and prefer to wait post 2.1 to make decisions.
OK, but I'm concerned that you've misunderstood what I was saying. Read
on...
Post by Jerome Louvel
**· **As javax.inject isn’t part of Java SE (yet?), we can’t add a
dependency on it directly from org.restlet.jar
Not sure why this is relevant. Nothing in what I proposed depends on
javax.inject.
Post by Jerome Louvel
****
**· **We could however add support for it via an
org.restlet.ext.inject extension
I don't see a need for that.

By the way, the main interface of the (incubator) extension
org.restlet.ext.guice, FinderFactory, depends on neither Guice nor
javax.inject. The other type in that package, RestletGuice, is
naturally Guice-specific, but that ought to be OK for Guice extension. :-)
Post by Jerome Louvel
****
**· **In addition to passing shared objects via
Context.attributes, it is also possible to directly access the parent
Application and its custom properties via ServerResource#getApplication().
It should be overridden to return the proper instance of your Application
subclass
I don't see why this is relevant, either. The point of what I proposed was
not the sharing of objects, but making it possible for ordinary Restlet apps
to play well with dependency injection frameworks. The org.restlet.ext.guice
extension already allows this, but it's awkward; I want a way to make it
less awkward.

Aside: But now that you mention it, :-) the overriding of getApplication()
can be "automated" to some extent to reduce the burden on the developer:

public class AppResource<T extends Application> extends ServerResource {
// ... same constructors as ServerResource ...
@SuppressWarnings("unchecked")
@Override public T getApplication() {
return (T) super.getApplication();
}
}

// Usage:

public class MyApp extends Application {
public String getSomeAppString() { ... }
}
public class MyResource extends AppResource<MyApp> {
@Get("txt") public String getStringValue() {
return getApplication().getSomeAppString();
}
}



****
Post by Jerome Louvel
Regarding the ServerResource pattern, I would say that the main reason is
that there can be any number of URIs/resources in a REST system, at no
design cost. Think about a REST API exposing billions of GPS points as
resources with separate URIs. It is obvious that you can’t pre-instantiate
all of them like a graph of objects.
Right.
Post by Jerome Louvel
Therefore, you need a way to manage groups/classes of resources and the
easiest criteria is to use URI path templates including variable parts and
query parameters. Then, you need a way to create/discard resource instances
on a per call basis.
Right.
Post by Jerome Louvel
Note that for resource classes limited in number of instances, it is in
theory possible to preinstantiate them. This is the purpose of the Finder
class and its find(Request,Response):ServerResource method, to reuse
existing ServerResource instances. However, as ServerResource acts as a
wrapper of a Request/Response couple, it doesn’t work in practice

Is it possible that you misunderstood what I proposed? It had nothing to do
with pre-instantiating ServerResources.

The problem is that currently Restlet's instantiation of ServerResources is
hard-wired to use the default constructor of a type. The Guice extension,
which I have been using in practice for over a year, gets around that
restrction and enables me to write dependency-injected resource classes.

Dependency injection is not only used to create initial graphs of objects.
Here's a simple example:

public class FooResource extends ServerResource {
@Inject FooResource(SomeService someService, @Fooish DatabaseTable
fooTable) {
this.someService = someService;
this.fooTable = fooTable;
}
@Get public Foo foo() {
String key = ensureNonEmpty(getRequestAttributes().get("foo"));
FooRecord record = fooTable.lookup(key);
return someService.convertRecordToFoo(record);
}
private final SomeService someService;
private final DatabaseTable fooTable;
}


An instance of FooResource is created *and injected* for every request.

To route FooResource right now, I have to say:

router.attach("/path/to/foo/{foo}/",
finderFactory.finder(FooResource.class));

and I want to be able to say simply

router.attach("/path/to/foo/{foo}/", FooResource.class);

That's what I was getting at. I'm not trying to put @Inject in Restlet, but
I *must* able to put @Inject on my own resource constructors.

--tim

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2806038
Jerome Louvel
2011-07-31 19:09:12 UTC
Permalink
Hi Tim,



After looking at JSR-330 in more details, I realize that it just contains annotations and no DI module management API at all. That probably explains why you don’t see a need for an org.restlet.ext.inject extension, sorry for the confusion!



Back to your original suggestion [1], it still seems to me that solutions 1) and 2) are too broad by working at the Engine level. Each Application deployed in the same Component could have been developed in different ways (ex: multitenant hosting), using different DI frameworks and so on. It seems to me that the Application and the Component classes are the right scope to define such behavior common to all Restlet and resources they contain, not the Engine.



As I think I now clearly understand your feed-back, I’ve done a bit of refactoring and committed the following changes in SVN trunk:



- Factorized "finderClass" property from Application and Router

into parent Restlet class and added a createFinder(Class)

method to facilitate instantiation and overriding.



- Deprecated ServerList.setNext(Class) as it isn't used and its

logic isn't consistent with similar methods in Filter/Router.



This Is only a first step in the direction of easier DI support. Next one is to provide similar level of support in Component and the specialized InternalRouter/VirtualHost classes it contains.



In the thread we also discussed about global DI and application specific DI all relying on JSR-330. That why I thought that we could provide a more generic extension based on the JSR-330 standard API. It would have contained an InjectedApplication. This wasn’t necessary exclusive with having more specific extensions for Guice and Spring. Actually, we could have a similar GuiceApplication and SpringApplication class.



Also, I’ve just updated the Guice library to version 2.0 in SVN trunk so that the Guice extension in the incubator compiles again in Eclipse.



Best regards,
Jerome
--
Restlet ~ Founder and Technical Lead ~ <http://www.restlet.org/> http://www.restlet.o​rg
Noelios Technologies ~ <http://www.noelios.com/> http://www.noelios.com





[1] http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458 <http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699138> &dsMessageId=2699138





De : tpeierls-***@public.gmane.org [mailto:tpeierls-***@public.gmane.org] De la part de Tim Peierls
Envoyé : samedi 30 juillet 2011 01:26
À : code-s0N/mLB9wL+***@public.gmane.org
Objet : Re: Unnecessary type check?



On Fri, Jul 29, 2011 at 6:12 PM, Jerome Louvel <jerome.louvel-***@public.gmane.org> wrote:

I’ve read the thread again and prefer to wait post 2.1 to make decisions.



OK, but I'm concerned that you've misunderstood what I was saying. Read on...





Some thoughts for now:

· As javax.inject isn’t part of Java SE (yet?), we can’t add a dependency on it directly from org.restlet.jar



Not sure why this is relevant. Nothing in what I proposed depends on javax.inject.





· We could however add support for it via an org.restlet.ext.inject extension

I don't see a need for that.



By the way, the main interface of the (incubator) extension org.restlet.ext.guice, FinderFactory, depends on neither Guice nor javax.inject. The other type in that package, RestletGuice, is naturally Guice-specific, but that ought to be OK for Guice extension. :-)





· In addition to passing shared objects via Context.attributes, it is also possible to directly access the parent Application and its custom properties via ServerResource#getApplication(). It should be overridden to return the proper instance of your Application subclass

I don't see why this is relevant, either. The point of what I proposed was not the sharing of objects, but making it possible for ordinary Restlet apps to play well with dependency injection frameworks. The org.restlet.ext.guice extension already allows this, but it's awkward; I want a way to make it less awkward.



Aside: But now that you mention it, :-) the overriding of getApplication() can be "automated" to some extent to reduce the burden on the developer:



public class AppResource<T extends Application> extends ServerResource {

// ... same constructors as ServerResource ...

@SuppressWarnings("unchecked")

@Override public T getApplication() {

return (T) super.getApplication();

}

}



// Usage:



public class MyApp extends Application {

public String getSomeAppString() { ... }

}

public class MyResource extends AppResource<MyApp> {

@Get("txt") public String getStringValue() {

return getApplication().getSomeAppString();

}

}





Regarding the ServerResource pattern, I would say that the main reason is that there can be any number of URIs/resources in a REST system, at no design cost. Think about a REST API exposing billions of GPS points as resources with separate URIs. It is obvious that you can’t pre-instantiate all of them like a graph of objects.



Right.





Therefore, you need a way to manage groups/classes of resources and the easiest criteria is to use URI path templates including variable parts and query parameters. Then, you need a way to create/discard resource instances on a per call basis.



Right.





Note that for resource classes limited in number of instances, it is in theory possible to preinstantiate them. This is the purpose of the Finder class and its find(Request,Response):ServerResource method, to reuse existing ServerResource instances. However, as ServerResource acts as a wrapper of a Request/Response couple, it doesn’t work in practice




Is it possible that you misunderstood what I proposed? It had nothing to do with pre-instantiating ServerResources.



The problem is that currently Restlet's instantiation of ServerResources is hard-wired to use the default constructor of a type. The Guice extension, which I have been using in practice for over a year, gets around that restrction and enables me to write dependency-injected resource classes.



Dependency injection is not only used to create initial graphs of objects. Here's a simple example:



public class FooResource extends ServerResource {

@Inject FooResource(SomeService someService, @Fooish DatabaseTable fooTable) {

this.someService = someService;

this.fooTable = fooTable;

}

@Get public Foo foo() {

String key = ensureNonEmpty(getRequestAttributes().get("foo"));

FooRecord record = fooTable.lookup(key);

return someService.convertRecordToFoo(record);

}

private final SomeService someService;

private final DatabaseTable fooTable;

}



An instance of FooResource is created and injected for every request.



To route FooResource right now, I have to say:



router.attach("/path/to/foo/{foo}/", finderFactory.finder(FooResource.class));



and I want to be able to say simply



router.attach("/path/to/foo/{foo}/", FooResource.class);



That's what I was getting at. I'm not trying to put @Inject in Restlet, but I must able to put @Inject on my own resource constructors.



--tim

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2807270
Tim Peierls
2011-07-31 22:34:30 UTC
Permalink
Post by Jerome Louvel
After looking at JSR-330 in more details, I realize that it just contains
annotations and no DI module management API at all. That probably explains
why you don’t see a need for an org.restlet.ext.inject extension, sorry for
the confusion!
Actually, since FinderFactory in the incubator doesn't depend on Guice,
maybe there *should* be an org.restlet.ext.inject extension to hold it and a
few related types I plan to add (see below). The RestletGuice class could
remain in org.restlet.ext.guice -- although I don't know if there's a
precedent for one extension depending on another.
Post by Jerome Louvel
Back to your original suggestion [1], it still seems to me that solutions
1) and 2) are too broad by working at the Engine level. Each Application
deployed in the same Component could have been developed in different ways
(ex: multitenant hosting), using different DI frameworks and so on. It seems
to me that the Application and the Component classes are the right scope to
define such behavior common to all Restlet and resources they contain, not
the Engine.
OK, sounds reasonable. A portably-written Application that uses DI shouldn't
depend directly on a particular framework -- that's what javax.inject is for
-- but it does no harm to *allow *an Application (or a Component) to do so.
Post by Jerome Louvel
As I think I now clearly understand your feed-back, I’ve done a bit of
** **
- *Factorized* "finderClass" property from Application and Router***
*
into parent Restlet class and added a createFinder(Class)****
method to facilitate instantiation and overriding.****
** **
- Deprecated ServerList.setNext(Class) as it isn't used and its****
logic isn't consistent with similar methods in
Filter/Router.
Thanks, those are good changes!
Post by Jerome Louvel
****
This Is only a first step in the direction of easier DI support. Next one
is to provide similar level of support in Component and the specialized
InternalRouter/VirtualHost classes it contains.
Will look forward to that.
Post by Jerome Louvel
In the thread we also discussed about global DI and application specific DI
all relying on JSR-330. That why I thought that we could provide a more
generic extension based on the JSR-330 standard API. It would have contained
an InjectedApplication. This wasn’t necessary exclusive with having more
specific extensions for Guice and Spring. Actually, we could have a similar
GuiceApplication and SpringApplication class.
Having to provide GuiceApplication and SpringApplication would be admitting
defeat. The goal is to have Applications injected without knowing who's
doing the injecting.

But I don't see a problem here. I'll add InjectedApplication to the
incubator. It will take an optional FinderFactory argument and override
createFinder to use that FinderFactory (if provided) to create the Finder,
otherwise revert to the usual behavior.

No need to mention Guice or Spring, just FinderFactory.

Similarly with Component when you have support for that.

Even better would be to put FinderFactory in the standard Restlet library
and have Application do what InjectedApplication would do (override
createFinder to use FinderFactory, if provided). And if you don't like
passing FinderFactory as a constructor argument, how about via the Context?
Post by Jerome Louvel
****
Also, I’ve just updated the Guice library to version 2.0 in SVN trunk so
that the Guice extension in the incubator compiles again in Eclipse.
Great, but Guice is now on 3.0!

It's OK, though. The incubator code doesn't make use of any 3.0 features.

--tim

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2807287
Thierry Boileau
2011-01-20 17:24:04 UTC
Permalink
Hello Tim,

thanks a lot for your sharp look, I've removed the unnecessary check.

Best regards,
Thierry Boileau


Most recent trunk has defensive code in Finder that looks like it was left
Post by Tim Peierls
public static Finder createFinder(
Class<? extends ServerResource> targetClass,
Class<? extends Finder> finderClass, Context context, Logger
logger) {
Finder result = null;
*if (ServerResource.class.isAssignableFrom(targetClass)) {*
...
} else {
// Log with this warning: "Cannot create a Finder for the given
target class, since
// it is neither a subclass of Resource nor a subclass of
ServerResource."
}
return result;
}
That isAssignableFrom check should always be true now. If it isn't,
someone's trying to subvert the type system. You could either leave out the
check, turn it into an assertion, or at least log it with more severity than
a warning.
--tim
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=7458&dsMessageId=2699396
Loading...