001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.reef.examples.scheduler.driver.http; 020 021import org.apache.reef.examples.scheduler.driver.SchedulerDriver; 022import org.apache.reef.examples.scheduler.driver.exceptions.NotFoundException; 023import org.apache.reef.examples.scheduler.driver.exceptions.UnsuccessfulException; 024import org.apache.reef.tang.InjectionFuture; 025import org.apache.reef.webserver.HttpHandler; 026import org.apache.reef.webserver.ParsedHttpRequest; 027 028import javax.inject.Inject; 029import javax.servlet.ServletException; 030import javax.servlet.http.HttpServletResponse; 031import java.io.IOException; 032import java.util.List; 033import java.util.Map; 034 035/** 036 * Receive HttpRequest so that it can handle the command list. 037 */ 038public final class SchedulerHttpHandler implements HttpHandler { 039 private final InjectionFuture<SchedulerDriver> schedulerDriver; 040 041 private String uriSpecification = "reef-example-scheduler"; 042 043 @Inject 044 private SchedulerHttpHandler(final InjectionFuture<SchedulerDriver> schedulerDriver) { 045 this.schedulerDriver = schedulerDriver; 046 } 047 048 @Override 049 public String getUriSpecification() { 050 return uriSpecification; 051 } 052 053 @Override 054 public void setUriSpecification(final String s) { 055 uriSpecification = s; 056 } 057 058 /** 059 * HttpRequest handler. You must specify UriSpecification and API version. 060 * The request url is http://{address}:{port}/scheduler/v1 061 * 062 * APIs 063 * /list to get the status list for all tasks 064 * /status?id={id} to query the status of such a task, given id 065 * /submit?cmd={cmd} to submit a Task, which returns its id 066 * /cancel?id={id} to cancel the task's execution 067 * /max-eval?num={num} to set the maximum number of evaluators 068 * /clear to clear the waiting queue 069 */ 070 @Override 071 public void onHttpRequest(final ParsedHttpRequest request, final HttpServletResponse response) 072 throws IOException, ServletException { 073 final String target = request.getTargetEntity().toLowerCase(); 074 final Map<String, List<String>> queryMap = request.getQueryMap(); 075 076 final SchedulerResponse result; 077 switch (target) { 078 case "list": 079 result = onList(); 080 break; 081 case "clear": 082 result = onClear(); 083 break; 084 case "status": 085 result = onStatus(queryMap); 086 break; 087 case "submit": 088 result = onSubmit(queryMap); 089 break; 090 case "cancel": 091 result = onCancel(queryMap); 092 break; 093 case "max-eval": 094 result = onMaxEval(queryMap); 095 break; 096 default: 097 result = SchedulerResponse.notFound("Unsupported operation"); 098 } 099 100 // Send response to the http client 101 final int status = result.getStatus(); 102 final String message= result.getMessage(); 103 104 if (result.isOK()) { 105 response.getOutputStream().println(message); 106 } else { 107 response.sendError(status, message); 108 } 109 } 110 111 private SchedulerResponse onList() { 112 final Map<String, List<Integer>> listMap = schedulerDriver.get().getList(); 113 114 final StringBuilder sb = new StringBuilder(); 115 for (final Map.Entry<String, List<Integer>> entry : listMap.entrySet()) { 116 sb.append("\n").append(entry.getKey()).append(" :"); 117 for (final int taskId : entry.getValue()) { 118 sb.append(" ").append(taskId); 119 } 120 } 121 return SchedulerResponse.ok(sb.toString()); 122 } 123 124 private SchedulerResponse onClear() { 125 final int count = schedulerDriver.get().clearList(); 126 return SchedulerResponse.ok(count + " tasks removed."); 127 } 128 129 private SchedulerResponse onStatus(final Map<String, List<String>> queryMap) { 130 final List<String> args = queryMap.get("id"); 131 if (args.size() != 1) { 132 return SchedulerResponse.badRequest("Usage : only one ID at a time"); 133 } 134 135 try { 136 137 final int taskId = Integer.parseInt(args.get(0)); 138 return SchedulerResponse.ok(schedulerDriver.get().getTaskStatus(taskId)); 139 140 } catch (final NotFoundException e) { 141 return SchedulerResponse.notFound(e.getMessage()); 142 } catch (final NumberFormatException e) { 143 return SchedulerResponse.badRequest("Usage : ID must be an integer"); 144 } 145 } 146 147 private SchedulerResponse onSubmit(final Map<String, List<String>> queryMap) { 148 final List<String> args = queryMap.get("cmd"); 149 if (args.size() != 1) { 150 return SchedulerResponse.badRequest("Usage : only one command at a time"); 151 } 152 153 return SchedulerResponse.ok("Task ID : " + schedulerDriver.get().submitCommand(args.get(0))); 154 } 155 156 private SchedulerResponse onCancel(final Map<String, List<String>> queryMap) { 157 final List<String> args = queryMap.get("id"); 158 if (args.size() != 1) { 159 return SchedulerResponse.badRequest("Usage : only one ID at a time"); 160 } 161 162 try { 163 164 final int taskId = Integer.parseInt(args.get(0)); 165 final int canceledId = schedulerDriver.get().cancelTask(taskId); 166 return SchedulerResponse.ok("Canceled " + canceledId); 167 168 } catch (final NotFoundException e) { 169 return SchedulerResponse.notFound(e.getMessage()); 170 } catch (final UnsuccessfulException e) { 171 return SchedulerResponse.forbidden(e.getMessage()); 172 } catch (final NumberFormatException e) { 173 return SchedulerResponse.badRequest("Usage : ID must be an integer"); 174 } 175 } 176 177 private SchedulerResponse onMaxEval(final Map<String, List<String>> queryMap) { 178 final List<String> args = queryMap.get("num"); 179 if (args.size() != 1) { 180 return SchedulerResponse.badRequest("Usage : Only one value can be used"); 181 } 182 183 try { 184 185 final int targetNum = Integer.parseInt(args.get(0)); 186 final int maxEval = schedulerDriver.get().setMaxEvaluators(targetNum); 187 return SchedulerResponse.ok("You can use up to " + maxEval + " evaluators."); 188 189 } catch (final UnsuccessfulException e) { 190 return SchedulerResponse.forbidden(e.getMessage()); 191 } catch (final NumberFormatException e) { 192 return SchedulerResponse.badRequest("Usage : num must be an integer"); 193 } 194 } 195}