001    /**
002     * Copyright (c) 2010 Yahoo! Inc. All rights reserved.
003     * Licensed under the Apache License, Version 2.0 (the "License");
004     * you may not use this file except in compliance with the License.
005     * You may obtain a copy of the License at
006     *
007     *   http://www.apache.org/licenses/LICENSE-2.0
008     *
009     *  Unless required by applicable law or agreed to in writing, software
010     *  distributed under the License is distributed on an "AS IS" BASIS,
011     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012     *  See the License for the specific language governing permissions and
013     *  limitations under the License. See accompanying LICENSE file.
014     */
015    package org.apache.oozie.servlet;
016    
017    import java.io.IOException;
018    import java.util.Arrays;
019    
020    import javax.servlet.ServletException;
021    import javax.servlet.http.HttpServletRequest;
022    import javax.servlet.http.HttpServletResponse;
023    
024    import org.apache.hadoop.conf.Configuration;
025    import org.apache.oozie.ErrorCode;
026    import org.apache.oozie.client.OozieClient;
027    import org.apache.oozie.client.rest.RestConstants;
028    import org.apache.oozie.service.Services;
029    import org.apache.oozie.service.WorkflowAppService;
030    import org.apache.oozie.util.JobUtils;
031    import org.apache.oozie.util.XConfiguration;
032    import org.json.simple.JSONObject;
033    
034    public abstract class BaseJobsServlet extends JsonRestServlet {
035    
036        private static final JsonRestServlet.ResourceInfo RESOURCES_INFO[] = new JsonRestServlet.ResourceInfo[1];
037    
038        static {
039            RESOURCES_INFO[0] = new JsonRestServlet.ResourceInfo("", Arrays.asList(
040                    "POST", "GET"), Arrays.asList(
041                    new JsonRestServlet.ParameterInfo(RestConstants.ACTION_PARAM,
042                                                      String.class, false, Arrays.asList("POST")),
043                    new JsonRestServlet.ParameterInfo(
044                            RestConstants.JOBS_FILTER_PARAM, String.class, false,
045                            Arrays.asList("GET")),
046                    new JsonRestServlet.ParameterInfo(RestConstants.JOBTYPE_PARAM,
047                                                      String.class, false, Arrays.asList("GET", "POST")),
048                    new JsonRestServlet.ParameterInfo(RestConstants.OFFSET_PARAM,
049                                                      String.class, false, Arrays.asList("GET")),
050                    new JsonRestServlet.ParameterInfo(RestConstants.LEN_PARAM,
051                                                      String.class, false, Arrays.asList("GET")),
052    
053                    new JsonRestServlet.ParameterInfo(
054                            RestConstants.JOBS_EXTERNAL_ID_PARAM, String.class,
055                            false, Arrays.asList("GET"))));
056        }
057    
058        public BaseJobsServlet(String instrumentationName) {
059            super(instrumentationName, RESOURCES_INFO);
060        }
061    
062        /**
063         * Create a job.
064         */
065        @Override
066        @SuppressWarnings("unchecked")
067        protected void doPost(HttpServletRequest request,
068                HttpServletResponse response) throws ServletException, IOException {
069            String authTok = getAuthToken(request);
070            /*
071             * Enumeration p = request.getAttributeNames();
072             * for(;p.hasMoreElements();){ String key = (String)p.nextElement();
073             * XLog.getLog(getClass()).warn(" key "+ key + " val "+ (String)
074             * request.getAttribute(key)); }
075             */
076            validateContentType(request, RestConstants.XML_CONTENT_TYPE);
077    
078            request.setAttribute(AUDIT_OPERATION, request
079                    .getParameter(RestConstants.ACTION_PARAM));
080    
081            XConfiguration conf = new XConfiguration(request.getInputStream());
082    
083            stopCron();
084    
085            conf = conf.trim();
086            conf = conf.resolve();
087    
088            validateJobConfiguration(conf);
089            BaseJobServlet.checkAuthorizationForApp(getUser(request), conf);
090            JobUtils.normalizeAppPath(conf.get(OozieClient.USER_NAME), conf.get(OozieClient.GROUP_NAME), conf);
091    
092            JSONObject json = submitJob(request, conf);
093            startCron();
094            sendJsonResponse(response, HttpServletResponse.SC_CREATED, json);
095        }
096    
097        /**
098         * Return information about jobs.
099         */
100        @Override
101        public void doGet(HttpServletRequest request, HttpServletResponse response)
102        throws ServletException, IOException {
103            String externalId = request
104            .getParameter(RestConstants.JOBS_EXTERNAL_ID_PARAM);
105            if (externalId != null) {
106                stopCron();
107                JSONObject json = getJobIdForExternalId(request, externalId);
108                startCron();
109                sendJsonResponse(response, HttpServletResponse.SC_OK, json);
110            }
111            else {
112                stopCron();
113                JSONObject json = getJobs(request);
114                startCron();
115                sendJsonResponse(response, HttpServletResponse.SC_OK, json);
116            }
117        }
118    
119        /**
120         * abstract method to submit a job, either workflow or coordinator in the case of workflow job, there is an optional
121         * flag in request to indicate if want this job to be started immediately or not
122         *
123         * @param request
124         * @param conf
125         * @return JSONObject of job id
126         * @throws XServletException
127         * @throws IOException
128         */
129        abstract JSONObject submitJob(HttpServletRequest request, Configuration conf)
130        throws XServletException, IOException;
131    
132        /**
133         * abstract method to get a job from external ID
134         *
135         * @param request
136         * @param externalId
137         * @return JSONObject for the requested job
138         * @throws XServletException
139         * @throws IOException
140         */
141        abstract JSONObject getJobIdForExternalId(HttpServletRequest request,
142                String externalId) throws XServletException, IOException;
143    
144        /**
145         * abstract method to get a list of workflow jobs
146         *
147         * @param request
148         * @return JSONObject of the requested jobs
149         * @throws XServletException
150         * @throws IOException
151         */
152        abstract JSONObject getJobs(HttpServletRequest request)
153        throws XServletException, IOException;
154    
155        static void validateJobConfiguration(Configuration conf) throws XServletException {
156            if (conf.get(OozieClient.USER_NAME) == null) {
157                throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0401,
158                        OozieClient.USER_NAME);
159            }
160    
161            String localRealm = Services.get().getConf().get("local.realm");
162    
163            //if the job properties don't define JT/NN Kerberos principals, add default value
164            if (conf.get(WorkflowAppService.HADOOP_JT_KERBEROS_NAME) == null) {
165                conf.set(WorkflowAppService.HADOOP_JT_KERBEROS_NAME, "mapred/_HOST@" + localRealm);
166            }
167            if (conf.get(WorkflowAppService.HADOOP_NN_KERBEROS_NAME) == null) {
168                conf.set(WorkflowAppService.HADOOP_NN_KERBEROS_NAME, "hdfs/_HOST@" + localRealm);
169            }
170        }
171    }