package geniusweb.partiesserver;
import java.io.IOException;
import java.util.logging.Level;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import geniusweb.partiesserver.repository.AvailablePartiesRepo;
import geniusweb.partiesserver.repository.AvailableParty;
import geniusweb.partiesserver.repository.RunningPartiesRepo;
import geniusweb.partiesserver.repository.RunningParty;
import tudelft.utilities.logging.ReportToLogger;
import tudelft.utilities.logging.Reporter;
import tudelft.utilities.repository.NoResourcesNowException;
/**
* Servlet implementation class RunParty. It's behind the url
* partiesserver/run/NAME where NAME is the name of the party that needs to be
* run.
*/
public class RunParty extends HttpServlet {
private static final int DEFAULT_TIMEOUT = 3000; // ms
private static final long serialVersionUID = 1L;
private final Reporter log;
/**
* @see HttpServlet#HttpServlet()
*/
public RunParty() {
this(new ReportToLogger("partiesserver"));
}
/**
*
* @param reporter the reporter where we log issues to.
*/
public RunParty(Reporter reporter) {
this.log = reporter;
}
/**
* See
* {@link HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)}.
* Returns
*
* - URL with websocket address to contact the now running agent.
*
- SC_NOT_FOUND (404) if attempt is made to access non-running party.
*
- SC_SERVICE_UNAVAILABLE (503) if there are no free slots to run the
* party.
*
- SC_EXPECTATION_FAILED (417) if something else goes wrong during
* instantiating the party (then see logs for more details)
*
*/
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String name = request.getPathInfo().substring(1);
log.log(Level.INFO, "request to run " + name);
System.setSecurityManager(new SimpleSecurityManager());
AvailableParty party = AvailablePartiesRepo.instance().get(name);
if (party == null) {
log.log(Level.INFO, "party " + name + " does not exist");
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
// try to avoid needless creation of the party.
if (RunningPartiesRepo.instance().availableSlots() <= 0) {
tryLater(response, name);
return;
}
RunningParty running;
try {
running = RunningParty.create(party, DEFAULT_TIMEOUT);
} catch (Throwable e1) {
log.log(Level.WARNING, "Failed to instantiate party " + name, e1);
response.sendError(HttpServletResponse.SC_EXPECTATION_FAILED,
"Failed to instantiate party " + name + ":"
+ e1.getMessage()
+ ". See partiesserver log for stack trace");
return;
}
// in the mean time, another party may have taken the slot anyway...
// the chances that this happens is small though.
try {
RunningPartiesRepo.instance().put(running);
} catch (NoResourcesNowException e) {
running.getParty().terminate();
tryLater(response, name);
return;
}
log.log(Level.INFO, "started " + name);
String url = "ws://" + request.getLocalName() + ":"
+ request.getLocalPort() + request.getContextPath() + "/party/"
+ running.getID();
response.getWriter().append(url);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
/**
* Reply with 503 plus message that the caller should try later
*
* @param response the response container
* @param name the name of the party that was attempted to launch
* @throws IOException
*/
private void tryLater(HttpServletResponse response, String name)
throws IOException {
long time = RunningPartiesRepo.instance().estimateCleanupTime()
.getTime();
log.log(Level.INFO, "There are no free slots to run the party " + name
+ ". suggesting " + time);
// sendError does not always work as expected, avoid it.
response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
response.getWriter().append("retry later at " + time);
}
}