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.service;
016
017 import org.apache.oozie.service.Service;
018 import org.apache.oozie.service.Services;
019 import org.apache.oozie.util.ParamChecker;
020 import org.apache.hadoop.conf.Configuration;
021
022 import java.io.UnsupportedEncodingException;
023 import java.net.URLDecoder;
024 import java.text.MessageFormat;
025
026 /**
027 * Service that generates and parses callback URLs.
028 */
029 public class CallbackService implements Service {
030
031 public static final String CONF_PREFIX = Service.CONF_PREFIX + "CallbackService.";
032
033 public static final String CONF_BASE_URL = CONF_PREFIX + "base.url";
034
035 private Configuration oozieConf;
036
037 /**
038 * Initialize the service.
039 *
040 * @param services services instance.
041 */
042 public void init(Services services) {
043 oozieConf = services.getConf();
044 }
045
046 /**
047 * Destroy the service.
048 */
049 public void destroy() {
050 }
051
052 /**
053 * Return the public interface of the Dag engine service.
054 *
055 * @return {@link CallbackService}.
056 */
057 public Class<? extends Service> getInterface() {
058 return CallbackService.class;
059 }
060
061 private static final String ID_PARAM = "id=";
062 private static final String STATUS_PARAM = "&status=";
063 private static final String CALL_BACK_QUERY_STRING = "{0}?" + ID_PARAM + "{1}" + STATUS_PARAM + "{2}&";
064
065 /**
066 * Create a callback URL.
067 *
068 * @param actionId action ID for the callback URL.
069 * @param externalStatusVar variable for the caller to inject the external status.
070 * @return the callback URL.
071 */
072 public String createCallBackUrl(String actionId, String externalStatusVar) {
073 ParamChecker.notEmpty(actionId, "actionId");
074 ParamChecker.notEmpty(externalStatusVar, "externalStatusVar");
075 //TODO: figure out why double encoding is happening in case of hadoop callbacks.
076 String baseCallbackUrl = oozieConf.get(CONF_BASE_URL, "http://localhost:8080/oozie/v0/callback");
077 return MessageFormat.format(CALL_BACK_QUERY_STRING, baseCallbackUrl, actionId, externalStatusVar);
078 }
079
080 private String getParam(String str, String name) {
081 String value = null;
082 int start = str.indexOf(name);
083 if (start > -1) {
084 int end = str.indexOf("&", start + 1);
085 start = start + name.length();
086 value = (end > -1) ? str.substring(start, end) : str.substring(start);
087 }
088 return value;
089 }
090
091 /**
092 * Return if a callback URL is valid or not.
093 *
094 * @param callback callback URL (it can be just the callback portion of it).
095 * @return <code>true</code> if the callback URL is valid, <code>false</code> if it is not.
096 */
097 public boolean isValid(String callback) {
098 return callback != null && getParam(callback, ID_PARAM) != null && getParam(callback, STATUS_PARAM) != null;
099 }
100
101 /**
102 * Return the action ID from a callback URL.
103 *
104 * @param callback callback URL (it can be just the callback portion of it).
105 * @return the action ID from a callback URL.
106 */
107 public String getActionId(String callback) {
108 try {
109 return URLDecoder.decode(getParam(ParamChecker.notEmpty(callback, "callback"), ID_PARAM), "UTF-8");
110 }
111 catch (UnsupportedEncodingException ex) {
112 throw new RuntimeException(ex);
113 }
114 }
115
116 /**
117 * Return the action external status from a callback URL.
118 *
119 * @param callback callback URL (it can be just the callback portion of it).
120 * @return the action external status from a callback URL.
121 */
122 public String getExternalStatus(String callback) {
123 try {
124 return URLDecoder.decode(getParam(ParamChecker.notEmpty(callback, "callback"), STATUS_PARAM), "UTF-8");
125 }
126 catch (UnsupportedEncodingException ex) {
127 throw new RuntimeException(ex);
128 }
129 }
130
131 }