diff --git a/azkaban-execserver/src/main/java/azkaban/execapp/event/JobCallbackUtil.java b/azkaban-execserver/src/main/java/azkaban/execapp/event/JobCallbackUtil.java
index c796186..cd576b7 100644
--- a/azkaban-execserver/src/main/java/azkaban/execapp/event/JobCallbackUtil.java
+++ b/azkaban-execserver/src/main/java/azkaban/execapp/event/JobCallbackUtil.java
@@ -19,6 +19,7 @@ import static azkaban.jobcallback.JobCallbackConstants.SERVER_TOKEN;
import static azkaban.jobcallback.JobCallbackConstants.STATUS_TOKEN;
import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -143,7 +144,7 @@ public class JobCallbackUtil {
break;
} else {
String callbackUrlWithTokenReplaced =
- replaceToken(callbackUrl, contextInfo);
+ replaceTokens(callbackUrl, contextInfo, true);
String requestMethodKey =
requestMethod.replace(SEQUENCE_TOKEN, sequenceStr);
@@ -162,7 +163,8 @@ public class JobCallbackUtil {
} else {
// put together an URL
HttpPost httpPost = new HttpPost(callbackUrlWithTokenReplaced);
- String postActualBody = replaceToken(httpBodyValue, contextInfo);
+ String postActualBody =
+ replaceTokens(httpBodyValue, contextInfo, false);
privateLogger.info("postActualBody: " + postActualBody);
httpPost.setEntity(createStringEntity(postActualBody));
httpRequest = httpPost;
@@ -270,25 +272,52 @@ public class JobCallbackUtil {
}
/**
- * Replace the supported tokens in the URL with values in the contextInfo
+ * Replace the supported tokens in the URL with values in the contextInfo.
+ * This will also make sure the values are HTTP encoded.
*
- * @param url
+ * @param value
* @param contextInfo
- * @return String - url with tokens replaced with values
+ * @param withEncoding - whether the token values will be HTTP encoded
+ * @return String - value with tokens replaced with values
*/
- public static String replaceToken(String url, Map<String, String> contextInfo) {
+ public static String replaceTokens(String value,
+ Map<String, String> contextInfo, boolean withEncoding) {
- String result = url;
+ String result = value;
+ String tokenValue =
+ encodeQueryParam(contextInfo.get(SERVER_TOKEN), withEncoding);
+ result = result.replace(SERVER_TOKEN, tokenValue);
- result = result.replace(SERVER_TOKEN, contextInfo.get(SERVER_TOKEN));
- result = result.replace(PROJECT_TOKEN, contextInfo.get(PROJECT_TOKEN));
- result = result.replace(FLOW_TOKEN, contextInfo.get(FLOW_TOKEN));
- result = result.replace(JOB_TOKEN, contextInfo.get(JOB_TOKEN));
- result =
- result.replace(EXECUTION_ID_TOKEN, contextInfo.get(EXECUTION_ID_TOKEN));
- result =
- result.replace(JOB_STATUS_TOKEN, contextInfo.get(JOB_STATUS_TOKEN));
+ tokenValue = encodeQueryParam(contextInfo.get(PROJECT_TOKEN), withEncoding);
+ result = result.replace(PROJECT_TOKEN, tokenValue);
+
+ tokenValue = encodeQueryParam(contextInfo.get(FLOW_TOKEN), withEncoding);
+ result = result.replace(FLOW_TOKEN, tokenValue);
+
+ tokenValue = encodeQueryParam(contextInfo.get(JOB_TOKEN), withEncoding);
+ result = result.replace(JOB_TOKEN, tokenValue);
+
+ tokenValue =
+ encodeQueryParam(contextInfo.get(EXECUTION_ID_TOKEN), withEncoding);
+ result = result.replace(EXECUTION_ID_TOKEN, tokenValue);
+
+ tokenValue =
+ encodeQueryParam(contextInfo.get(JOB_STATUS_TOKEN), withEncoding);
+
+ result = result.replace(JOB_STATUS_TOKEN, tokenValue);
return result;
}
+
+ private static String encodeQueryParam(String str, boolean withEncoding) {
+ if (!withEncoding) {
+ return str;
+ }
+ try {
+ return URLEncoder.encode(str, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new IllegalArgumentException(
+ "Encountered problem during encoding:", e);
+ }
+ }
}
diff --git a/azkaban-execserver/src/test/java/azkaban/execapp/event/JobCallbackUtilTest.java b/azkaban-execserver/src/test/java/azkaban/execapp/event/JobCallbackUtilTest.java
index 33dd0bd..d5e0902 100644
--- a/azkaban-execserver/src/test/java/azkaban/execapp/event/JobCallbackUtilTest.java
+++ b/azkaban-execserver/src/test/java/azkaban/execapp/event/JobCallbackUtilTest.java
@@ -9,6 +9,7 @@ import static azkaban.jobcallback.JobCallbackConstants.JOB_TOKEN;
import static azkaban.jobcallback.JobCallbackConstants.PROJECT_TOKEN;
import static azkaban.jobcallback.JobCallbackConstants.SERVER_TOKEN;
+import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -28,20 +29,22 @@ public class JobCallbackUtilTest {
private static Map<String, String> contextInfo;
private static final String SERVER_NAME = "localhost:9999";
- private static final String PROJECT_NANE = "PROJECTX";
- private static final String FLOW_NANE = "FLOWX";
- private static final String JOB_NANE = "JOBX";
+ private static final String PROJECT_NAME = "PROJECTX";
+ private static final String FLOW_NAME = "FLOWX";
+ private static final String JOB_NAME = "JOBX";
private static final String EXECUTION_ID = "1234";
+ private static final String JOB_STATUS_NAME = JobCallbackStatusEnum.STARTED
+ .name();
@BeforeClass
public static void setup() {
contextInfo = new HashMap<String, String>();
contextInfo.put(SERVER_TOKEN, SERVER_NAME);
- contextInfo.put(PROJECT_TOKEN, PROJECT_NANE);
- contextInfo.put(FLOW_TOKEN, FLOW_NANE);
+ contextInfo.put(PROJECT_TOKEN, PROJECT_NAME);
+ contextInfo.put(FLOW_TOKEN, FLOW_NAME);
contextInfo.put(EXECUTION_ID_TOKEN, EXECUTION_ID);
- contextInfo.put(JOB_TOKEN, JOB_NANE);
- contextInfo.put(JOB_STATUS_TOKEN, JobCallbackStatusEnum.STARTED.name());
+ contextInfo.put(JOB_TOKEN, JOB_NAME);
+ contextInfo.put(JOB_STATUS_TOKEN, JOB_STATUS_NAME);
}
@Test
@@ -157,18 +160,21 @@ public class JobCallbackUtilTest {
@Test
public void noTokenTest() {
String urlWithNoToken = "http://www.linkedin.com";
- String result = JobCallbackUtil.replaceToken(urlWithNoToken, contextInfo);
+ String result =
+ JobCallbackUtil.replaceTokens(urlWithNoToken, contextInfo, true);
Assert.assertEquals(urlWithNoToken, result);
}
@Test
public void oneTokenTest() {
- String urlWithOneToken = "http://www.linkedin.com?project=" + PROJECT_TOKEN;
+ String urlWithOneToken =
+ "http://www.linkedin.com?project=" + PROJECT_TOKEN + "&another=yes";
- String result = JobCallbackUtil.replaceToken(urlWithOneToken, contextInfo);
- Assert.assertEquals("http://www.linkedin.com?project=" + PROJECT_NANE,
- result);
+ String result =
+ JobCallbackUtil.replaceTokens(urlWithOneToken, contextInfo, true);
+ Assert.assertEquals("http://www.linkedin.com?project=" + PROJECT_NAME
+ + "&another=yes", result);
}
@Test
@@ -178,9 +184,53 @@ public class JobCallbackUtilTest {
"http://www.linkedin.com?project=" + PROJECT_TOKEN + "&flow="
+ FLOW_TOKEN;
- String result = JobCallbackUtil.replaceToken(urlWithOneToken, contextInfo);
- Assert.assertEquals("http://www.linkedin.com?project=" + PROJECT_NANE
- + "&flow=" + FLOW_NANE, result);
+ String result =
+ JobCallbackUtil.replaceTokens(urlWithOneToken, contextInfo, true);
+ Assert.assertEquals("http://www.linkedin.com?project=" + PROJECT_NAME
+ + "&flow=" + FLOW_NAME, result);
+ }
+
+ @Test
+ public void allTokensTest() {
+
+ String urlWithOneToken =
+ "http://www.linkedin.com?server=" + SERVER_NAME + "&project="
+ + PROJECT_TOKEN + "&flow=" + FLOW_TOKEN + "&executionId="
+ + EXECUTION_ID_TOKEN + "&job=" + JOB_TOKEN + "&status="
+ + JOB_STATUS_TOKEN;
+
+ String result =
+ JobCallbackUtil.replaceTokens(urlWithOneToken, contextInfo, true);
+
+ String expectedResult =
+ "http://www.linkedin.com?server=" + SERVER_NAME + "&project="
+ + PROJECT_NAME + "&flow=" + FLOW_NAME + "&executionId="
+ + EXECUTION_ID + "&job=" + JOB_NAME + "&status=" + JOB_STATUS_NAME;
+
+ Assert.assertEquals(expectedResult, result);
+ }
+
+ @Test
+ public void tokenWithEncoding() throws Exception {
+ String jobNameWithSpaces = "my job";
+ String encodedJobName = URLEncoder.encode(jobNameWithSpaces, "UTF-8");
+
+ Map<String, String> customContextInfo = new HashMap<String, String>();
+ customContextInfo = new HashMap<String, String>();
+ customContextInfo.put(SERVER_TOKEN, SERVER_NAME);
+ customContextInfo.put(PROJECT_TOKEN, PROJECT_NAME);
+ customContextInfo.put(FLOW_TOKEN, FLOW_NAME);
+ customContextInfo.put(EXECUTION_ID_TOKEN, EXECUTION_ID);
+ customContextInfo.put(JOB_TOKEN, jobNameWithSpaces);
+ customContextInfo.put(JOB_STATUS_TOKEN, JOB_STATUS_NAME);
+
+ String urlWithOneToken =
+ "http://www.linkedin.com?job=" + JOB_TOKEN + "&flow=" + FLOW_TOKEN;
+
+ String result =
+ JobCallbackUtil.replaceTokens(urlWithOneToken, customContextInfo, true);
+ Assert.assertEquals("http://www.linkedin.com?job=" + encodedJobName
+ + "&flow=" + FLOW_NAME, result);
}
@Test