/*******************************************************************************
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
package org.spiffyui.spiffyforms.server;
import java.net.URI;
import java.util.Iterator;
import java.util.logging.Logger;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* This class supports our REST endpoint for getting user data, updating users,
* creating new users, and deleting existing users. It serves at /user/{userid}.
*/
@Path("/users/{arg1}")
public class User
{
private static final Logger LOGGER = Logger.getLogger(User.class.getName());
static private final String RESULT_SUCCESS = "{\"result\" : \"success\"}";
static private final String USER_NOT_FOUND = "Userid not found: ";
@Context
UriInfo uriInfo;
// this Java method finds a particular user in the list of users
private static JSONObject findUserInArray(String userID)
{
JSONArray users = Users.getUserList();
if (users == null)
return null;
int len = users.length();
try {
for (int i = 0; i < len; i++) {
if (!users.isNull(i) && userID.equals(users.getJSONObject(i).getString("userID"))) {
// found it!
return users.getJSONObject(i);
}
}
} catch (JSONException je) {
LOGGER.throwing(User.class.getName(), "findUserInArray", je);
}
// if we got here then we didn't find it
return null;
}
// this Java method finds a particular user in the list of users
private static int findUserIndexInArray(String userID)
{
JSONArray users = Users.getUserList();
if (users == null)
return -1;
int len = users.length();
try {
for (int i = 0; i < len; i++) {
if (!users.isNull(i) && userID.equals(users.getJSONObject(i).getString("userID"))) {
// found it!
return i;
}
}
} catch (JSONException je) {
LOGGER.throwing(User.class.getName(), "findUserIndexArray", je);
}
// if we got here then we didn't find it
return -1;
}
/**
* Get details about the specified user or return a 404 if the user isn't found.
*/
@GET
@Produces("application/json")
public String getUserInfo()
{
MultivaluedMap<String, String> params = uriInfo.getPathParameters();
String userid = params.getFirst("arg1");
// we know that userid is not null because of the @path annotation
JSONObject user = findUserInArray(userid);
if (user == null) {
throw buildException(Response.Status.NOT_FOUND, USER_NOT_FOUND + userid);
}
return user.toString();
}
/**
* This method handles creating new users on the server.
*
* @param input a JSON string containing information about the new user
*
* @return a success message indicating the new user was added or an error
* message indicating why the weren't
*/
@POST
@Produces("application/JSON")
public Response createUser(String input)
{
MultivaluedMap<String, String> params = uriInfo.getPathParameters();
String userID = params.getFirst("arg1");
// we know that userID is not null because of the Path annotation
Response.ResponseBuilder rb;
// userids can't have spaces
if (userID.indexOf(' ') != -1) {
throw buildException(Response.Status.BAD_REQUEST, "UserIDs cannot have spaces. UserID: " + userID);
}
// do we already have this user?
if (findUserInArray(userID) != null) {
throw buildException(Response.Status.NOT_FOUND, USER_NOT_FOUND + userID);
}
try {
JSONArray userList = Users.getUserList();
if (userList != null) {
userList.put(new JSONObject(input));
}
} catch (JSONException je) {
LOGGER.throwing(User.class.getName(), "createUser", je);
// input string was probably not correctly formatted JSON.
throw buildException(Response.Status.BAD_REQUEST, "Could not parse JSON data: " + input);
}
rb = Response.created(URI.create(userID));
rb.entity(RESULT_SUCCESS);
return rb.build();
}
/**
* This method updates the information about the specified user.
*
* @param input a string of JSON containing the updated information about the user
*
* @return the response to the client indicating that the user was successfully
* updated or that the user couldn't be found
*/
@PUT
@Produces("application/json")
public String updateUser(String input)
{
MultivaluedMap<String, String> params = uriInfo.getPathParameters();
String userID = params.getFirst("arg1");
// we know userID is non-null
JSONObject storedUser = findUserInArray(userID);
if (storedUser != null) {
try {
JSONObject inputUser = new JSONObject(input);
Iterator iter = inputUser.keys();
while (iter.hasNext()) {
String key = (String) iter.next();
storedUser.put(key, inputUser.get(key));
}
} catch (JSONException je) {
LOGGER.throwing(User.class.getName(), "updateUser", je);
// generic error
throw buildException(Response.Status.BAD_REQUEST, "Could not modify user info: " + userID);
}
} else {
throw buildException(Response.Status.NOT_FOUND, USER_NOT_FOUND + userID);
}
return RESULT_SUCCESS;
}
/**
* This method deletes the specified user from the server. If the user is found then
* we return a 200 and a simple success response. If the user is not found then we
* return a 404 and a specific error message.
*
* @return the response for the client
*/
@DELETE
@Produces("application/JSON")
public String deleteUser()
{
MultivaluedMap<String, String> params = uriInfo.getPathParameters();
String userID = params.getFirst("arg1");
// we know userID is non-null
int i = findUserIndexInArray(userID);
if (i != -1) { // -1 means not found
JSONArray userList = Users.getUserList();
try {
userList.put(i, (Object) null);
} catch (JSONException je) {
LOGGER.throwing(User.class.getName(), "deleteUser", je);
}
return "{\"success\":true}";
} else {
throw buildException(Response.Status.NOT_FOUND, USER_NOT_FOUND + userID);
}
}
/*
* Private methods
*/
private static WebApplicationException buildException(Response.Status code, String reason)
{
Response r = buildErrorResponse(code, reason);
return new WebApplicationException(r);
}
/**
* This method builds a JSON error response in the specific format Spiffy knows how to
* deal with. You don't have to use this error format, but it makes your application
* easier if you do.
*
* @param code the main error code
* @param reason the reason for the error
* @return a response containing the error
*/
private static Response buildErrorResponse(Response.Status code, String reason)
{
JSONObject root = null;
Response.ResponseBuilder rb = Response.status(code);
try {
JSONObject r = new JSONObject();
r.put("Text", reason);
JSONObject subcode = new JSONObject();
subcode.put("Value", "0");
JSONObject c = new JSONObject();
c.put("Subcode", subcode);
c.put("Value", code);
JSONObject f = new JSONObject();
f.put("Code", c);
f.put("Reason", r);
root = new JSONObject();
root.put("Fault", f);
} catch (JSONException je) {
LOGGER.throwing(User.class.getName(), "buildErrorResponse", je);
}
if (root != null) {
rb.entity(root.toString());
}
return rb.build();
}
}