// Copyright 2011 Google Inc. All Rights Reserved.
package com.google.appengine.tools.mapreduce.impl.handlers;
import com.google.appengine.api.datastore.Cursor;
import com.google.appengine.tools.mapreduce.impl.MapperStateEntity;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.logging.Level;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* UI Status view logic handler.
*
*/
final class StatusHandler {
// --------------------------- STATIC FIELDS ---------------------------
public static final int DEFAULT_JOBS_PER_PAGE_COUNT = 50;
// Command paths
public static final String LIST_JOBS_PATH = "list_jobs";
public static final String LIST_CONFIGS_PATH = "list_configs";
public static final String CLEANUP_JOB_PATH = "cleanup_job";
public static final String ABORT_JOB_PATH = "abort_job";
public static final String GET_JOB_DETAIL_PATH = "get_job_detail";
public static final String START_JOB_PATH = "start_job";
// --------------------------- CONSTRUCTORS ---------------------------
private StatusHandler() {
}
// -------------------------- STATIC METHODS --------------------------
/**
* Handle the cleanup_job AJAX command.
*/
private static JSONObject handleCleanupJob(String jobId) throws JSONException {
JSONObject retValue = new JSONObject();
MapperStateEntity<?, ?, ?, ?> state = MapperStateEntity.getMapReduceStateFromJobID(jobId);
if (state == null) {
retValue.put("status", "Couldn't find requested job.");
} else {
state.delete();
retValue.put("status", "Successfully deleted requested job.");
}
return retValue;
}
/**
* Handles all status page commands.
*/
static void handleCommand(
String command, HttpServletRequest request, HttpServletResponse response) {
response.setContentType("application/json");
boolean isPost = "POST".equals(request.getMethod());
JSONObject retValue;
try {
if (command.equals(LIST_CONFIGS_PATH) && !isPost) {
retValue = handleListConfigs();
} else if (command.equals(LIST_JOBS_PATH) && !isPost) {
retValue = handleListJobs(request);
} else if (command.equals(CLEANUP_JOB_PATH) && isPost) {
retValue = handleCleanupJob(request.getParameter("mapreduce_id"));
} else if (command.equals(ABORT_JOB_PATH) && isPost) {
retValue = ControllerHandler.handleAbortJob(request.getParameter("mapreduce_id"));
} else if (command.equals(GET_JOB_DETAIL_PATH) && !isPost) {
retValue = handleGetJobDetail(request.getParameter("mapreduce_id"));
} else if (command.equals(START_JOB_PATH) && isPost) {
retValue = handleStartJob();
} else {
response.sendError(404);
return;
}
} catch (Throwable t) {
MapReduceServletImpl.LOG.log(Level.SEVERE, "Got exception while running command", t);
try {
retValue = new JSONObject();
retValue.put("error_class", t.getClass().getName());
retValue.put("error_message",
"Full stack trace is available in the server logs. Message: "
+ t.getMessage());
} catch (JSONException e) {
throw new RuntimeException("Couldn't create error JSON object", e);
}
}
try {
retValue.write(response.getWriter());
response.getWriter().flush();
} catch (JSONException e) {
throw new RuntimeException("Couldn't write command response", e);
} catch (IOException e) {
throw new RuntimeException("Couldn't write command response", e);
}
}
/**
* Handle the get_job_detail AJAX command.
*/
private static JSONObject handleGetJobDetail(String jobId) {
MapperStateEntity<?, ?, ?, ?> state = MapperStateEntity.getMapReduceStateFromJobID(jobId);
if (state == null) {
throw new IllegalArgumentException("Couldn't find MapReduce for id:" + jobId);
}
return state.toJson(true);
}
private static JSONObject handleListConfigs() {
return new JSONObject();
}
private static JSONObject handleListJobs(HttpServletRequest request) throws JSONException {
String cursor = request.getParameter("cursor");
String countString = request.getParameter("count");
int count = DEFAULT_JOBS_PER_PAGE_COUNT;
if (countString != null) {
count = Integer.parseInt(countString);
}
return handleListJobs(cursor, count);
}
/**
* Handle the list_jobs AJAX command.
*/
private static JSONObject handleListJobs(String cursor, int count) throws JSONException {
Collection<MapperStateEntity<?, ?, ?, ?>> states = new ArrayList<MapperStateEntity<?, ?, ?, ?>>();
Cursor newCursor = MapperStateEntity.getMapReduceStates(cursor, count, states);
JSONArray jobs = new JSONArray();
for (MapperStateEntity<?, ?, ?, ?> state : states) {
jobs.put(state.toJson(false));
}
JSONObject retValue = new JSONObject();
retValue.put("jobs", jobs);
if (newCursor != null) {
retValue.put("cursor", newCursor.toWebSafeString());
}
return retValue;
}
private static JSONObject handleStartJob() {
throw new UnsupportedOperationException("handleStartJob is not implemented.");
}
}