org.apache.oozie.servlet.BaseJobServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.oozie.servlet.BaseJobServlet.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.oozie.servlet;

import java.io.IOException;
import java.util.Arrays;

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

import org.apache.hadoop.conf.Configuration;
import org.apache.oozie.BaseEngineException;
import org.apache.oozie.ErrorCode;
import org.apache.oozie.client.OozieClient;
import org.apache.oozie.client.XOozieClient;
import org.apache.oozie.client.rest.JsonBean;
import org.apache.oozie.client.rest.JsonTags;
import org.apache.oozie.client.rest.RestConstants;
import org.apache.oozie.service.AuthorizationException;
import org.apache.oozie.service.AuthorizationService;
import org.apache.oozie.service.Services;
import org.apache.oozie.service.XLogService;
import org.apache.oozie.util.ConfigUtils;
import org.apache.oozie.util.JobUtils;
import org.apache.oozie.util.XConfiguration;
import org.apache.oozie.util.XLog;
import org.json.simple.JSONObject;

public abstract class BaseJobServlet extends JsonRestServlet {

    private static final ResourceInfo RESOURCES_INFO[] = new ResourceInfo[1];

    static {
        RESOURCES_INFO[0] = new ResourceInfo("*", Arrays.asList("PUT", "GET"),
                Arrays.asList(
                        new ParameterInfo(RestConstants.ACTION_PARAM, String.class, true, Arrays.asList("PUT")),
                        new ParameterInfo(RestConstants.JOB_SHOW_PARAM, String.class, false, Arrays.asList("GET")),
                        new ParameterInfo(RestConstants.ORDER_PARAM, String.class, false, Arrays.asList("GET"))));
    }

    public BaseJobServlet(String instrumentationName) {
        super(instrumentationName, RESOURCES_INFO);
    }

    /**
     * Perform various job related actions - start, suspend, resume, kill, etc.
     */
    @Override
    protected void doPut(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String jobId = getResourceName(request);
        request.setAttribute(AUDIT_PARAM, jobId);
        request.setAttribute(AUDIT_OPERATION, request.getParameter(RestConstants.ACTION_PARAM));
        try {
            AuthorizationService auth = Services.get().get(AuthorizationService.class);
            auth.authorizeForJob(getUser(request), jobId, true);
        } catch (AuthorizationException ex) {
            throw new XServletException(HttpServletResponse.SC_UNAUTHORIZED, ex);
        }

        String action = request.getParameter(RestConstants.ACTION_PARAM);
        if (action.equals(RestConstants.JOB_ACTION_START)) {
            stopCron();
            startJob(request, response);
            startCron();
            response.setStatus(HttpServletResponse.SC_OK);
        } else if (action.equals(RestConstants.JOB_ACTION_RESUME)) {
            stopCron();
            resumeJob(request, response);
            startCron();
            response.setStatus(HttpServletResponse.SC_OK);
        } else if (action.equals(RestConstants.JOB_ACTION_SUSPEND)) {
            stopCron();
            suspendJob(request, response);
            startCron();
            response.setStatus(HttpServletResponse.SC_OK);
        } else if (action.equals(RestConstants.JOB_ACTION_KILL)) {
            stopCron();
            JSONObject json = killJob(request, response);
            startCron();
            if (json != null) {
                sendJsonResponse(response, HttpServletResponse.SC_OK, json);
            } else {
                response.setStatus(HttpServletResponse.SC_OK);
            }
        } else if (action.equals(RestConstants.JOB_ACTION_CHANGE)) {
            stopCron();
            changeJob(request, response);
            startCron();
            response.setStatus(HttpServletResponse.SC_OK);
        } else if (action.equals(RestConstants.JOB_ACTION_IGNORE)) {
            stopCron();
            JSONObject json = ignoreJob(request, response);
            startCron();
            if (json != null) {
                sendJsonResponse(response, HttpServletResponse.SC_OK, json);
            } else {
                response.setStatus(HttpServletResponse.SC_OK);
            }
        } else if (action.equals(RestConstants.JOB_ACTION_RERUN)) {
            validateContentType(request, RestConstants.XML_CONTENT_TYPE);
            Configuration conf = new XConfiguration(request.getInputStream());
            stopCron();
            String requestUser = getUser(request);
            if (!requestUser.equals(UNDEF)) {
                conf.set(OozieClient.USER_NAME, requestUser);
            }
            if (conf.get(OozieClient.APP_PATH) != null) {
                BaseJobServlet.checkAuthorizationForApp(conf);
                JobUtils.normalizeAppPath(conf.get(OozieClient.USER_NAME), conf.get(OozieClient.GROUP_NAME), conf);
            }
            reRunJob(request, response, conf);
            startCron();
            response.setStatus(HttpServletResponse.SC_OK);
        } else if (action.equals(RestConstants.JOB_COORD_ACTION_RERUN)) {
            validateContentType(request, RestConstants.XML_CONTENT_TYPE);
            stopCron();
            JSONObject json = reRunJob(request, response, null);
            startCron();
            if (json != null) {
                sendJsonResponse(response, HttpServletResponse.SC_OK, json);
            } else {
                response.setStatus(HttpServletResponse.SC_OK);
            }
        } else if (action.equals(RestConstants.JOB_BUNDLE_ACTION_RERUN)) {
            validateContentType(request, RestConstants.XML_CONTENT_TYPE);
            stopCron();
            JSONObject json = reRunJob(request, response, null);
            startCron();
            if (json != null) {
                sendJsonResponse(response, HttpServletResponse.SC_OK, json);
            } else {
                response.setStatus(HttpServletResponse.SC_OK);
            }
        } else if (action.equals(RestConstants.JOB_COORD_UPDATE)) {
            validateContentType(request, RestConstants.XML_CONTENT_TYPE);
            Configuration conf = new XConfiguration(request.getInputStream());
            stopCron();
            String requestUser = getUser(request);
            if (!requestUser.equals(UNDEF)) {
                conf.set(OozieClient.USER_NAME, requestUser);
            }
            if (conf.get(OozieClient.COORDINATOR_APP_PATH) != null) {
                //If coord is submitted from bundle, user may want to update individual coord job with bundle properties
                //If COORDINATOR_APP_PATH is set, we should check only COORDINATOR_APP_PATH path permission
                String bundlePath = conf.get(OozieClient.BUNDLE_APP_PATH);
                if (bundlePath != null) {
                    conf.unset(OozieClient.BUNDLE_APP_PATH);
                }
                BaseJobServlet.checkAuthorizationForApp(conf);
                JobUtils.normalizeAppPath(conf.get(OozieClient.USER_NAME), conf.get(OozieClient.GROUP_NAME), conf);
                if (bundlePath != null) {
                    conf.set(OozieClient.BUNDLE_APP_PATH, bundlePath);
                }
            }
            JSONObject json = updateJob(request, response, conf);
            startCron();
            sendJsonResponse(response, HttpServletResponse.SC_OK, json);
        } else if (action.equals(RestConstants.SLA_ENABLE_ALERT)) {
            validateContentType(request, RestConstants.XML_CONTENT_TYPE);
            stopCron();
            slaEnableAlert(request, response);
            startCron();
            response.setStatus(HttpServletResponse.SC_OK);
        } else if (action.equals(RestConstants.SLA_DISABLE_ALERT)) {
            validateContentType(request, RestConstants.XML_CONTENT_TYPE);
            stopCron();
            slaDisableAlert(request, response);
            startCron();
            response.setStatus(HttpServletResponse.SC_OK);
        } else if (action.equals(RestConstants.SLA_CHANGE)) {
            validateContentType(request, RestConstants.XML_CONTENT_TYPE);
            stopCron();
            slaChange(request, response);
            startCron();
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0303,
                    RestConstants.ACTION_PARAM, action);
        }
    }

    abstract JSONObject ignoreJob(HttpServletRequest request, HttpServletResponse response)
            throws XServletException, IOException;

    /**
     * Validate the configuration user/group. <p>
     *
     * @param conf configuration.
     * @throws XServletException thrown if the configuration does not have a property {@link
     * org.apache.oozie.client.OozieClient#USER_NAME}.
     */
    static void checkAuthorizationForApp(Configuration conf) throws XServletException {
        String user = conf.get(OozieClient.USER_NAME);
        String acl = ConfigUtils.getWithDeprecatedCheck(conf, OozieClient.GROUP_NAME, OozieClient.JOB_ACL, null);
        try {
            if (user == null) {
                throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0401,
                        OozieClient.USER_NAME);
            }
            AuthorizationService auth = Services.get().get(AuthorizationService.class);

            if (acl != null) {
                conf.set(OozieClient.GROUP_NAME, acl);
            } else if (acl == null && auth.useDefaultGroupAsAcl()) {
                acl = auth.getDefaultGroup(user);
                conf.set(OozieClient.GROUP_NAME, acl);
            }
            XLog.Info.get().setParameter(XLogService.GROUP, acl);
            String wfPath = conf.get(OozieClient.APP_PATH);
            String coordPath = conf.get(OozieClient.COORDINATOR_APP_PATH);
            String bundlePath = conf.get(OozieClient.BUNDLE_APP_PATH);

            if (wfPath == null && coordPath == null && bundlePath == null) {
                String[] libPaths = conf.getStrings(XOozieClient.LIBPATH);
                if (libPaths != null && libPaths.length > 0 && libPaths[0].trim().length() > 0) {
                    conf.set(OozieClient.APP_PATH, libPaths[0].trim());
                    wfPath = libPaths[0].trim();
                } else {
                    throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0405);
                }
            }
            ServletUtilities.ValidateAppPath(wfPath, coordPath, bundlePath);

            if (wfPath != null) {
                auth.authorizeForApp(user, acl, wfPath, "workflow.xml", conf);
            } else if (coordPath != null) {
                auth.authorizeForApp(user, acl, coordPath, "coordinator.xml", conf);
            } else if (bundlePath != null) {
                auth.authorizeForApp(user, acl, bundlePath, "bundle.xml", conf);
            }
        } catch (AuthorizationException ex) {
            XLog.getLog(BaseJobServlet.class).info("AuthorizationException ", ex);
            throw new XServletException(HttpServletResponse.SC_UNAUTHORIZED, ex);
        }
    }

    /**
     * Return information about jobs.
     */
    @Override
    @SuppressWarnings("unchecked")
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String jobId = getResourceName(request);
        String show = request.getParameter(RestConstants.JOB_SHOW_PARAM);
        String timeZoneId = request.getParameter(RestConstants.TIME_ZONE_PARAM) == null ? "GMT"
                : request.getParameter(RestConstants.TIME_ZONE_PARAM);

        try {
            AuthorizationService auth = Services.get().get(AuthorizationService.class);
            auth.authorizeForJob(getUser(request), jobId, false);
        } catch (AuthorizationException ex) {
            throw new XServletException(HttpServletResponse.SC_UNAUTHORIZED, ex);
        }

        if (show == null || show.equals(RestConstants.JOB_SHOW_INFO)) {
            stopCron();
            JsonBean job = null;
            try {
                job = getJob(request, response);
            } catch (BaseEngineException e) {
                // TODO Auto-generated catch block
                // e.printStackTrace();

                throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, e);
            }
            startCron();
            sendJsonResponse(response, HttpServletResponse.SC_OK, job, timeZoneId);
        } else if (show.equals(RestConstants.ALL_WORKFLOWS_FOR_COORD_ACTION)) {
            stopCron();
            JSONObject json = getJobsByParentId(request, response);
            startCron();
            sendJsonResponse(response, HttpServletResponse.SC_OK, json);
        } else if (show.equals(RestConstants.JOB_SHOW_JMS_TOPIC)) {
            stopCron();
            String jmsTopicName = getJMSTopicName(request, response);
            JSONObject json = new JSONObject();
            json.put(JsonTags.JMS_TOPIC_NAME, jmsTopicName);
            startCron();
            sendJsonResponse(response, HttpServletResponse.SC_OK, json);
        }

        else if (show.equals(RestConstants.JOB_SHOW_LOG)) {
            response.setContentType(TEXT_UTF8);
            streamJobLog(request, response);
        } else if (show.equals(RestConstants.JOB_SHOW_ERROR_LOG)) {
            response.setContentType(TEXT_UTF8);
            streamJobErrorLog(request, response);
        } else if (show.equals(RestConstants.JOB_SHOW_AUDIT_LOG)) {
            response.setContentType(TEXT_UTF8);
            streamJobAuditLog(request, response);
        }

        else if (show.equals(RestConstants.JOB_SHOW_DEFINITION)) {
            stopCron();
            response.setContentType(XML_UTF8);
            String wfDefinition = getJobDefinition(request, response);
            startCron();
            response.setStatus(HttpServletResponse.SC_OK);
            response.getWriter().write(wfDefinition);
        } else if (show.equals(RestConstants.JOB_SHOW_GRAPH)) {
            stopCron();
            streamJobGraph(request, response);
            startCron(); // -- should happen before you stream anything in response?
        } else if (show.equals(RestConstants.JOB_SHOW_STATUS)) {
            stopCron();
            String status = getJobStatus(request, response);
            JSONObject json = new JSONObject();
            json.put(JsonTags.STATUS, status);
            startCron();
            sendJsonResponse(response, HttpServletResponse.SC_OK, json);
        } else {
            throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0303,
                    RestConstants.JOB_SHOW_PARAM, show);
        }
    }

    /**
     * abstract method to start a job, either workflow or coordinator
     *
     * @param request
     * @param response
     * @throws XServletException
     * @throws IOException TODO
     */
    abstract void startJob(HttpServletRequest request, HttpServletResponse response)
            throws XServletException, IOException;

    /**
     * abstract method to resume a job, either workflow or coordinator
     *
     * @param request
     * @param response
     * @throws XServletException
     * @throws IOException TODO
     */
    abstract void resumeJob(HttpServletRequest request, HttpServletResponse response)
            throws XServletException, IOException;

    /**
     * abstract method to suspend a job, either workflow or coordinator
     *
     * @param request
     * @param response
     * @throws XServletException
     * @throws IOException TODO
     */
    abstract void suspendJob(HttpServletRequest request, HttpServletResponse response)
            throws XServletException, IOException;

    /**
     * abstract method to kill a job, either workflow or coordinator
     *
     * @param request
     * @param response
     * @return
     * @throws XServletException
     * @throws IOException TODO
     */
    abstract JSONObject killJob(HttpServletRequest request, HttpServletResponse response)
            throws XServletException, IOException;

    /**
     * abstract method to change a coordinator job
     *
     * @param request
     * @param response
     * @throws XServletException
     * @throws IOException TODO
     */
    abstract void changeJob(HttpServletRequest request, HttpServletResponse response)
            throws XServletException, IOException;

    /**
     * abstract method to re-run a job, either workflow or coordinator
     *
     * @param request
     * @param response
     * @param conf
     * @throws XServletException
     * @throws IOException TODO
     */
    abstract JSONObject reRunJob(HttpServletRequest request, HttpServletResponse response, Configuration conf)
            throws XServletException, IOException;

    /**
     * abstract method to get a job, either workflow or coordinator, in JsonBean representation
     *
     * @param request
     * @param response
     * @return JsonBean representation of a job, either workflow or coordinator
     * @throws XServletException
     * @throws IOException TODO
     * @throws BaseEngineException
     */
    abstract JsonBean getJob(HttpServletRequest request, HttpServletResponse response)
            throws XServletException, IOException, BaseEngineException;

    /**
     * abstract method to get definition of a job, either workflow or coordinator
     *
     * @param request
     * @param response
     * @return job, either workflow or coordinator, definition in string format
     * @throws XServletException
     * @throws IOException TODO
     */
    abstract String getJobDefinition(HttpServletRequest request, HttpServletResponse response)
            throws XServletException, IOException;

    /**
     * abstract method to get and stream log information of job, either workflow or coordinator
     *
     * @param request
     * @param response
     * @throws XServletException
     * @throws IOException
     */
    abstract void streamJobLog(HttpServletRequest request, HttpServletResponse response)
            throws XServletException, IOException;

    /**
     * abstract method to get and stream error log information of job, either workflow, coordinator or bundle
     *
     * @param request
     * @param response
     * @throws XServletException
     * @throws IOException
     */
    abstract void streamJobErrorLog(HttpServletRequest request, HttpServletResponse response)
            throws XServletException, IOException;

    abstract void streamJobAuditLog(HttpServletRequest request, HttpServletResponse response)
            throws XServletException, IOException;

    /**
     * abstract method to create and stream image for runtime DAG -- workflow only
     *
     * @param request
     * @param response
     * @throws XServletException
     * @throws IOException
     */
    abstract void streamJobGraph(HttpServletRequest request, HttpServletResponse response)
            throws XServletException, IOException;

    /**
     * abstract method to get JMS topic name for a job
     * @param request
     * @param response
     * @throws XServletException
     * @throws IOException
     */
    abstract String getJMSTopicName(HttpServletRequest request, HttpServletResponse response)
            throws XServletException, IOException;

    /**
     * abstract method to get workflow job ids from the parent id
     * i.e. coordinator action
     * @param request
     * @param response
     * @return comma-separated list of workflow job ids
     * @throws XServletException
     * @throws IOException
     */
    abstract JSONObject getJobsByParentId(HttpServletRequest request, HttpServletResponse response)
            throws XServletException, IOException;

    /**
     * Abstract method to Update coord job.
     *
     * @param request the request
     * @param response the response
     * @param conf the Configuration
     * @return the JSON object
     * @throws XServletException the x servlet exception
     * @throws IOException Signals that an I/O exception has occurred.
     */
    abstract JSONObject updateJob(HttpServletRequest request, HttpServletResponse response, Configuration conf)
            throws XServletException, IOException;

    /**
     * Abstract method to get status for a job
     *
     * @param request the request
     * @param response the response
     * @return the JSON object
     * @throws XServletException the x servlet exception
     * @throws IOException Signals that an I/O exception has occurred.
     */
    abstract String getJobStatus(HttpServletRequest request, HttpServletResponse response)
            throws XServletException, IOException;

    /**
     * Abstract method to enable SLA alert.
     *
     * @param request the request
     * @param response the response
     * @throws XServletException the x servlet exception
     * @throws IOException Signals that an I/O exception has occurred.
     */
    abstract void slaEnableAlert(HttpServletRequest request, HttpServletResponse response)
            throws XServletException, IOException;

    /**
     * Abstract method to disable SLA alert.
     *
     * @param request the request
     * @param response the response
     * @throws XServletException the x servlet exception
     * @throws IOException Signals that an I/O exception has occurred.
     */
    abstract void slaDisableAlert(HttpServletRequest request, HttpServletResponse response)
            throws XServletException, IOException;

    /**
     * Abstract method to change SLA definition.
     *
     * @param request the request
     * @param response the response
     * @throws XServletException the x servlet exception
     * @throws IOException Signals that an I/O exception has occurred.
     */
    abstract void slaChange(HttpServletRequest request, HttpServletResponse response)
            throws XServletException, IOException;

}