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 }