Hello,
I'm having a hard time getting the b17 release running using Tomcat and
Spring. What I am trying to accomplish is the setup as described by
Manohar Viswanathan, but unlike Manohar I am using the B17 release.
This is what I've done so far.
The 'standard' stuff in web.xml. The 'org.restlet.target.class' is set
to 'com.javafabric.jobstoday.ws.rest.util.RestTarget', a class extending
'org.restlet.component.RestletContainer'. The 'handle' method is
overridden. For the sake of readability I've attached the sources files.
Looking at RestTarget you'll notice that on the first handle invocation
a manager bean is retrieved from the Spring context. That manager uses
the RestTarget instance to setup a 'RestletContainerBuilder'.
The following snippet shows how I think the various resources should be
linked to instances of Restlet. This snippet is from the manager's init
method.
RestletContainerBuilder builder = Builders.buildContainer(rootContainer);
for ( ResourceMapping mapping : resourceMappings ) {
Map<String, Restlet> restletMap = mapping.getRestletMap();
for ( String key : restletMap.keySet() ) {
LOG.info(key + "/" + restletMap.get(key));
builder.attachRouter().attach(key, restletMap.get(key));
}
}
Now, assuming that the key has a value of '/vacancy' and the
corresponding map class is an instance of Restlet with a handleGet
method, then an 'http://localhost:8080/ws-rest/vacancy' URL should
invoke the restlet's handleGet method?
I've included the spring configuration file
(ws-rest-application-context.xml). the resource (Vacancy.java), an
overridden RestletContainer (RestTarget.java) and the manager to set up
the restlets and their corresponsind URLs (RestManager.java).
Deployment of this code works like a charm. With the a
'http://localhost:8080/ws-rest' url I notice the invocation of the
handle method of RestTarget. However, Tomcat gives a 405 error; 'The
method specified in the Request-Line is not allowed for the resource
identified by the request URI'. What is it that I do work?
Thank you very much for your time,
Marcel
Resources:
http://manoharviswanathan.com/blog/tech/developing-restful-web-services-in-java/
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<!-- $Id: web.xml 56 2006-06-30 11:38:51Z mgl $ -->
<display-name>JobsToday WS Rest</display-name>
<distributable/>
<context-param>
<param-name>org.restlet.target.class</param-name>
<param-value>com.javafabric.jobstoday.ws.rest.util.RestTarget</param-value>
</context-param>
<!-- Parameter indicating the Servlet attribute to use to store the target Restlet reference -->
<context-param>
<param-name>org.restlet.target.attribute</param-name>
<param-value>org.restlet.target</param-value>
</context-param>
<!-- Parameter indicating the name of an initialization parameter that should be set with the ServerServlet context path -->
<context-param>
<param-name>org.restlet.target.init.contextPath</param-name>
<param-value>contextPath</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:ws-rest-application-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>RestServlet</servlet-name>
<servlet-class>com.noelios.restlet.ext.servlet.ServerServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>RestServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- $Id: $-->
<!-- Restlets -->
<bean id="vacancyRestlet" class="com.javafabric.jobstoday.ws.rest.resource.Vacancy"/>
<!-- Manager: manages mapping of restlets, guard etc -->
<bean id="manager" class="com.javafabric.jobstoday.ws.rest.util.RestManager">
<property name="resourceMappings">
<list>
<bean class="com.javafabric.jobstoday.ws.rest.util.ResourceMapping">
<property name="restletMap">
<bean class="java.util.HashMap">
<constructor-arg>
<map>
<entry key="/vacancy">
<ref local="vacancyRestlet"/>
</entry>
</map>
</constructor-arg>
</bean>
</property>
</bean>
</list>
</property>
</bean>
</beans>/*
*
* Copyright 2004 - 2006 JavaFabric, the Netherlands. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are not permitted.
*
* Neither the name of JavaFabric or the names of contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* JAVAFABRIC AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES OR
* LIABILITIES SUFFERED BY LICENSEE AS A RESULT OF OR RELATING TO USE,
* MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS DERIVATIVES.
* IN NO EVENT WILL JAVAFABRIC OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
* CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
* REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
* OR INABILITY TO USE SOFTWARE, EVEN IF JAVAFABRIC HAS BEEN ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGES.
*/
package com.javafabric.jobstoday.ws.rest.util;
import java.io.Serializable;
import java.util.Map;
import java.util.HashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.restlet.connector.Client;
import org.restlet.component.RestletContainer;
import org.restlet.Restlet;
/**
* TBS
*
* <p><b>Usage:</b><code> N/A</code>
*
* @author <a href="mailto:[EMAIL PROTECTED]">Marcel Schepers</a>
* @version $Id: $
* @since Aug 10, 2006
*/
public class ResourceMapping implements Serializable {
private static final Log LOG = LogFactory.getLog(ResourceMapping.class);
private Map<String, Restlet> restletMap = new HashMap<String, Restlet>();
public Map<String, Restlet> getRestletMap() {
return restletMap;
}
public void setRestletMap(Map<String, Restlet> restletMap) {
this.restletMap = restletMap;
}
}
/*
*
* Copyright 2004 - 2006 JavaFabric, the Netherlands. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are not permitted.
*
* Neither the name of JavaFabric or the names of contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* JAVAFABRIC AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES OR
* LIABILITIES SUFFERED BY LICENSEE AS A RESULT OF OR RELATING TO USE,
* MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS DERIVATIVES.
* IN NO EVENT WILL JAVAFABRIC OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
* CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
* REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
* OR INABILITY TO USE SOFTWARE, EVEN IF JAVAFABRIC HAS BEEN ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGES.
*/
package com.javafabric.jobstoday.ws.rest.util;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.restlet.Restlet;
import org.restlet.component.RestletContainer;
import com.noelios.restlet.build.Builders;
import com.noelios.restlet.build.RestletContainerBuilder;
/**
* TBS
*
* <p><b>Usage:</b><code> N/A</code>
*
* @author <a href="mailto:[EMAIL PROTECTED]">Marcel Schepers</a>
* @version $Id: $
* @since Aug 10, 2006
*/
public class RestManager implements Serializable {
private static final Log LOG = LogFactory.getLog(RestManager.class);
private RestletContainer rootContainer;
private List<ResourceMapping> resourceMappings;
public void init() {
if ( rootContainer == null ) {
throw new RuntimeException("missing required property: 'rootContainer'");
}
if ( resourceMappings == null ) {
throw new RuntimeException("missing required property: 'resourceMappings'");
}
RestletContainerBuilder builder = Builders.buildContainer(rootContainer);
for ( ResourceMapping mapping : resourceMappings ) {
Map<String, Restlet> restletMap = mapping.getRestletMap();
for ( String key : restletMap.keySet() ) {
LOG.info(key + "/" + restletMap.get(key));
builder.attachRouter().attach(key, restletMap.get(key));
}
}
}
public List<ResourceMapping> getResourceMappings() {
return resourceMappings;
}
public void setResourceMappings(List<ResourceMapping> resourceMappings) {
this.resourceMappings = resourceMappings;
}
public RestletContainer getRootContainer() {
return rootContainer;
}
public void setRootContainer(RestletContainer rootContainer) {
this.rootContainer = rootContainer;
}
}
/*
*
* Copyright 2004 - 2006 JavaFabric, the Netherlands. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are not permitted.
*
* Neither the name of JavaFabric or the names of contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* JAVAFABRIC AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES OR
* LIABILITIES SUFFERED BY LICENSEE AS A RESULT OF OR RELATING TO USE,
* MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS DERIVATIVES.
* IN NO EVENT WILL JAVAFABRIC OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
* CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
* REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
* OR INABILITY TO USE SOFTWARE, EVEN IF JAVAFABRIC HAS BEEN ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGES.
*/
package com.javafabric.jobstoday.ws.rest.util;
import java.io.Serializable;
import javax.servlet.ServletContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.restlet.Call;
import org.restlet.component.RestletContainer;
import org.restlet.data.ParameterList;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.noelios.restlet.ext.servlet.ServletCall;
/**
* Component whose main purpose is to contain and manage a set of Restlets (Handlers, Routers or Filters) in order to
* constitue a coherent processing chain for incoming REST calls.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Marcel Schepers</a>
* @version $Id: $
* @since Aug 10, 2006
*/
public class RestTarget extends RestletContainer implements Serializable {
private static final Log LOG = LogFactory.getLog(RestTarget.class);
private volatile boolean initialized = false;
public RestTarget() {
}
@Override
public void handle(Call call) {
if ( !this.initialized ) {
try {
// Get servlet context.
ServletCall servletCall = (ServletCall) call.getConnectorCall();
ServletContext servletContext = servletCall.getContext();
WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(servletContext);
ParameterList parameters = getParameters();
String contextPath = parameters.getValues("contextPath");
if ( LOG.isInfoEnabled() ) {
LOG.info("contextPath: " + contextPath);
}
RestManager manager = (RestManager) wac.getBean("manager");
manager.setRootContainer(this);
manager.init();
start();
this.initialized = true;
} catch ( Exception e ) {
LOG.error(e);
}
}
super.handle(call);
}
}
/*
*
* Copyright 2004 - 2006 JavaFabric, the Netherlands. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are not permitted.
*
* Neither the name of JavaFabric or the names of contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
* JAVAFABRIC AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES OR
* LIABILITIES SUFFERED BY LICENSEE AS A RESULT OF OR RELATING TO USE,
* MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS DERIVATIVES.
* IN NO EVENT WILL JAVAFABRIC OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
* CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
* REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
* OR INABILITY TO USE SOFTWARE, EVEN IF JAVAFABRIC HAS BEEN ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGES.
*/
package com.javafabric.jobstoday.ws.rest.resource;
import java.io.Serializable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.restlet.AbstractRestlet;
import org.restlet.Call;
import org.restlet.data.MediaTypes;
import com.noelios.restlet.data.StringRepresentation;
/**
* TBS
*
* <p><b>Usage:</b><code> N/A</code>
*
* @author <a href="mailto:[EMAIL PROTECTED]">Marcel Schepers</a>
* @version $Id: $
* @since Aug 10, 2006
*/
public class Vacancy extends AbstractRestlet implements Serializable {
private static final Log LOG = LogFactory.getLog(Vacancy.class);
public void handleGet(Call call) {
call.setOutput(new StringRepresentation("Vacancy", MediaTypes.TEXT_PLAIN));
}
}