<!-- Safari Services -->
<bean id='travelService' class='com.safari.core.travel.TravelService'/>
<bean id='identityService' class='com.safari.core.travel.IdentityService'/
package com.safari.core.travel;
import com.safari.core.SafariContext;
import java.util.ArrayList;
import java.util.List;
/**
* In memory service for demo and testing purposes
*/
public class IdentityService {
public static final String MANAGER = 'manager';
public static final String CUSTOMER = 'customer';
public boolean authenticate(String username, String password) {
// Perform simple example authentication
if (username.equals(password)) {
SafariContext.setCurrentUser(username);
return true;
}
return false;
}
public List<String> getUsers() {
List<String> users = new ArrayList<String>();
users.add('erik'); // A registered customer
users.add('roy'); // Sales manager for the company who sometimes buy trips
return users;
}
public List<String> getGroups(String user) {
List<String> groups = new ArrayList<String>();
if (user.equals('erik')) {
groups.add(CUSTOMER);
}
else if (user.equals('roy')) {
groups.add(MANAGER);
groups.add(CUSTOMER);
}
return groups;
}
}
package com.safari.core;
public abstract class SafariContext {
static ThreadLocal<String> authenticatedUserNameThreadLocal = new ThreadLocal<String>();
public static void setCurrentUser(String userName) {
authenticatedUserNameThreadLocal.set(userName);
}
public static String getCurrentUser() {
return authenticatedUserNameThreadLocal.get();
}
}
<!-- Spring WebScripts -->
<servlet>
<servlet-name>WebScriptServlet</servlet-name>
<servlet-class>org.springframework.extensions.webscripts.servlet.WebScriptServlet</servlet-class>
<init-param>
<param-name>authenticator</param-name>
<param-value>webscripts.authenticator.safari</param-value>
</init-param>
</servlet>
package com.safari.rest.auth;
import com.safari.core.travel.IdentityService;
import org.springframework.extensions.webscripts.AbstractBasicHttpAuthenticatorFactory;
import org.springframework.extensions.webscripts.Description;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;
import java.util.ArrayList;
import java.util.List;
public class SafariBasicHttpAuthenticatorFactory extends AbstractBasicHttpAuthenticatorFactory
{
private IdentityService identityService;
/**
* The Safari Identity Service which will perform the authentication.
*
* @param identityService The safari identity service
*/
public void setIdentityService(IdentityService identityService) {
this.identityService = identityService;
}
/**
* Performs an authentication check using the Identity Service.
*
* @param username The username of the user
* @param password THe password the user tries to log in with
* @return true if the username and pass word matched a user in the system
*/
public boolean doAuthenticate(String username, String password) {
return identityService.authenticate(username, password);
}
/**
* Translate the logged in users groups with the WebScript security
* role model and decide if user is allowed to execute the WebScript.
*
* @param username The username of the logged in user
* @param role The authority role that is required for the user to execute the webscript
* @return true if user is authorized to execute the WebScript
*/
public boolean doAuthorize(String username, Description.RequiredAuthentication role)
{
List<String> grantedGroupIds = new ArrayList<String>();
if (role == Description.RequiredAuthentication.user) {
/**
* This method is called after doAuthenticate which means
* the login was successful and the request was done by a user.
*/
grantedGroupIds.add(IdentityService.CUSTOMER);
}
else if (role == Description.RequiredAuthentication.admin) {
// Check if user is member of the admin group.
grantedGroupIds.add(IdentityService.MANAGER);
}
if (grantedGroupIds.size() == 0) {
// No group membership is required for the user.
return true;
}
else {
// Certain group membership is required user.
List<String> userGroups = identityService.getGroups(username);
for (String group : userGroups)
{
for (String grantedGroupId : grantedGroupIds) {
if (group.equals(grantedGroupId)) {
return true;
}
}
}
}
return false;
}
}
<!-- Add authentication and authorization support for webscripts (used by the WebScriptServlet) -->
<bean id='webscripts.authenticator.safari' class='com.safari.rest.auth.SafariBasicHttpAuthenticatorFactory'>
<property name='identityService' ref='identityService'/>
</bean>
<!--
Temporary include the 'spring-surf' artifact to get the AbstractBasicHttpAuthenticatorFactory.
When updating to RC2 or the final 1.0.0 release it will have moved to 'spring-webscripts'.
-->
<dependency>
<groupId>org.springframework.extensions.surf</groupId>
<artifactId>spring-surf</artifactId>
<version>1.0.0-RC1</version>
</dependency>
<!-- Include the Spring WebScripts runtime -->
<dependency>
<groupId>org.springframework.extensions.surf</groupId>
<artifactId>spring-webscripts</artifactId>
<version>1.0.0-RC1</version>
</dependency>
<!-- Include the Spring WebScript API so we can browse and list our webscripts on the server -->
<dependency>
<groupId>org.springframework.extensions.surf</groupId>
<artifactId>spring-webscripts-api</artifactId>
<version>1.0.0-RC1</version>
</dependency>
mvn -f safari-root/pom.xml clean install org.codehaus.mojo:tomcat-maven-plugin:1.0-beta-1:redeploy
public class SafariBasicHttpAuthenticatorFactoryWithSession extends AbstractBasicHttpAuthenticatorFactory
{
...
// Add a place to store the request and response when the authenticator is created
private WebScriptRequest req;
private WebScriptResponse res;
...
@Override
public Authenticator create(WebScriptServletRequest req, WebScriptServletResponse res)
{
// Override the create method so we get a change to store the request & response
this.req = req;
this.res = res;
return new BasicHttpAuthenticator(req, res);
}
@Override
public boolean doAuthenticate(String username, String password) {
if (identityService.authenticate(username, password)) {
// ...so we can access the HttpSession after a successful login
this.req.getHttpServletRequest().getSession().setAttribute('safari.username', username);
return true;
}
return false;
}
...
}
public class SafariWebScriptWithSessionGet extends SafariWebScript
{
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache) {
String bar = (String) ((WebScriptServletRequest)req).getHttpServletRequest().getSession().getAttribute('safari.username');
…
}
}
package com.safari.core.travel;
public class Booking {
private int id;
private String username;
private Trip trip;
public Booking () {}
public int getId(){ return id; }
public void setId(int id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public Trip getTrip() { return trip; }
public void setTrip(Trip trip) { this.trip = trip; }
}
package com.safari.core.travel;
import com.safari.core.SafariContext;
import java.util.ArrayList;
import java.util.List;
/**
* In memory service for testing purposes
*/
public class TravelService {
private static int tripIndex = 0;
private static List<Trip> trips = new ArrayList<Trip>();
private static List<Booking> bookings = new ArrayList<Booking>();
public TravelService() {
// Bootstrap data
trips.add(new Trip(++tripIndex, 'Masai Mara Adventurer'));
trips.add(new Trip(++tripIndex, 'Serengeti Explorer'));
trips.add(new Trip(++tripIndex, 'Kruger Wildlife'));
}
/**
* Returns a public list of all available trips
*
* @return a list of trips
*/
public List<Trip> getTrips() {
return trips;
}
/**
* Finds a trip by id
*
* @param tripId The trip id to look for
* @return the trip if found otherwise null
*/
public Trip getTrip(int tripId) {
// Find the trip
for (Trip trip : trips) {
if (trip.getId() == tripId) {
return trip;
}
}
return null;
}
/**
* Administration method to create new trips
*
* @param trip The trip to create
* @return The created trip with a unique id
*/
public Trip createTrip(Trip trip) {
// Give trip a unique id and add it
trip.setId(++tripIndex);
trips.add(trip);
return trip;
}
/**
* Lets the current user create a booking for a certain trip
*
* @param tripId The trip to create a booking for
*/
public Booking createBooking(int tripId) {
// Check that the trip exists
Trip trip = getTrip(tripId);
if (trip == null) {
throw new IllegalArgumentException('Cannot book trip with id '' + tripId + '' since it doesn't exist');
}
// Create booking and return it
Booking booking = new Booking();
booking.setTrip(trip);
booking.setUsername(SafariContext.getCurrentUser());
bookings.add(booking);
return booking;
}
/**
* Returns a list of the current users bookings
*/
public List<Booking> getBookings() {
List<Booking> userBookings = new ArrayList<Booking>();
for (Booking booking : bookings) {
if (booking.getUsername().equals(SafariContext.getCurrentUser())) {
userBookings.add(booking);
}
}
return userBookings;
}
}
<webscript>
<shortname>Create Trip</shortname>
<description>Creates a trip</description>
<url>/travel/trip</url>
<format default='json'>argument</format>
<authentication>admin</authentication>
</webscript>
package com.safari.rest.api.travel;
import com.safari.core.travel.Trip;
import com.safari.rest.api.SafariWebScript;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
import java.util.HashMap;
import java.util.Map;
public class TripPost extends SafariWebScript
{
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache) {
try {
JSONObject json = new JSONObject(req.getContent().getContent());
Trip trip = new Trip();
trip.setName(json.getString('name'));
trip = getTravelService().createTrip(trip);
Map<String, Object> model = new HashMap<String, Object>();
model.put('trip', trip);
return model;
}
catch (JSONException e) {
throw new WebScriptException(Status.STATUS_BAD_REQUEST, 'The request body contains badly formatted json');
} catch (Exception e) {
throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR, 'Trip could not be created: ' + e.getMessage());
}
}
}
<#escape x as jsonUtils.encodeJSONString(x)>
{
'id': ${trip.id},
'name': '${trip.name}'
}
</#escape>
<webscript>
<shortname>Create Booking</shortname>
<description>Creates a booking</description>
<url>/travel/booking</url>
<format default='json'>argument</format>
<authentication>user</authentication>
</webscript>
package com.safari.rest.api.travel;
import com.safari.core.travel.Booking;
import com.safari.rest.api.SafariWebScript;
import org.json.JSONObject;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
import java.util.HashMap;
import java.util.Map;
public class BookingPost extends SafariWebScript
{
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
{
// Make sure tripId is a number and create the booking
try {
JSONObject json = new JSONObject(req.getContent().getContent());
Booking booking = getTravelService().createBooking(json.getInt('tripId'));
Map<String, Object> model = new HashMap<String, Object>();
model.put('booking', booking);
return model;
}
catch (NumberFormatException nfe) {
throw new WebScriptException(Status.STATUS_BAD_REQUEST, 'Parameter tripId is mandatory and must contain an integer value');
} catch (Exception e) {
throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR, 'Trip could not be booked: ' + e.getMessage());
}
}
}
<#escape x as jsonUtils.encodeJSONString(x)>
{
'id': ${booking.id},
'username': '${booking.username}',
'trip': {
'id': '${booking.trip.id}',
'name': '${booking.trip.name}'
}
}
</#escape>
<webscript>
<shortname>List User's Bookings</shortname>
<description>Lists the logged in user's bookings</description>
<url>/travel/bookings</url>
<format default='json'>argument</format>
<authentication>user</authentication>
</webscript>
package com.safari.rest.api.travel;
import com.safari.rest.api.SafariWebScript;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptRequest;
import java.util.HashMap;
import java.util.Map;
public class BookingsGet extends SafariWebScript
{
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
{
// Create the template model and fill it with trips
Map<String, Object> model = new HashMap<String, Object>();
model.put('bookings', getTravelService().getBookings());
return model;
}
}
<#escape x as jsonUtils.encodeJSONString(x)>
[<#list bookings as booking>
{
'id': ${booking.id},
'username': '${booking.username}',
'trip': {
'id': '${booking.trip.id}',
'name': '${booking.trip.name}'
}
}<#if booking_has_next>,</#if>
</#list>]
</#escape>
<!-- Safari WebScripts / REST API calls (id follows pattern with 'webscript.' + package + webscript name + method -->
<bean id='webscript.com.safari.travel.trips.get'
class='com.safari.rest.api.travel.TripsGet'
parent='safariWebscript'>
</bean>
<bean id='webscript.com.safari.travel.trip.post'
class='com.safari.rest.api.travel.TripPost'
parent='safariWebscript'>
</bean>
<bean id='webscript.com.safari.travel.booking.post'
class='com.safari.rest.api.travel.BookingPost'
parent='safariWebscript'>
</bean>
<bean id='webscript.com.safari.travel.bookings.get'
class='com.safari.rest.api.travel.BookingsGet'
parent='safariWebscript'>
</bean>
mvn -f safari-root/pom.xml clean install org.codehaus.mojo:tomcat-maven-plugin:1.0-beta-1:redeploy
POST http://localhost:8080/safari-rest/service/travel/trip
{
'name': 'Spring Safari'
}
{
'id': 4,
'name': 'Spring Safari'
}
GET http://localhost:8080/safari-rest/service/travel/trips
POST http://localhost:8080/safari-rest/service/travel/booking
{
'tripId': 4
}
{
'id': 0,
'username': 'roy',
'trip': {
'id': 4,
'name': 'Spring Safari'
}
}
GET http://localhost:8080/safari-rest/service/travel/bookings
[
{
'id': 0,
'username': 'roy',
'trip': {
'id': 4,
'name': 'Spring Safari'
}
}
]
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.