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 import java.util.Collections;
020 import java.util.Properties;
021
022 import javax.servlet.ServletException;
023 import javax.servlet.http.HttpServletRequest;
024 import javax.servlet.http.HttpServletResponse;
025
026 import org.apache.oozie.DagEngine;
027 import org.apache.oozie.DagEngineException;
028 import org.apache.oozie.ErrorCode;
029 import org.apache.oozie.client.rest.RestConstants;
030 import org.apache.oozie.service.CallbackService;
031 import org.apache.oozie.service.DagEngineService;
032 import org.apache.oozie.service.Services;
033 import org.apache.oozie.util.IOUtils;
034 import org.apache.oozie.util.PropertiesUtils;
035 import org.apache.oozie.util.XLog;
036
037 public class CallbackServlet extends JsonRestServlet {
038 private static final String INSTRUMENTATION_NAME = "callback";
039
040 private static final ResourceInfo RESOURCE_INFO =
041 new ResourceInfo("", Arrays.asList("POST", "GET"), Collections.EMPTY_LIST);
042
043 public final static String CONF_MAX_DATA_LEN = "oozie.servlet.CallbackServlet.max.data.len";
044
045 private static int maxDataLen;
046
047 private XLog log = null;
048
049 public CallbackServlet() {
050 super(INSTRUMENTATION_NAME, RESOURCE_INFO);
051 }
052
053 @Override
054 public void init() {
055 maxDataLen = Services.get().getConf().getInt(CONF_MAX_DATA_LEN, 2 * 1024);
056 }
057
058 /**
059 * GET callback
060 */
061 @Override
062 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
063 String queryString = request.getQueryString();
064 CallbackService callbackService = Services.get().get(CallbackService.class);
065
066 if (!callbackService.isValid(queryString)) {
067 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0402, queryString);
068 }
069
070 String actionId = callbackService.getActionId(queryString);
071 if (actionId == null) {
072 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0402, queryString);
073 }
074 int idx = actionId.lastIndexOf('@', actionId.length());
075 String jobId;
076 if (idx == -1) {
077 jobId = actionId;
078 }
079 else {
080 jobId = actionId.substring(0, idx);
081 }
082 setLogInfo(jobId, actionId);
083 log = XLog.getLog(getClass());
084 log.debug("Received a CallbackServlet.doGet() with query string " + queryString);
085
086 DagEngine dagEngine = Services.get().get(DagEngineService.class).getSystemDagEngine();
087 try {
088 log.info(XLog.STD, "callback for action [{0}]", actionId);
089 dagEngine.processCallback(actionId, callbackService.getExternalStatus(queryString), null);
090 }
091 catch (DagEngineException ex) {
092 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ex);
093 }
094 }
095
096 /**
097 * POST callback
098 */
099 @Override
100 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
101 IOException {
102 String queryString = request.getQueryString();
103 CallbackService callbackService = Services.get().get(CallbackService.class);
104
105 if (!callbackService.isValid(queryString)) {
106 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0402, queryString);
107 }
108
109 String actionId = callbackService.getActionId(queryString);
110 if (actionId == null) {
111 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0402, queryString);
112 }
113 int idx = actionId.lastIndexOf('@', actionId.length());
114 String jobId;
115 if (idx == -1) {
116 jobId = actionId;
117 }
118 else {
119 jobId = actionId.substring(0, idx);
120 }
121 setLogInfo(jobId, actionId);
122 log = XLog.getLog(getClass());
123 log.debug("Received a CallbackServlet.doPost() with query string " + queryString);
124
125 validateContentType(request, RestConstants.TEXT_CONTENT_TYPE);
126 try {
127 log.info(XLog.STD, "callback for action [{0}]", actionId);
128 String data = IOUtils.getReaderAsString(request.getReader(), maxDataLen);
129 Properties props = PropertiesUtils.stringToProperties(data);
130 DagEngine dagEngine = Services.get().get(DagEngineService.class).getSystemDagEngine();
131 dagEngine.processCallback(actionId, callbackService.getExternalStatus(queryString), props);
132 }
133 catch (IOException ex) {
134 if (ex.getMessage().startsWith("stream exceeds limit")) {
135 // TODO, WE MUST SET THE ACTION TO ERROR
136 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ErrorCode.E0403, "data too long");
137 }
138 else {
139 throw ex;
140 }
141 }
142 catch (DagEngineException ex) {
143 throw new XServletException(HttpServletResponse.SC_BAD_REQUEST, ex);
144 }
145 }
146 }