diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/rcmlserver/resolver/RcmlserverResolver.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/rcmlserver/resolver/RcmlserverResolver.java
new file mode 100644
index 0000000000..628f20e6ac
--- /dev/null
+++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/rcmlserver/resolver/RcmlserverResolver.java
@@ -0,0 +1,93 @@
+/*
+ * TeleStax, Open Source Cloud Communications
+ * Copyright 2011-2014, Telestax Inc and individual contributors
+ * by the @authors tag.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ *
+ */
+
+package org.restcomm.connect.http.client.rcmlserver.resolver;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A relative URI resolver for Rcmlserver/RVD. It values defined in rcmlserver restcomm.xml configuration
+ * section (rcmlserver.base-url, rcmlserver.api-path) to convert relative urls to absolute i.e. prepent Rcmlserver origin (http://rcmlserver.domain:port).
+ * By design, the resolver is used when resolving Application.rcmlUrl only. An additional filter prefix
+ * is used and helps the resolver affect only urls that start with "/restcomm-rvd/". This filter value is
+ * configurable through rcmlserver.api-path. It will use whatever it between the first pair of slashes "/.../".
+ * If configuration is missing or rcmlserver is deployed bundled with restcomm the resolver won't affect the
+ * uri resolved, typically leaving UriUtils class take care of it.
+ *
+ * @author otsakir@gmail.com - Orestis Tsakiridis
+ */
+public class RcmlserverResolver {
+ protected static Logger logger = Logger.getLogger(RcmlserverResolver.class);
+ static RcmlserverResolver singleton;
+
+ String rvdOrigin;
+ String filterPrefix; // a pattern used to match against relative urls in application.rcmlUrl. If null, to resolving will occur.
+
+ static final String DEFAULT_FILTER_PREFIX = "/restcomm-rvd/";
+
+ // not really a clean singleton pattern but a way to init once and use many. Only the first time this method is called the parameters are used in the initialization
+ public static RcmlserverResolver getInstance(String rvdOrigin, String apiPath, boolean reinit) {
+ if (singleton == null || reinit) {
+ singleton = new RcmlserverResolver(rvdOrigin, apiPath);
+ }
+ return singleton;
+ }
+
+ public static RcmlserverResolver getInstance(String rvdOrigin, String apiPath) {
+ return getInstance(rvdOrigin, apiPath, false);
+ }
+
+ public RcmlserverResolver(String rvdOrigin, String apiPath) {
+ this.rvdOrigin = rvdOrigin;
+ if ( ! StringUtils.isEmpty(apiPath) ) {
+ // extract the first part of the path and use it as a filter prefix
+ Pattern pattern = Pattern.compile("/([^/]*)((/.*)|$)");
+ Matcher matcher = pattern.matcher(apiPath);
+ if (matcher.matches() && matcher.group(1) != null) {
+ filterPrefix = "/" + matcher.group(1) + "/";
+ } else
+ filterPrefix = DEFAULT_FILTER_PREFIX;
+ logger.info("RcmlserverResolver initialized. Urls starting with '" + filterPrefix + "' will get prepended with '" + (rvdOrigin == null ? "" : rvdOrigin) + "'");
+ } else
+ filterPrefix = null;
+ }
+
+ // if rvdOrigin is null no point in trying to resolve RVD location. We will return passed uri instead
+ public URI resolveRelative(URI uri) {
+ if (uri != null && rvdOrigin != null && filterPrefix != null) {
+ if (uri.isAbsolute())
+ return uri;
+ try {
+ String uriString = uri.toString();
+ if (uriString.startsWith(filterPrefix))
+ return new URI(rvdOrigin + uri.toString());
+ } catch (URISyntaxException e) {
+ logger.error("Cannot resolve uri: " + uri.toString() + ". Ignoring...", e);
+ }
+ }
+ return uri;
+ }
+}
diff --git a/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/client/rcmlserver/resolver/RcmlserverResolverTest.java b/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/client/rcmlserver/resolver/RcmlserverResolverTest.java
new file mode 100644
index 0000000000..c8ccbe241c
--- /dev/null
+++ b/restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/client/rcmlserver/resolver/RcmlserverResolverTest.java
@@ -0,0 +1,62 @@
+/*
+ * TeleStax, Open Source Cloud Communications
+ * Copyright 2011-2014, Telestax Inc and individual contributors
+ * by the @authors tag.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see
+ *
+ */
+
+package org.restcomm.connect.http.client.rcmlserver.resolver;
+
+import junit.framework.Assert;
+import org.junit.Test;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+/**
+ * @author otsakir@gmail.com - Orestis Tsakiridis
+ */
+public class RcmlserverResolverTest {
+ @Test
+ public void testResolving() throws URISyntaxException {
+ RcmlserverResolver resolver = RcmlserverResolver.getInstance("http://rvdserver.org","/restcomm-rvd/services/", true);
+ URI uri = resolver.resolveRelative(new URI("/restcomm-rvd/services/apps/AP5f58b0baf6e14001b6eec02295fab05a/controller"));
+ // relative urls to actual RVD applications should get prefixed
+ Assert.assertEquals("http://rvdserver.org/restcomm-rvd/services/apps/AP5f58b0baf6e14001b6eec02295fab05a/controller", uri.toString());
+ // absolute urls should not be touched
+ uri = resolver.resolveRelative(new URI("http://externalserver/AP5f58b0baf6e14001b6eec02295fab05a/controller"));
+ Assert.assertEquals("http://externalserver/AP5f58b0baf6e14001b6eec02295fab05a/controller", uri.toString());
+ // relative urls pointing to other (non-rvd) apps
+ uri = resolver.resolveRelative(new URI("/restcomm/demos/hellp-play.xml"));
+ Assert.assertEquals("/restcomm/demos/hellp-play.xml", uri.toString());
+ // make sure that RVD path can vary. Assume it's '/new-rvd' now
+ resolver = RcmlserverResolver.getInstance("http://rvdserver.org","/new-rvd/services/", true);
+ uri = resolver.resolveRelative(new URI("/new-rvd/myapp.xml"));
+ Assert.assertEquals("http://rvdserver.org/new-rvd/myapp.xml", uri.toString());
+ // if rcmlserver.baseUrl is null, no resolving should occur
+ resolver = RcmlserverResolver.getInstance(null,"/restcomm-rvd/services", true);
+ uri = resolver.resolveRelative(new URI("/restcomm-rvd/services/apps/xxxx"));
+ Assert.assertEquals("/restcomm-rvd/services/apps/xxxx", uri.toString());
+ // if rcmlserver.apiPath is null or empty, no resolving should occur
+ resolver = RcmlserverResolver.getInstance("http://rvdotsakir.org","", true);
+ uri = resolver.resolveRelative(new URI("/restcomm-rvd/services/apps/xxxx"));
+ Assert.assertEquals("/restcomm-rvd/services/apps/xxxx", uri.toString());
+ // all nulls
+ resolver = RcmlserverResolver.getInstance(null,null, true);
+ uri = resolver.resolveRelative(new URI("/restcomm-rvd/services/apps/xxxx"));
+ Assert.assertEquals("/restcomm-rvd/services/apps/xxxx", uri.toString());
+ }
+}
diff --git a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsService.java b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsService.java
index e58b3815cb..44a4bfc464 100644
--- a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsService.java
+++ b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsService.java
@@ -31,6 +31,8 @@
import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
import org.apache.commons.configuration.Configuration;
import org.joda.time.DateTime;
+import org.restcomm.connect.commons.configuration.RestcommConfiguration;
+import org.restcomm.connect.commons.configuration.sets.RcmlserverConfigurationSet;
import org.restcomm.connect.commons.dao.Sid;
import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor;
import org.restcomm.connect.commons.util.UriUtils;
@@ -53,6 +55,7 @@
import org.restcomm.connect.extension.api.RestcommExtensionException;
import org.restcomm.connect.extension.api.RestcommExtensionGeneric;
import org.restcomm.connect.extension.controller.ExtensionController;
+import org.restcomm.connect.http.client.rcmlserver.resolver.RcmlserverResolver;
import org.restcomm.connect.interpreter.SmsInterpreter;
import org.restcomm.connect.interpreter.SmsInterpreterParams;
import org.restcomm.connect.interpreter.StartInterpreter;
@@ -299,7 +302,9 @@ private boolean redirectToHostedSmsApp(final ActorRef self, final SipServletRequ
final Sid sid = number.getSmsApplicationSid();
if (sid != null) {
final Application application = applications.getApplication(sid);
- builder.setUrl(UriUtils.resolve(application.getRcmlUrl()));
+ RcmlserverConfigurationSet rcmlserverConfig = RestcommConfiguration.getInstance().getRcmlserver();
+ RcmlserverResolver resolver = RcmlserverResolver.getInstance(rcmlserverConfig.getBaseUrl(), rcmlserverConfig.getApiPath());
+ builder.setUrl(UriUtils.resolve(resolver.resolveRelative(application.getRcmlUrl())));
} else {
builder.setUrl(UriUtils.resolve(appUri));
}
diff --git a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppMessageHandler.java b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppMessageHandler.java
index e00354ca0a..7b1b595e63 100644
--- a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppMessageHandler.java
+++ b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppMessageHandler.java
@@ -18,6 +18,8 @@
import com.cloudhopper.smpp.type.UnrecoverablePduException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import org.apache.commons.configuration.Configuration;
+import org.restcomm.connect.commons.configuration.RestcommConfiguration;
+import org.restcomm.connect.commons.configuration.sets.RcmlserverConfigurationSet;
import org.restcomm.connect.commons.dao.Sid;
import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor;
import org.restcomm.connect.commons.util.UriUtils;
@@ -32,6 +34,7 @@
import org.restcomm.connect.extension.api.RestcommExtensionException;
import org.restcomm.connect.extension.api.RestcommExtensionGeneric;
import org.restcomm.connect.extension.controller.ExtensionController;
+import org.restcomm.connect.http.client.rcmlserver.resolver.RcmlserverResolver;
import org.restcomm.connect.interpreter.StartInterpreter;
import org.restcomm.connect.monitoringservice.MonitoringService;
import org.restcomm.connect.sms.SmsSession;
@@ -166,7 +169,9 @@ private boolean redirectToHostedSmsApp(final ActorRef self, final SmppInboundMes
final Sid sid = number.getSmsApplicationSid();
if (sid != null) {
final Application application = applications.getApplication(sid);
- builder.setUrl(UriUtils.resolve(application.getRcmlUrl()));
+ RcmlserverConfigurationSet rcmlserverConfig = RestcommConfiguration.getInstance().getRcmlserver();
+ RcmlserverResolver resolver = RcmlserverResolver.getInstance(rcmlserverConfig.getBaseUrl(), rcmlserverConfig.getApiPath());
+ builder.setUrl(UriUtils.resolve(resolver.resolveRelative(application.getRcmlUrl())));
} else if (appUri != null) {
builder.setUrl(UriUtils.resolve(appUri));
} else {
diff --git a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/CallManager.java b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/CallManager.java
index 46c37fe15c..4ca9f6182c 100644
--- a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/CallManager.java
+++ b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/CallManager.java
@@ -38,6 +38,7 @@
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.joda.time.DateTime;
import org.restcomm.connect.commons.configuration.RestcommConfiguration;
+import org.restcomm.connect.commons.configuration.sets.RcmlserverConfigurationSet;
import org.restcomm.connect.commons.dao.Sid;
import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor;
import org.restcomm.connect.commons.patterns.StopObserving;
@@ -65,6 +66,7 @@
import org.restcomm.connect.extension.api.RestcommExtensionException;
import org.restcomm.connect.extension.api.RestcommExtensionGeneric;
import org.restcomm.connect.extension.controller.ExtensionController;
+import org.restcomm.connect.http.client.rcmlserver.resolver.RcmlserverResolver;
import org.restcomm.connect.interpreter.StartInterpreter;
import org.restcomm.connect.interpreter.StopInterpreter;
import org.restcomm.connect.interpreter.VoiceInterpreter;
@@ -1124,7 +1126,9 @@ private void transfer(SipServletRequest request) throws Exception {
if (number.getReferApplicationSid() != null) {
Application application = storage.getApplicationsDao().getApplication(number.getReferApplicationSid());
- builder.setUrl(UriUtils.resolve(application.getRcmlUrl()));
+ RcmlserverConfigurationSet rcmlserverConfig = RestcommConfiguration.getInstance().getRcmlserver();
+ RcmlserverResolver resolver = RcmlserverResolver.getInstance(rcmlserverConfig.getBaseUrl(), rcmlserverConfig.getApiPath());
+ builder.setUrl(UriUtils.resolve(resolver.resolveRelative(application.getRcmlUrl())));
} else {
builder.setUrl(UriUtils.resolve(number.getReferUrl()));
}
@@ -1229,7 +1233,9 @@ private boolean redirectToHostedVoiceApp(final ActorRef self, final SipServletRe
final Sid sid = number.getVoiceApplicationSid();
if (sid != null) {
final Application application = applications.getApplication(sid);
- builder.setUrl(UriUtils.resolve(application.getRcmlUrl()));
+ RcmlserverConfigurationSet rcmlserverConfig = RestcommConfiguration.getInstance().getRcmlserver();
+ RcmlserverResolver rcmlserverResolver = RcmlserverResolver.getInstance(rcmlserverConfig.getBaseUrl(), rcmlserverConfig.getApiPath());
+ builder.setUrl(UriUtils.resolve(rcmlserverResolver.resolveRelative(application.getRcmlUrl())));
} else {
builder.setUrl(UriUtils.resolve(number.getVoiceUrl()));
}
@@ -1287,7 +1293,9 @@ private boolean redirectToClientVoiceApp(final ActorRef self, final SipServletRe
URI clientAppVoiceUrl = null;
if (applicationSid != null) {
final Application application = applications.getApplication(applicationSid);
- clientAppVoiceUrl = UriUtils.resolve(application.getRcmlUrl());
+ RcmlserverConfigurationSet rcmlserverConfig = RestcommConfiguration.getInstance().getRcmlserver();
+ RcmlserverResolver resolver = RcmlserverResolver.getInstance(rcmlserverConfig.getBaseUrl(), rcmlserverConfig.getApiPath());
+ clientAppVoiceUrl = UriUtils.resolve(resolver.resolveRelative(application.getRcmlUrl()));
}
if (clientAppVoiceUrl == null) {
clientAppVoiceUrl = client.getVoiceUrl();
diff --git a/restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/telephony/UssdCallManager.java b/restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/telephony/UssdCallManager.java
index f4a8cd57d3..aa0490b4e7 100644
--- a/restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/telephony/UssdCallManager.java
+++ b/restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/telephony/UssdCallManager.java
@@ -26,6 +26,8 @@
import akka.event.Logging;
import akka.event.LoggingAdapter;
import org.apache.commons.configuration.Configuration;
+import org.restcomm.connect.commons.configuration.RestcommConfiguration;
+import org.restcomm.connect.commons.configuration.sets.RcmlserverConfigurationSet;
import org.restcomm.connect.commons.dao.Sid;
import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor;
import org.restcomm.connect.commons.util.UriUtils;
@@ -36,6 +38,7 @@
import org.restcomm.connect.dao.entities.Account;
import org.restcomm.connect.dao.entities.Application;
import org.restcomm.connect.dao.entities.IncomingPhoneNumber;
+import org.restcomm.connect.http.client.rcmlserver.resolver.RcmlserverResolver;
import org.restcomm.connect.interpreter.StartInterpreter;
import org.restcomm.connect.telephony.api.CallManagerResponse;
import org.restcomm.connect.telephony.api.CreateCall;
@@ -217,7 +220,9 @@ private boolean redirectToHostedVoiceApp(final ActorRef self, final SipServletRe
final Sid sid = number.getUssdApplicationSid();
if (sid != null) {
final Application application = applications.getApplication(sid);
- builder.setUrl(UriUtils.resolve(application.getRcmlUrl()));
+ RcmlserverConfigurationSet rcmlserverConfig = RestcommConfiguration.getInstance().getRcmlserver();
+ RcmlserverResolver resolver = RcmlserverResolver.getInstance(rcmlserverConfig.getBaseUrl(), rcmlserverConfig.getApiPath());
+ builder.setUrl(UriUtils.resolve(resolver.resolveRelative(application.getRcmlUrl())));
} else {
builder.setUrl(UriUtils.resolve(number.getUssdUrl()));
}