Tom, thanks for your additional input into Restlet/Spring
integration. I too am looking for "the" solution.
So far, I take a slightly different approach and use Spring's
ApplicationContext as my Resource factory.
I've created SpringApplicationContext as an extension of
com.noelios.restlet.application.ApplicationContext and expose the
Spring ApplicationContext as a property. I extended Finder as
SpringFinder. Its createResource method looks as such:
@Override
public Resource createResource(final Request request, final Response
response) {
ApplicationContext springContext = ((SpringApplicationContext)
this.getContext()).getSpringApplicationContext();
Resource resource = (Resource) BeanFactoryUtils.beanOfType
(springContext, getTargetClass());
resource.init(getContext(), request, response);
return resource;
}
I get the Spring ApplicationContext from the Finder's (Restlet)
context and then look for a resource bean there by type. So
essentially, my Spring ApplicationContext is my resource factory. For
example,
<bean id="userResource" class="net.troove.ui.restlet.UserResource"
singleton="false">
<property name="userDao" ref="userDao"/>
<!-- Other collaborators here -->
</bean>
<bean id="userDao" class="net.troove.test.SimpleUserDao"
singleton="true" />
where net.troove.ui.restlet.UserResource extends
org.restlet.resource.Resource.
Because resources are request-scoped, you have to make sure they
declare singleton="false".
Comments/criticism would be much appreciated.
Justin
--
troove Inc.
http://troove.net/
(877) 330-8504
"The troove appliance -- enterprising find"
On Sep 4, 2007, at 2:56 PM, Tom McGee wrote:
I need more ability to configure and/or define restlet classes
(Component, Route, Router, Application, Filter, Resource and Restlet)
with spring. I think I have a spring framework addiction :-)
There is something of an architectural mismatch between the restlets
framework and the spring framework. With spring the way it works best
to let the spring container create and configure object instances.
The context for object instance is injected by spring. With restlets
the context is passed throw the applications object instances with a
chain of constructors.
To get around this I'm not using spring to create the restlets class
instances directly. Instead I use spring to create factories that
make the instances. For example here's a Resource factory:
public abstract class ResourceFactory extends Finder {
public Resource createResource(Request request, Response
response) {
Resource result = build();
result.init(getContext(), request, response);
return result;
}
public abstract Resource build();
}
public class PlayRestResourceFactory extends ResourceFactory
implements RouteCallback, UriPatternProvider{
@Override
public Resource build() {
return new Resource(){
private String testname;
@Override
public void init(Context context, Request request, Response
response) {
super.init(context, request, response);
testname = (String)
request.getAttributes().get("testname");
this.getVariants().add(new
Variant(MediaType.TEXT_PLAIN));
}
@Override
public Representation getRepresentation(Variant
variant) {
return new StringRepresentation(testname+" "+playBean.getMessage
());
}
};
}
private PlayBean playBean;
public void setPlayBean(PlayBean playBean) {
this.playBean = playBean;
}
public void routeCallback(Route r) {
System.out.println("PlayRestResourceFactory::routeCallback");
}
public String getUriPattern() {
return "/test3/tom_{testname}";
}
}
I have factory objects for Application, Filter, Resource, Restlet
and Router.
Where I could not control the creation of objects with factories I've
added callback objects to at least give access to configure. Here's
the callback a Component:
public class PlayComponentCallback implements ComponentCallback {
public void componentCallback(Component c) {
c.setLogService(new LogService(false));
}
}
I have callbacks for Component, Route and Router.
I have extended ServerServlet use these new classes:
public class SpringRestletServlet extends ServerServlet {
private static final long serialVersionUID = 2974584650224678065L;
// init param name of spring bean name for component callback
private static final String COMPONENT_CALLBACK_INIT_PARAM =
"lazyeye.restlet.spring.servlet.SpringRestletServlet.componentCallback
";
// init param name of spring bean name for application factory
private static final String APPLICATION_FACTORY_INIT_PARAM =
"lazyeye.restlet.spring.servlet.SpringRestletServlet.applicationFactor
y";
// default value of spring bean name for component callback
private static final String COMPONENT_CALLBACK_DEFAULT =
"restletComponentCallback";
// default value of spring bean name for application factory
private static final String APPLICATION_FACTORY_DEFAULT =
"restletApplicationFactory";
private String componentCallbackId;
private String applicationFactoryId;
/*
* reads the init parameters for component callback and
application factory
* then does parent init() and then send the the component to the
component
* callback.
*
* @see com.noelios.restlet.ext.servlet.ServerServlet#init()
*/
public void init() throws ServletException {
componentCallbackId =
this.getInitParameter
(COMPONENT_CALLBACK_INIT_PARAM,COMPONENT_CALLBACK_DEFAULT);
applicationFactoryId =
this.getInitParameter
(APPLICATION_FACTORY_INIT_PARAM,APPLICATION_FACTORY_DEFAULT);
super.init();
// Look to see if there is a ComponentCallback object defined for
this
// SpringRestletServlet instance and call it if it's there.
if ((getSpringContext() != null)
&&
(getSpringContext().containsBean(componentCallbackId))) {
ComponentCallback componentCallback = (ComponentCallback)
getSpringContext()
.getBean(componentCallbackId);
componentCallback.componentCallback(this.getComponent());
}
}
private ApplicationContext springContext;
/**
* @return spring application context
*/
public ApplicationContext getSpringContext() {
if (springContext == null) {
springContext = WebApplicationContextUtils
.getWebApplicationContext(this.getServletContext());
}
return springContext;
}
/*
* This is an overwrite of the parent method. Now the Application is
created using
* a an ApplicationFactory object obtained from the Spring
application context.
*
* @see
com.noelios.restlet.ext.servlet.ServerServlet#createApplication
(org.restlet.Context)
*/
public Application createApplication(Context context) {
Application result = null;
if ((getSpringContext() != null)
&&
(getSpringContext().containsBean(applicationFactoryId))) {
ApplicationFactory applicationFactory =
(ApplicationFactory)
getSpringContext()
.getBean(applicationFactoryId);
result = applicationFactory.build(context);
}
if (result == null) {
result = super.createApplication(context);
}
return result;
}
}
None of this has been fully tested yet but I want to share what I've
done so far with the hope that I might get your opinions.
<ComponentCallback.java>
<RouteCallback.java>
<RouterCallback.java>
<ApplicationFactory.java>
<ApplicationFactoryImp.java>
<FilterFactory.java>
<ResourceFactory.java>
<RestletFactory.java>
<RouterFactory.java>
<RouterFactoryImp.java>
<UriPatternProvider.java>
<SpringRestletServlet.java>