org.seamless_if.services.servlets.SchedulerServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.seamless_if.services.servlets.SchedulerServlet.java

Source

/*
 * Gromit: SchedulerServlet.java
 * ==============================================================================
 * This work has been carried out as part of the SEAMLESS Integrated Framework
 * project, EU 6th Framework Programme, contract no. 010036-2 and/or as part
 * of the SEAMLESS association.
 *
 * Copyright (c) 2009 The SEAMLESS Association.
 *
 * For more information: http://www.seamlessassociation.org;
 * email: info@seamless-if.org
 *
 * The contents of this file is subject to the SEAMLESS Association License for
 * software infrastructure and model components Version 1.1 (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.seamlessassociation.org/License.htm
 *
 * Software distributed under the License is distributed on an "AS IS"  basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific governing rights and limitations.
 * ================================================================================
 */

package org.seamless_if.services.servlets;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.dom.DOMElement;
import org.dom4j.io.XMLWriter;
import org.seamless_if.processing.scheduler.JobState;
import org.seamless_if.processing.scheduler.WorkerState;
import org.seamless_if.processing.scheduler.dto.JobTO;
import org.seamless_if.processing.scheduler.dto.ModelChainInfoTO;
import org.seamless_if.processing.scheduler.dto.WorkerTO;
import org.seamless_if.processing.sofa.SeamException;
import org.seamless_if.services.scheduler.SchedulerService;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

/**
 * Servlet implementation class Scheduler.
 */
public class SchedulerServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    private SchedulerService schedulerDao;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public SchedulerServlet() {
        super();
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);

        WebApplicationContext springContext = WebApplicationContextUtils
                .getWebApplicationContext(getServletContext());
        schedulerDao = (SchedulerService) springContext.getBean("schedulerDao");

        // TODO remove test code

        // create some sample model chains
        ModelChainInfoTO chainA = new ModelChainInfoTO();
        chainA.setName("APES->FSSIM");
        chainA.setVersion("1.0");
        ModelChainInfoTO chainB = new ModelChainInfoTO();
        chainB.setName("FSSIM<->CAPRI");
        chainB.setVersion("1.1");

        // create some sample workers
        WorkerTO workerA = new WorkerTO();
        workerA.setName("WorkerA");
        workerA.addAvailableModelChain(chainA);
        schedulerDao.registerWorker(workerA);
        WorkerTO workerB = new WorkerTO();
        workerB.setName("WorkerB");
        workerB.addAvailableModelChain(chainA);
        workerB.addAvailableModelChain(chainB);
        schedulerDao.registerWorker(workerB);

        // create some sample jobs
        JobTO jobA = new JobTO();
        jobA.setExperimentId(1L);
        jobA.setModelChain(chainA);
        schedulerDao.addJob(jobA);
        JobTO jobB = new JobTO();
        jobB.setExperimentId(2L);
        jobB.setModelChain(chainB);
        schedulerDao.addJob(jobB);
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        handleRequest(request, response);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        handleRequest(request, response);
    }

    @SuppressWarnings("unchecked")
    private void handleRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // set-up some things for output as XML
        response.setContentType("text/xml");
        XMLWriter writer = new XMLWriter(response.getOutputStream());
        Element root = new DOMElement("scheduler");
        Document document = DocumentHelper.createDocument(root);

        // parse arguments to figure out what to do
        String methodName = request.getParameter("method");
        if (methodName == null)
            methodName = "info";

        // invoke method based on reflection (names must match!)
        try {
            if (ACCESSIBLE_METHODS.valueOf(methodName) == null)
                throw new IllegalAccessException();
            Method method = this.getClass().getMethod(methodName, Element.class, HttpServletRequest.class);
            method.invoke(this, root, request);
        } catch (Exception e) {
            root.add(new DOMElement("error").addText(e.toString()));
            root.add(new DOMElement("method").addText(methodName));
            Map<String, String[]> parameters = (Map<String, String[]>) request.getParameterMap();
            for (Object key : parameters.keySet()) {
                Element param = new DOMElement("parameter").addAttribute("name", key.toString());
                Element valuesNode = new DOMElement("values");
                String[] values = parameters.get(key);
                for (String value : values) {
                    valuesNode.add(new DOMElement("value").addText(value));
                }
                param.add(valuesNode);
                root.add(param);
            }
            e.printStackTrace();
        }

        // write the output
        try {
            writer.write(document);
            writer.close();
        } catch (Exception ex) {
            throw new SeamException(ex, "Failed to create servlet xml output! Error: %s", ex.getMessage());
        }
    }

    /**
     * List of accessible methods that can be called through the servlet. Note
     * that they all must have the same signature and produce output as XML
     * added to the root node, based on the parameters from the request. 
     */
    private enum ACCESSIBLE_METHODS {
        info, // no param 
        allJobs, // no param
        jobById, // jid (job id)
        allWorkers, // no param
        workerById, // wid (worker id)
        allKnownChains, // no param
        addJob, // eid (experiment id), cid (chain id)
        registerWorker, // ip, name
        unregisterWorker, // wid (worker id)
        registerChain, // wid (worker id), name, version
        unregisterChain, // wid (worker id), cid (chain id)
        jobForWorker, // wid (worker id)
        setWorkerState, // wid (worker id), ws (worker state name)
        setJobState, // jid (job id), js (job state name)
        workerStates, // no param
        jobStates // no param
    }

    public void info(Element root, HttpServletRequest request) {
        allJobs(root, request);
        allWorkers(root, request);
        allKnownChains(root, request);
        workerStates(root, request);
        jobStates(root, request);
    }

    public void allJobs(Element root, HttpServletRequest request) {
        Element node = new DOMElement("jobs");
        List<JobTO> jobs = schedulerDao.allJobs();
        for (JobTO job : jobs) {
            node.add(job.toXml());
        }
        root.add(node);
    }

    public void jobById(Element root, HttpServletRequest request) {
        Element node = new DOMElement("job");
        String id = request.getParameter("jid");
        if (id == null) {
            throw new SeamException("Method requires additional parameter: jid (job id)");
        } else {
            JobTO obj = schedulerDao.jobById(id);
            if (obj != null)
                node.add(obj.toXml());
        }
        root.add(node);
    }

    public void allKnownChains(Element root, HttpServletRequest request) {
        Element node = new DOMElement("chains");
        List<ModelChainInfoTO> chains = schedulerDao.allCurrentlyKnownModelChains();
        for (ModelChainInfoTO chain : chains) {
            node.add(chain.toXml());
        }
        root.add(node);
    }

    public void allWorkers(Element root, HttpServletRequest request) {
        Element node = new DOMElement("workers");
        List<WorkerTO> workers = schedulerDao.allWorkers();
        for (WorkerTO worker : workers) {
            node.add(worker.toXml());
        }
        root.add(node);
    }

    public void workerById(Element root, HttpServletRequest request) {
        Element node = new DOMElement("worker");
        String id = request.getParameter("wid");

        if (id == null) {
            throw new SeamException("Method requires additional parameter: wid (worker id)");
        } else {
            WorkerTO obj = schedulerDao.workerById(id);
            if (obj != null)
                node.add(obj.toXml());
        }
        root.add(node);
    }

    public void addJob(Element root, HttpServletRequest request) {
        String experimentId = request.getParameter("eid");
        String modelChainId = request.getParameter("cid");

        if ((experimentId == null) || (modelChainId == null)) {
            throw new SeamException("Method requires additional parameters: eid (experiment id), cid (chain id)");
        }

        JobTO job = schedulerDao.addJob(Long.valueOf(experimentId), modelChainId);
        if (job == null) {
            throw new SeamException("Failed to create new job, please see server log for cause!");
        } else {
            Element node = new DOMElement("job");
            node.add(job.toXml());
            root.add(node);
        }
    }

    public void registerWorker(Element root, HttpServletRequest request) {
        // TODO can we get the IP of the requester in another way?
        String workerIp = request.getParameter("ip");
        String workerName = request.getParameter("name");
        if ((workerIp == null) || (workerName == null)) {
            throw new SeamException("Method requires additional parameters: ip, name");
        }

        WorkerTO worker = schedulerDao.registerWorker(workerIp, workerName);
        if (worker == null) {
            throw new SeamException("Failed to register worker node, please see server log for cause!");
        } else {
            Element node = new DOMElement("worker");
            node.add(worker.toXml());
            root.add(node);
        }
    }

    public void unregisterWorker(Element root, HttpServletRequest request) {
        Element node = new DOMElement("worker");
        String id = request.getParameter("wid");

        if (id == null) {
            throw new SeamException("Method requires additional parameter: wid (worker id)");
        } else {
            WorkerTO obj = schedulerDao.workerById(id);
            if (obj != null) {
                schedulerDao.unregisterWorker(id);
                node.add(obj.toXml());
            } else {
                throw new SeamException("Failed to unregister worker node, no worker registered with id: " + id);
            }
        }
        root.add(node);
    }

    public void registerChain(Element root, HttpServletRequest request) {
        String workerId = request.getParameter("wid");
        String modelChainName = request.getParameter("name");
        String modelChainVersion = request.getParameter("version");

        if ((workerId == null) || (modelChainName == null) || (modelChainVersion == null)) {
            throw new SeamException(
                    "Method requires additional parameters: wid (worker id), name (of chain), version (of chain)");
        }

        ModelChainInfoTO mci = schedulerDao.registerModelChainForWorker(workerId, modelChainName,
                modelChainVersion);
        if (mci == null) {
            throw new SeamException("Failed to register model chain for worker, please see server log for cause!");
        } else {
            Element node = new DOMElement("chain");
            node.add(mci.toXml());
            root.add(node);
        }
    }

    public void unregisterChain(Element root, HttpServletRequest request) {
        String workerId = request.getParameter("wid");
        String modelChainId = request.getParameter("cid");

        if ((workerId == null) || (modelChainId == null)) {
            throw new SeamException("Method requires additional parameters: wid (worker id), cid (chain id)");
        }

        ModelChainInfoTO mci = schedulerDao.unregisterModelChainForWorker(workerId, modelChainId);
        if (mci == null) {
            throw new SeamException(
                    "Failed to unregister model chain for worker, please see server log for cause!");
        } else {
            Element node = new DOMElement("chain");
            node.add(mci.toXml());
            root.add(node);
        }
    }

    public void jobForWorker(Element root, HttpServletRequest request) {
        String workerId = request.getParameter("wid");

        if (workerId == null) {
            throw new SeamException("Method requires additional parameter: wid (worker id)");
        }

        JobTO job = schedulerDao.findJobForWorker(workerId);
        if (job == null) {
            throw new SeamException("Failed to find job for worker, please see server log for cause!");
        } else {
            Element node = new DOMElement("job");
            node.add(job.toXml());
            root.add(node);
        }
    }

    public void setWorkerState(Element root, HttpServletRequest request) {
        String workerId = request.getParameter("wid");
        String workerStateName = request.getParameter("ws");

        if ((workerId == null) || (workerStateName == null)) {
            throw new SeamException(
                    "Method requires additional parameters: wid (worker id), ws (worker state name)");
        }

        try {
            WorkerState newState = WorkerState.valueOf(workerStateName);
            schedulerDao.updateWorkerState(workerId, newState);
            Element node = new DOMElement("worker");
            WorkerTO worker = schedulerDao.workerById(workerId);
            node.add(worker.toXml());
            root.add(node);
        } catch (Exception ex) {
            throw new SeamException("Failed to update state of worker, please see server log for cause!");
        }
    }

    public void workerStates(Element root, HttpServletRequest request) {
        Element node = new DOMElement("workerStates");
        for (WorkerState state : WorkerState.values()) {
            node.add(new DOMElement("state").addText(state.name()));
        }
        root.add(node);
    }

    public void setJobState(Element root, HttpServletRequest request) {
        String jobId = request.getParameter("jid");
        String jobStateName = request.getParameter("js");

        if ((jobId == null) || (jobStateName == null)) {
            throw new SeamException("Method requires additional parameters: jid (job id), js (job state name)");
        }

        try {
            JobState newState = JobState.valueOf(jobStateName);
            schedulerDao.updateJobState(jobId, newState);
            Element node = new DOMElement("job");
            JobTO job = schedulerDao.jobById(jobId);
            node.add(job.toXml());
            root.add(node);
        } catch (Exception ex) {
            throw new SeamException("Failed to update state of job, please see server log for cause!");
        }
    }

    public void jobStates(Element root, HttpServletRequest request) {
        Element node = new DOMElement("jobStates");
        for (JobState state : JobState.values()) {
            node.add(new DOMElement("state").addText(state.name()));
        }
        root.add(node);
    }

    // TODO Consider for (re)implementation
    /**
     * Check the state of the specified experiment. The string returned can be:
     * <p/>
     * EXP_RUNNING EXP_QUEUED + [POSTFIX_HAS_RESULTS | POSTFIX_NO_RESULTS]
     * EXP_NOTQUEUED + [POSTFIX_HAS_RESULTS | POSTFIX_NO_RESULTS]
     *
     * @param experiment to check
     * @return String description of the state
     */
    /*
    private static String EXP_RUNNING = "Running";
    private static String EXP_QUEUED = "Queued";
    private static String EXP_NOTQUEUED = "Not Scheduled";
        
    private static String POSTFIX_HAS_RESULTS = ", results from previous run available";
    private static String POSTFIX_NO_RESULTS = ", no results available at this time";
        
    private static String POSTFIX_STATE_MISSING = " [State info missing]";
    private static String POSTFIX_STATE_UNKNOWN = " [Unknown state]";
    private static String POSTFIX_STATE_0 = " [Not calculated]";
    private static String POSTFIX_STATE_1 = " [Last calculation aborted]";
    private static String POSTFIX_STATE_2 = " [Calculation in progress]";
    private static String POSTFIX_STATE_3 = " [Last calculation ok]";
    private static String POSTFIX_STATE_4 = " [Last calculation failed]";
        
        
    public synchronized String query(Experiment experiment) {
    StringBuffer output = new StringBuffer();
        
    // check if the experiment is currently running
    if ((_actualExperiment.getExperiment() != null)
            && (_actualExperiment.getExperiment().equals(experiment)))
        return EXP_RUNNING;
        
    // check if it is in the queue or not
    if (_expQueue.indexOf(experiment) >= 0)
        output.append(EXP_QUEUED);
    else
        output.append(EXP_NOTQUEUED);
        
    // include results availability in message
    if ((experiment != null) && (experiment.getIndicatorValues() != null)
            && (experiment.getIndicatorValues().size() > 0))
        output.append(POSTFIX_HAS_RESULTS);
    else
        output.append(POSTFIX_NO_RESULTS);
        
    // include state of QueuedExperiment in message
    if ((experiment != null) && (experiment.getState() != null)) {
        switch (experiment.getState()) {
            case 0:
                output.append(POSTFIX_STATE_0);
                break;
            case 1:
                output.append(POSTFIX_STATE_1);
                break;
            case 2:
                output.append(POSTFIX_STATE_2);
                break;
            case 3:
                output.append(POSTFIX_STATE_3);
                break;
            case 4:
                output.append(POSTFIX_STATE_4);
                break;
            default:
                output.append(POSTFIX_STATE_UNKNOWN);
        }
    } else
        output.append(POSTFIX_STATE_MISSING);
        
    return output.toString();
    }
    */
}