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        @SuppressWarnings("unchecked")
102        public void doGet(HttpServletRequest request, HttpServletResponse response)
103        throws ServletException, IOException {
104            String externalId = request
105            .getParameter(RestConstants.JOBS_EXTERNAL_ID_PARAM);
106            if (externalId != null) {
107                stopCron();
108                JSONObject json = getJobIdForExternalId(request, externalId);
109                startCron();
110                sendJsonResponse(response, HttpServletResponse.SC_OK, json);
111            }
112            else {
113                stopCron();
114                // Configuration conf = new
115                // XConfiguration(request.getInputStream());
116                JSONObject json = getJobs(request);
117                startCron();
118                sendJsonResponse(response, HttpServletResponse.SC_OK, json);
119            }
120        }
121    
122        /**
123         * abstract method to submit a job, either workflow or coordinator in the case of workflow job, there is an optional
124         * flag in request to indicate if want this job to be started immediately or not
125         *
126         * @param request
127         * @param conf
128         * @return JSONObject of job id
129         * @throws XServletException
130         * @throws IOException
131         */
132        abstract JSONObject submitJob(HttpServletRequest request, Configuration conf)
133        throws XServletException, IOException;
134    
135        /**
136         * abstract method to get a job from external ID
137         *
138         * @param request
139         * @param externalId
140         * @return JSONObject for the requested job
141         * @throws XServletException
142         * @throws IOException
143         */
144        abstract JSONObject getJobIdForExternalId(HttpServletRequest request,
145                String externalId) throws XServletException, IOException;
146    
147        /**
148         * abstract method to get a list of workflow jobs
149         *
150         * @param request
151         * @return JSONObject of the requested jobs
152         * @throws XServletException
153         * @throws IOException
154         */
155        abstract JSONObject getJobs(HttpServletRequest request)
156        throws XServletException, IOException;
157    
158        static void validateJobConfiguration(Configuration conf) throws XServletException {
159            if (conf.get(OozieClient.USER_NAME) == null) {
160                throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0401,
161                        OozieClient.USER_NAME);
162            }
163    
164            String localRealm = Services.get().getConf().get("local.realm");
165    
166            //if the job properties don't define JT/NN Kerberos principals, add default value
167            if (conf.get(WorkflowAppService.HADOOP_JT_KERBEROS_NAME) == null) {
168                conf.set(WorkflowAppService.HADOOP_JT_KERBEROS_NAME, "mapred/_HOST@" + localRealm);
169            }
170            if (conf.get(WorkflowAppService.HADOOP_NN_KERBEROS_NAME) == null) {
171                conf.set(WorkflowAppService.HADOOP_NN_KERBEROS_NAME, "hdfs/_HOST@" + localRealm);
172            }
173        }
174    }