001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 package org.apache.oozie.service; 019 020 import org.apache.oozie.service.Service; 021 import org.apache.oozie.service.Services; 022 import org.apache.oozie.util.ParamChecker; 023 import org.apache.hadoop.conf.Configuration; 024 025 import java.io.UnsupportedEncodingException; 026 import java.net.URLDecoder; 027 import java.text.MessageFormat; 028 029 /** 030 * Service that generates and parses callback URLs. 031 */ 032 public class CallbackService implements Service { 033 034 public static final String CONF_PREFIX = Service.CONF_PREFIX + "CallbackService."; 035 036 public static final String CONF_BASE_URL = CONF_PREFIX + "base.url"; 037 038 private Configuration oozieConf; 039 040 /** 041 * Initialize the service. 042 * 043 * @param services services instance. 044 */ 045 public void init(Services services) { 046 oozieConf = services.getConf(); 047 } 048 049 /** 050 * Destroy the service. 051 */ 052 public void destroy() { 053 } 054 055 /** 056 * Return the public interface of the Dag engine service. 057 * 058 * @return {@link CallbackService}. 059 */ 060 public Class<? extends Service> getInterface() { 061 return CallbackService.class; 062 } 063 064 private static final String ID_PARAM = "id="; 065 private static final String STATUS_PARAM = "status="; 066 private static final String CALL_BACK_QUERY_STRING = "{0}?" + ID_PARAM + "{1}" + "&" + STATUS_PARAM + "{2}&"; 067 068 /** 069 * Create a callback URL. 070 * 071 * @param actionId action ID for the callback URL. 072 * @param externalStatusVar variable for the caller to inject the external status. 073 * @return the callback URL. 074 */ 075 public String createCallBackUrl(String actionId, String externalStatusVar) { 076 ParamChecker.notEmpty(actionId, "actionId"); 077 ParamChecker.notEmpty(externalStatusVar, "externalStatusVar"); 078 //TODO: figure out why double encoding is happening in case of hadoop callbacks. 079 String baseCallbackUrl = oozieConf.get(CONF_BASE_URL, "http://localhost:8080/oozie/v0/callback"); 080 return MessageFormat.format(CALL_BACK_QUERY_STRING, baseCallbackUrl, actionId, externalStatusVar); 081 } 082 083 private String getParam(String str, String name) { 084 String value = null; 085 int start = str.indexOf(name); 086 if (start > -1) { 087 int end = str.indexOf("&", start + 1); 088 start = start + name.length(); 089 value = (end > -1) ? str.substring(start, end) : str.substring(start); 090 } 091 return value; 092 } 093 094 /** 095 * Return if a callback URL is valid or not. 096 * 097 * @param callback callback URL (it can be just the callback portion of it). 098 * @return <code>true</code> if the callback URL is valid, <code>false</code> if it is not. 099 */ 100 public boolean isValid(String callback) { 101 return callback != null && getParam(callback, ID_PARAM) != null && getParam(callback, STATUS_PARAM) != null; 102 } 103 104 /** 105 * Return the action ID from a callback URL. 106 * 107 * @param callback callback URL (it can be just the callback portion of it). 108 * @return the action ID from a callback URL. 109 */ 110 public String getActionId(String callback) { 111 try { 112 return URLDecoder.decode(getParam(ParamChecker.notEmpty(callback, "callback"), ID_PARAM), "UTF-8"); 113 } 114 catch (UnsupportedEncodingException ex) { 115 throw new RuntimeException(ex); 116 } 117 } 118 119 /** 120 * Return the action external status from a callback URL. 121 * 122 * @param callback callback URL (it can be just the callback portion of it). 123 * @return the action external status from a callback URL. 124 */ 125 public String getExternalStatus(String callback) { 126 try { 127 return URLDecoder.decode(getParam(ParamChecker.notEmpty(callback, "callback"), STATUS_PARAM), "UTF-8"); 128 } 129 catch (UnsupportedEncodingException ex) { 130 throw new RuntimeException(ex); 131 } 132 } 133 134 }