From 4e2b8ca7334648f08e4e7e1293615b8fdfbbe53e Mon Sep 17 00:00:00 2001 From: Eugene Lapin Date: Fri, 7 Jul 2017 14:09:12 +0300 Subject: [PATCH 01/34] Add AsrSignal support --- .../restcomm/autoconfig.d/config-restcomm.sh | 17 + .../as7-config-scripts/restcomm/restcomm.conf | 8 +- .../src/main/webapp/WEB-INF/conf/restcomm.xml | 17 + .../configuration/RestcommConfiguration.java | 8 +- .../sets/impl/MgAsrConfigurationSet.java | 62 ++ .../connect/commons/dao/CollectedResult.java | 58 ++ .../configuration/MgAsrConfigurationTest.java | 82 +++ .../src/test/resources/restcomm-no-mg-asr.xml | 381 ++++++++++++ .../src/test/resources/restcomm.xml | 17 + restcomm/restcomm.interpreter/pom.xml | 7 +- .../interpreter/BaseVoiceInterpreter.java | 232 +++++-- .../connect/interpreter/VoiceInterpreter.java | 94 ++- .../connect/interpreter/rcml/Attribute.java | 8 + .../rcml/domain/GatherAttributes.java | 41 ++ .../interpreter/rcml/GatherSpeechTest.java | 392 ++++++++++++ .../connect/interpreter/rcml/MockedActor.java | 140 +++++ .../src/test/resources/restcomm.xml | 583 ++++++++++++++++++ restcomm/restcomm.mgcp/pom.xml | 6 + .../org/restcomm/connect/mgcp/AsrSignal.java | 111 ++++ .../restcomm/connect/mgcp/IvrEndpoint.java | 83 ++- .../connect/mgcp/IvrEndpointResponse.java | 5 +- .../restcomm/connect/mgcp/MediaGateway.java | 15 +- .../org/restcomm/connect/mgcp/MgcpUtil.java | 58 ++ .../mgcp/AbstractMockMediaGateway.java | 2 + .../restcomm/connect/mgcp/AsrSignalTest.java | 82 +++ .../connect/mgcp/IvrAsrEndpointTest.java | 301 +++++++++ .../connect/mgcp/IvrEndpointTest.java | 40 +- .../mscontrol/api/messages/Collect.java | 44 +- .../connect/mscontrol/mms/MgcpMediaGroup.java | 79 ++- 29 files changed, 2770 insertions(+), 203 deletions(-) create mode 100644 restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/impl/MgAsrConfigurationSet.java create mode 100644 restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/dao/CollectedResult.java create mode 100644 restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/MgAsrConfigurationTest.java create mode 100644 restcomm/restcomm.commons/src/test/resources/restcomm-no-mg-asr.xml create mode 100644 restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/rcml/domain/GatherAttributes.java create mode 100644 restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/rcml/GatherSpeechTest.java create mode 100644 restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/rcml/MockedActor.java create mode 100644 restcomm/restcomm.interpreter/src/test/resources/restcomm.xml create mode 100644 restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java create mode 100644 restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MgcpUtil.java create mode 100644 restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AsrSignalTest.java create mode 100644 restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-restcomm.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-restcomm.sh index 680edbbfe2..5db1570dfe 100755 --- a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-restcomm.sh +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-restcomm.sh @@ -602,6 +602,22 @@ configRMSNetworking() { fi } +configAsrDriver() { + if [ ! -z "$MG_ASR_DRIVERS" ] && [ ! -z "$MG_ASR_DRIVER_DEFAULT" ]; then + FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml + xmlstarlet ed -d "/restcomm/runtime-settings/mg-asr-drivers" \ + -s "/restcomm/runtime-settings" -t elem -n mg-asr-drivers \ + -i "/restcomm/runtime-settings/mg-asr-drivers" -t attr -n default -v "$MG_ASR_DRIVER_DEFAULT" \ + $FILE > $FILE.bak + mv $FILE.bak $FILE + for driverName in ${MG_ASR_DRIVERS//,/ }; do + xmlstarlet ed -s "/restcomm/runtime-settings/mg-asr-drivers" -t elem -n "driver" -v "$driverName" \ + $FILE > $FILE.bak + mv $FILE.bak $FILE + done + fi +} + # MAIN echo 'Configuring RestComm...' configRCJavaOpts @@ -641,4 +657,5 @@ otherRestCommConf confRcmlserver confRVD configRMSNetworking +configAsrDriver echo 'Configured RestComm!' diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/restcomm.conf b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/restcomm.conf index b4d1d64822..d20bcaa115 100755 --- a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/restcomm.conf +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/restcomm.conf @@ -106,4 +106,10 @@ LOG_LEVEL_COMPONENT_SIPRESTCOMM='INFO' #Log level for "org.mobicents.servlet.sip LOG_LEVEL_COMPONENT_RESTCOMM='INFO' #Log level for "org.restcomm.connect" module #AKKA log level. Set the Log level for the AKKA actor system. -AKKA_LOG_LEVEL='INFO' \ No newline at end of file +AKKA_LOG_LEVEL='INFO' + +#ASR drivers +#list of drivers divided with comma, for example: "driver1,driver2,driver3" +MG_ASR_DRIVERS="" +#default asr driver to use. It has to be included to MG_ASR_DRIVERS +MG_ASR_DRIVER_DEFAULT="" \ No newline at end of file diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/restcomm.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/restcomm.xml index 8f96ed1e3f..724472fa25 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/restcomm.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/restcomm.xml @@ -27,6 +27,23 @@ beep.wav alert.wav + + + en-US + en-GB + es-ES + it-IT + fr-FR + pl-PL + pt-PT + + + + + ${restcomm:home}/cache /restcomm/cache diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/RestcommConfiguration.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/RestcommConfiguration.java index 0c7ba036d5..a5746eb4f1 100644 --- a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/RestcommConfiguration.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/RestcommConfiguration.java @@ -26,10 +26,11 @@ import org.apache.commons.configuration.Configuration; import org.restcomm.connect.commons.configuration.sets.CacheConfigurationSet; import org.restcomm.connect.commons.configuration.sets.RcmlserverConfigurationSet; +import org.restcomm.connect.commons.configuration.sets.MainConfigurationSet; import org.restcomm.connect.commons.configuration.sets.impl.CacheConfigurationSetImpl; import org.restcomm.connect.commons.configuration.sets.impl.ConfigurationSet; -import org.restcomm.connect.commons.configuration.sets.MainConfigurationSet; import org.restcomm.connect.commons.configuration.sets.impl.MainConfigurationSetImpl; +import org.restcomm.connect.commons.configuration.sets.impl.MgAsrConfigurationSet; import org.restcomm.connect.commons.configuration.sets.impl.RcmlserverConfigurationSetImpl; import org.restcomm.connect.commons.configuration.sources.ApacheConfigurationSource; @@ -55,6 +56,7 @@ public RestcommConfiguration(Configuration apacheConf) { addConfigurationSet("main", new MainConfigurationSetImpl(apacheCfgSrc)); addConfigurationSet("cache", new CacheConfigurationSetImpl(apacheCfgSrc)); addConfigurationSet("rcmlserver", new RcmlserverConfigurationSetImpl(apacheCfgSrc)); + addConfigurationSet("mg-asr", new MgAsrConfigurationSet(apacheCfgSrc, apacheConf)); // addConfigurationSet("identity", new IdentityConfigurationSet( new DbConfigurationSource(dbConf))); // ... @@ -86,6 +88,10 @@ public CacheConfigurationSet getCache() { public RcmlserverConfigurationSet getRcmlserver() { return (RcmlserverConfigurationSet) sets.get("rcmlserver"); } + public MgAsrConfigurationSet getMgAsr() { + return (MgAsrConfigurationSet) sets.get("mg-asr"); + } + // singleton stuff private static RestcommConfiguration instance; public static RestcommConfiguration createOnce(Configuration apacheConf) { diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/impl/MgAsrConfigurationSet.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/impl/MgAsrConfigurationSet.java new file mode 100644 index 0000000000..f50c3f7467 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/configuration/sets/impl/MgAsrConfigurationSet.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.commons.configuration.sets.impl; + +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.configuration.sources.ConfigurationSource; + +import java.util.Collections; +import java.util.List; + +/** + * Created by gdubina on 26.06.17. + */ +public class MgAsrConfigurationSet extends ConfigurationSet { + + private final List drivers; + private final String defaultDriver; + private final List languages; + private final String defaultLanguage; + + public MgAsrConfigurationSet(ConfigurationSource source, Configuration config) { + super(source); + drivers = Collections.unmodifiableList(config.getList("runtime-settings.mg-asr-drivers.driver")); + defaultDriver = config.getString("runtime-settings.mg-asr-drivers[@default]"); + languages = Collections.unmodifiableList(config.getList("runtime-settings.asr-languages.language")); + defaultLanguage = config.getString("runtime-settings.asr-languages[@default]"); + } + + public List getDrivers() { + return drivers; + } + + public String getDefaultDriver() { + return defaultDriver; + } + + public List getLanguages() { + return languages; + } + + public String getDefaultLanguage() { + return defaultLanguage; + } +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/dao/CollectedResult.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/dao/CollectedResult.java new file mode 100644 index 0000000000..1615d02e9b --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/dao/CollectedResult.java @@ -0,0 +1,58 @@ +/* + * 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.commons.dao; + +/** + * Created by gdubina on 6/6/17. + */ +public class CollectedResult { + + private final String result; + private final boolean isAsr; + private final boolean isPartial; + + public CollectedResult(String result, boolean isAsr, boolean isPartial) { + this.result = result; + this.isAsr = isAsr; + this.isPartial = isPartial; + } + + public String getResult() { + return result; + } + + public boolean isAsr() { + return isAsr; + } + + public boolean isPartial() { + return isPartial; + } + + @Override + public String toString() { + return "CollectedResult{" + + "result='" + result + '\'' + + ", isAsr=" + isAsr + + ", isPartial=" + isPartial + + '}'; + } +} diff --git a/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/MgAsrConfigurationTest.java b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/MgAsrConfigurationTest.java new file mode 100644 index 0000000000..e91c1125f0 --- /dev/null +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/configuration/MgAsrConfigurationTest.java @@ -0,0 +1,82 @@ +/* + * 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.commons.configuration; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.configuration.Configuration; +import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.configuration.XMLConfiguration; +import org.junit.Test; +import org.restcomm.connect.commons.configuration.sets.impl.MgAsrConfigurationSet; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +public class MgAsrConfigurationTest { + + private List expectedDrivers = Arrays.asList("driver1", "driver2"); + + private List expectedLanguages = Arrays.asList("en-US", "en-GB", "es-ES", "it-IT", "fr-FR", "pl-PL", "pt-PT"); + + private RestcommConfiguration createCfg(final String cfgFileName) throws ConfigurationException, + MalformedURLException { + URL url = this.getClass().getResource(cfgFileName); + + Configuration xml = new XMLConfiguration(url); + return new RestcommConfiguration(xml); + } + + public MgAsrConfigurationTest() { + super(); + } + + @Test + public void checkMgAsrSection() throws ConfigurationException, MalformedURLException { + MgAsrConfigurationSet conf = createCfg("/restcomm.xml").getMgAsr(); + + assertTrue(CollectionUtils.isEqualCollection(expectedDrivers, conf.getDrivers())); + assertEquals("driver1", conf.getDefaultDriver()); + } + + @Test + public void checkNoMgAsrSection() throws ConfigurationException, MalformedURLException { + MgAsrConfigurationSet conf = createCfg("/restcomm-no-mg-asr.xml").getMgAsr(); + + assertTrue(CollectionUtils.isEqualCollection(Collections.emptyList(), conf.getDrivers())); + assertNull(conf.getDefaultDriver()); + } + + @Test + public void checkAsrLanguagesSection() throws ConfigurationException, MalformedURLException { + MgAsrConfigurationSet conf = createCfg("/restcomm.xml").getMgAsr(); + + assertTrue(CollectionUtils.isEqualCollection(expectedLanguages, conf.getLanguages())); + assertEquals("en-US", conf.getDefaultLanguage()); + } + +} diff --git a/restcomm/restcomm.commons/src/test/resources/restcomm-no-mg-asr.xml b/restcomm/restcomm.commons/src/test/resources/restcomm-no-mg-asr.xml new file mode 100644 index 0000000000..14728d1641 --- /dev/null +++ b/restcomm/restcomm.commons/src/test/resources/restcomm-no-mg-asr.xml @@ -0,0 +1,381 @@ + + + + + + 2012-04-24 + + + true + + + http://127.0.0.1:8080/restcomm/audio + + + ${restcomm:home}/cache + http://127.0.0.1:8080/restcomm/cache + + + file://${restcomm:home}/recordings + http://127.0.0.1:8080/restcomm/recordings + + + http://127.0.0.1:8080/restcomm/errors + + + + + + true + + + false + + + true + + + false + + true + + + + true + + + false + + + + + + 127.0.0.1:5070 + + + + + 127.0.0.1:5090 + + + + + false + + + true + + + false + + 20 + + true + + + + false + restcomm + restcomm + restcomm_instance_id + site_id + http://127.0.0.1:2080 + + + + + + + + + + + + + RestComm:*:Accounts + RestComm:*:Applications + RestComm:*:Announcements + RestComm:Read:AvailablePhoneNumbers + RestComm:*:Calls + RestComm:*:Clients + RestComm:*:Conferences + RestComm:Create,Delete,Read:Faxes + RestComm:*:IncomingPhoneNumbers + RestComm:Read:Notifications + RestComm:*:OutgoingCallerIds + RestComm:Delete,Read:Recordings + RestComm:Read,Modify:SandBoxes + RestComm:*:ShortCodes + RestComm:Read:SmsMessages + RestComm:Read:Transcriptions + RestComm:*:OutboundProxies + + + + + + + + + + + + + + + + + + + + + + https://backoffice.voipinnovations.com/api2.pl + + + + + + + https://api.inetwork.com/v1.0 + + + + + https://rest.nexmo.com/ + + + + + https://api.voxbone.com/ws-voxbone/services/rest + + + + + + + + + + + + + + + + + + + false + restcomm-recordings + + + + false + 7 + true + + + + + rms + +
127.0.0.1
+ 5060 + udp + 5 +
+
+ + + + + 127.0.0.1 + 2727 + 127.0.0.1 + 2427 + 500 + + + + + + + + + 5000 + + strict + + true + + + + + + + + 127.0.0.1:5070 + + + + + + + + + + + + + + + + + http://api.voicerss.org + + + ca-es + zh-cn + zh-hk + zh-tw + da-dk + nl-nl + en-au + en-ca + en-gb + en-in + en-us + fi-fi + fr-ca + fr-fr + de-de + it-it + ja-jp + ko-kr + nb-no + pl-pl + pt-br + pt-pt + ru-ru + es-mx + es-es + sv-se + + + + + +
diff --git a/restcomm/restcomm.commons/src/test/resources/restcomm.xml b/restcomm/restcomm.commons/src/test/resources/restcomm.xml index 14728d1641..5952bfffeb 100644 --- a/restcomm/restcomm.commons/src/test/resources/restcomm.xml +++ b/restcomm/restcomm.commons/src/test/resources/restcomm.xml @@ -14,6 +14,23 @@ 2012-04-24 + + + en-US + en-GB + es-ES + it-IT + fr-FR + pl-PL + pt-PT + + + + + driver1 + driver2 + + + + + + 2012-04-24 + + + false + + + /restcomm/audio + + + beep.wav + alert.wav + + + + google + + + + ${restcomm:home}/cache + /restcomm/cache + + + false + + + file://${restcomm:home}/recordings + /restcomm/recordings + + + /restcomm/errors + + + + + + true + + + false + + + true + + + + false + + + 5060 + WebRTCGW__1@ + WebRTCGW/1.0 + + + + + 60 + + + false + + true + + + + true + + + false + + + + false + + + + false + + + false + + + + false + + + + + + 127.0.0.1:5070 + + + + + 127.0.0.1:5090 + + + + + false + + + true + + + false + + 20 + + true + + + + + false + restcomm + restcomm + restcomm_instance_id + site_id + http://127.0.0.1:2080 + + + + + + + + + + + + http://GMLC-IP:port/restcomm/gmlc/rest?msisdn= + + + + + + + + RestComm:*:Accounts + RestComm:*:Applications + RestComm:*:Announcements + RestComm:Read:AvailablePhoneNumbers + RestComm:*:Calls + RestComm:*:Clients + RestComm:*:Conferences + RestComm:Create,Delete,Read:Faxes + RestComm:*:IncomingPhoneNumbers + RestComm:Read:Notifications + RestComm:*:OutgoingCallerIds + RestComm:Delete,Read:Recordings + RestComm:Read,Modify:SandBoxes + RestComm:*:ShortCodes + RestComm:Read:SmsMessages + RestComm:Read:Transcriptions + RestComm:*:OutboundProxies + RestComm:*:EmailMessages + RestComm:*:Usage + RestComm:*:Geolocation + + + + + + + + + + + + + + + + + + + + + + https://backoffice.voipinnovations.com/api2.pl + + + + + + + https://api.inetwork.com/v1.0 + + + + + https://rest.nexmo.com/ + + + + + + https://api.voxbone.com/ws-voxbone/services/rest + + + + + + + + + + + + + + + + + + + + + false + restcomm-recordings + + + + false + 10 + true + us-east-1 + + secure + false + http://127.0.0.1:8090/s3 + + + + + rms + +
127.0.0.1
+ 5060 + udp + 5 +
+
+ + + + + 127.0.0.1 + 2727 + 127.0.0.1 + 2427 + 500 + + 60 + im + + + + + + + 6000 + + strict + + true + + + + + + + /restcomm-rvd/services + true + 5000 + 500 + + + + + + 127.0.0.1:5070 + + + + + + + + + + test + test + 127.0.0.1 + 2776 + TRANSCEIVER + + test + sms + + 0x34 + -1 + -1 + + + 1 + + 60000 + + 10000 + + 30000 + + 15000 + true + true + + 30000 + + + + + + + + + + + + + + + + + + + + http://vaas.acapela-group.com/Services/Synthesizer + + + + + justine8k + marcia8k + rachel8k graham8k + louise8k + eliska8k + mette8krasmus8k + laura8k ryan8k + sanna8k + claire8k bruno8k + sarah8k klaus8k + dimitris8k + chiara8k vittorio8k + jasmijn8k daan8k + kari8k olav8k + ania8k + celia8k + alyona8k + salma8k mehdi8k + laia8k + maria8k antonio8k + elin8k emil8k + ipek8k + lulu8k + sakura8k + + + + + http://api.voicerss.org + + + ca-es + zh-cn + zh-hk + zh-tw + da-dk + nl-nl + en-au + en-ca + en-gb + en-in + en-us + fi-fi + fr-ca + fr-fr + de-de + it-it + ja-jp + ko-kr + nb-no + pl-pl + pt-br + pt-pt + ru-ru + es-mx + es-es + sv-se + + + + + + + + + + Mizuki + Filiz + TatyanaMaxim + CarmenMaxim + InesCristiano + VitoriaRicardo + MajaJan + LotteRuben + Liv + CarlaGiorgio + DoraKarl + CelineMathieu + Chantal + PenelopeMiguel + ConchitaEnrique + Geraint + Gwyneth + JoannaJoey + Raveena + EmmaBrian + NicoleRussell + MarleneHans + NajaMads + + + + + +
diff --git a/restcomm/restcomm.mgcp/pom.xml b/restcomm/restcomm.mgcp/pom.xml index b31ba3363d..25dc74ad8a 100644 --- a/restcomm/restcomm.mgcp/pom.xml +++ b/restcomm/restcomm.mgcp/pom.xml @@ -73,6 +73,12 @@ provided + + org.snmp4j + snmp4j + 2.5.6 + + junit junit diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java new file mode 100644 index 0000000000..2ca76a012e --- /dev/null +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java @@ -0,0 +1,111 @@ +/* + * 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.mgcp; + +import jain.protocol.ip.mgcp.pkg.MgcpEvent; +import org.mobicents.protocols.mgcp.jain.pkg.AUMgcpEvent; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; +import org.snmp4j.smi.OctetString; + +import java.net.URI; +import java.util.List; + +/** + * Created by gdubina on 6/6/17. + */ +@Immutable +public class AsrSignal { + + public static final MgcpEvent REQUEST_ASR = MgcpEvent.factory("asr", AUMgcpEvent.END_SIGNAL + 1); + + private static final String SPACE_CHARACTER = " "; + + private final String driver; + private final List initialPrompts; + private final String endInputKey; + private final long maximumRecTimer; + private final long waitingInputTimer; + private final long timeAfterSpeech; + private final String hotWords; + private final String lang; + + public AsrSignal(String driver, String lang, List initialPrompts, String endInputKey, long maximumRecTimer, long waitingInputTimer, + long timeAfterSpeech, String hotWords) { + this.driver = driver; + this.initialPrompts = initialPrompts; + this.endInputKey = endInputKey; + this.maximumRecTimer = maximumRecTimer; + this.waitingInputTimer = waitingInputTimer; + this.timeAfterSpeech = timeAfterSpeech; + this.hotWords = hotWords; + this.lang = lang; + } + + @Override + public String toString() { + final StringBuilder buffer = new StringBuilder(); + if (!initialPrompts.isEmpty()) { + buffer.append("ip="); + for (int index = 0; index < initialPrompts.size(); index++) { + buffer.append(initialPrompts.get(index)); + if (index < initialPrompts.size() - 1) { + //https://github.com/RestComm/Restcomm-Connect/issues/1988 + buffer.append(","); + } + } + } + + if (buffer.length() > 0) + buffer.append(SPACE_CHARACTER); + buffer.append("dr=").append(driver); + + if (buffer.length() > 0) + buffer.append(SPACE_CHARACTER); + buffer.append("ln=").append(lang); + + if (endInputKey != null) { + if (buffer.length() > 0) + buffer.append(SPACE_CHARACTER); + buffer.append("eik=").append(endInputKey); + } + if (maximumRecTimer > 0) { + if (buffer.length() > 0) + buffer.append(SPACE_CHARACTER); + buffer.append("mrt=").append(maximumRecTimer * 10); + } + if (waitingInputTimer > 0) { + if (buffer.length() > 0) + buffer.append(SPACE_CHARACTER); + buffer.append("wit=").append(waitingInputTimer * 10); + } + if (timeAfterSpeech > 0) { + if (buffer.length() > 0) + buffer.append(SPACE_CHARACTER); + buffer.append("pst=").append(timeAfterSpeech * 10); + } + if (hotWords != null) { + if (buffer.length() > 0) + buffer.append(SPACE_CHARACTER); + buffer.append("hw=").append(new OctetString(hotWords).toHexString()); + } + return buffer.toString(); + } +} diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java index 758a9bd214..99234d85de 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java @@ -19,16 +19,6 @@ */ package org.restcomm.connect.mgcp; -import static jain.protocol.ip.mgcp.message.parms.ReturnCode.Transaction_Executed_Normally; - -import java.util.HashMap; -import java.util.Map; - -import org.mobicents.protocols.mgcp.jain.pkg.AUMgcpEvent; -import org.mobicents.protocols.mgcp.jain.pkg.AUPackage; -import org.restcomm.connect.commons.patterns.Observe; -import org.restcomm.connect.commons.patterns.StopObserving; - import akka.actor.ActorRef; import jain.protocol.ip.mgcp.JainIPMgcpException; import jain.protocol.ip.mgcp.JainMgcpResponseEvent; @@ -45,6 +35,17 @@ import jain.protocol.ip.mgcp.message.parms.ReturnCode; import jain.protocol.ip.mgcp.pkg.MgcpEvent; import jain.protocol.ip.mgcp.pkg.PackageName; +import org.apache.commons.lang.StringUtils; +import org.mobicents.protocols.mgcp.jain.pkg.AUMgcpEvent; +import org.mobicents.protocols.mgcp.jain.pkg.AUPackage; +import org.restcomm.connect.commons.dao.CollectedResult; +import org.restcomm.connect.commons.patterns.Observe; +import org.restcomm.connect.commons.patterns.StopObserving; +import org.snmp4j.smi.OctetString; + +import java.util.Map; + +import static jain.protocol.ip.mgcp.message.parms.ReturnCode.Transaction_Executed_Normally; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -53,11 +54,13 @@ public final class IvrEndpoint extends GenericEndpoint { private static final PackageName PACKAGE_NAME = AUPackage.AU; private static final RequestedEvent[] REQUESTED_EVENTS = new RequestedEvent[2]; + static { - final RequestedAction[] action = new RequestedAction[] { RequestedAction.NotifyImmediately }; + final RequestedAction[] action = new RequestedAction[]{RequestedAction.NotifyImmediately}; REQUESTED_EVENTS[0] = new RequestedEvent(new EventName(PACKAGE_NAME, AUMgcpEvent.auoc), action); REQUESTED_EVENTS[1] = new RequestedEvent(new EventName(PACKAGE_NAME, AUMgcpEvent.auof), action); } + private static final String EMPTY_STRING = new String(); private static final String DEFAULT_REQUEST_ID = "0"; @@ -65,10 +68,15 @@ public final class IvrEndpoint extends GenericEndpoint { protected static String ivrEndpointName = "mobicents/ivr/$"; public IvrEndpoint(final ActorRef gateway, final MediaSession session, final NotifiedEntity agent, final String domain, long timeout, String endpointName) { - super(gateway, session, agent, new EndpointIdentifier(endpointName==null?ivrEndpointName:endpointName, domain), timeout); + super(gateway, session, agent, new EndpointIdentifier(endpointName == null ? ivrEndpointName : endpointName, domain), timeout); this.agent = agent; } + private void sendAsr(final AsrSignal message) { + MgcpEvent event = AsrSignal.REQUEST_ASR.withParm(message.toString()); + sendRequest(new EventName(PACKAGE_NAME, event), REQUESTED_EVENTS); + } + private void send(final Object message) { final Class klass = message.getClass(); final String parameters = message.toString(); @@ -80,12 +88,16 @@ private void send(final Object message) { } else if (PlayRecord.class.equals(klass)) { event = AUMgcpEvent.aupr.withParm(parameters); } + sendRequest(new EventName(PACKAGE_NAME, event), REQUESTED_EVENTS); + } + + private void sendRequest(EventName reqSignal, RequestedEvent[] reqEvents) { final EventName[] signal = new EventName[1]; - signal[0] = new EventName(PACKAGE_NAME, event); + signal[0] = reqSignal; final RequestIdentifier requestId = new RequestIdentifier(DEFAULT_REQUEST_ID); final NotificationRequest request = new NotificationRequest(self(), id, requestId); request.setNotifiedEntity(agent); - request.setRequestedEvents(REQUESTED_EVENTS); + request.setRequestedEvents(reqEvents); request.setSignalRequests(signal); gateway.tell(request, self()); } @@ -106,7 +118,6 @@ private void stop(Object message) { final NotificationRequest request = new NotificationRequest(self(), id, requestId); request.setSignalRequests(signal); request.setNotifiedEntity(agent); -// request.setRequestedEvents(REQUESTED_EVENTS); gateway.tell(request, self()); } @@ -130,6 +141,8 @@ public void onReceive(final Object message) throws Exception { onDestroyEndpoint((DestroyEndpoint) message, self, sender); } else if (Play.class.equals(klass) || PlayCollect.class.equals(klass) || PlayRecord.class.equals(klass)) { send(message); + } else if (AsrSignal.class.equals(klass)) { + sendAsr((AsrSignal) message); } else if (StopEndpoint.class.equals(klass)) { stop(message); } else if (Notify.class.equals(klass)) { @@ -147,7 +160,7 @@ private void fail(final int code) { final String error = Integer.toString(code); final String message = "The IVR request failed with the following error code " + error; final JainIPMgcpException exception = new JainIPMgcpException(message); - final IvrEndpointResponse response = new IvrEndpointResponse(exception); + final IvrEndpointResponse response = new IvrEndpointResponse(exception); for (final ActorRef observer : observers) { observer.tell(response, self); } @@ -174,25 +187,42 @@ private void notification(final Object message) { final EventName[] observedEvents = notification.getObservedEvents(); if (observedEvents.length == 1) { final MgcpEvent event = observedEvents[0].getEventIdentifier(); - final Map parameters = parse(event.getParms()); + final Map parameters = MgcpUtil.parseParameters(event.getParms()); final int code = Integer.parseInt(parameters.get("rc")); switch (code) { case 326: // No digits case 327: // No speech case 328: // Spoke too long case 329: // Digit pattern not matched - case 100: { // Success + case 100: { // Success(final result) String digits = parameters.get("dc"); if (digits == null) { digits = EMPTY_STRING; } - // Notify the observers that the event successfully completed. - final IvrEndpointResponse result = new IvrEndpointResponse(digits); + final IvrEndpointResponse result = new IvrEndpointResponse( + new CollectedResult(digits, AsrSignal.REQUEST_ASR.getName().equals(event.getName()), false)); for (final ActorRef observer : observers) { observer.tell(result, self); } break; } + case 101: { // Success(partial result) + if (parameters.containsKey("asrr")) { + String asrr = parameters.get("asrr"); + if (!StringUtils.isEmpty(asrr)) { + asrr = OctetString.fromHexString(asrr).toString(); + } + // Notify the observers that the event successfully completed. + final IvrEndpointResponse result = new IvrEndpointResponse(new CollectedResult(asrr, true, true)); + for (final ActorRef observer : observers) { + observer.tell(result, self); + } + } else { + logger.error("asrr parameter is missing"); + fail(code); + } + break; + } default: { fail(code); } @@ -200,17 +230,4 @@ private void notification(final Object message) { } } - private Map parse(final String input) { - final Map parameters = new HashMap(); - final String[] tokens = input.split(" "); - for (final String token : tokens) { - final String[] values = token.split("="); - if (values.length == 1) { - parameters.put(values[0], null); - } else if (values.length == 2) { - parameters.put(values[0], values[1]); - } - } - return parameters; - } } diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpointResponse.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpointResponse.java index e8467377d4..e7c84a6a17 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpointResponse.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpointResponse.java @@ -19,13 +19,14 @@ */ package org.restcomm.connect.mgcp; +import org.restcomm.connect.commons.dao.CollectedResult; import org.restcomm.connect.commons.patterns.StandardResponse; /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ -public class IvrEndpointResponse extends StandardResponse { - public IvrEndpointResponse(final T object) { +public class IvrEndpointResponse extends StandardResponse { + public IvrEndpointResponse(final CollectedResult object) { super(object); } diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MediaGateway.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MediaGateway.java index 242222b3f1..29074e45c2 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MediaGateway.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MediaGateway.java @@ -18,7 +18,6 @@ * */ package org.restcomm.connect.mgcp; - import akka.actor.Actor; import akka.actor.ActorRef; import akka.actor.ActorSystem; @@ -39,6 +38,7 @@ import jain.protocol.ip.mgcp.message.NotificationRequest; import jain.protocol.ip.mgcp.message.Notify; import jain.protocol.ip.mgcp.message.parms.ConnectionIdentifier; +import jain.protocol.ip.mgcp.message.parms.EventName; import jain.protocol.ip.mgcp.message.parms.NotifiedEntity; import org.restcomm.connect.commons.util.RevolvingCounter; @@ -264,6 +264,11 @@ private void powerOn(final Object message) { transactionIdPool = new RevolvingCounter(1, Long.MAX_VALUE); } + private boolean isPartialNotify(final Notify notify) { + EventName[] events = notify.getObservedEvents(); + return events != null && events.length != 0 && MgcpUtil.isPartialNotify(events[events.length - 1]); + } + @Override public void processMgcpCommandEvent(final JainMgcpCommandEvent event) { final int value = event.getObjectIdentifier(); @@ -271,7 +276,13 @@ public void processMgcpCommandEvent(final JainMgcpCommandEvent event) { case Constants.CMD_NOTIFY: { final Notify notify = (Notify) event; final String id = notify.getRequestIdentifier().toString(); - final ActorRef listener = notificationListeners.remove(id); + + final ActorRef listener; + if (isPartialNotify(notify)) { + listener = notificationListeners.get(id); + } else { + listener = notificationListeners.remove(id); + } if (listener != null) { listener.tell(notify, self()); } diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MgcpUtil.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MgcpUtil.java new file mode 100644 index 0000000000..d3afc0feca --- /dev/null +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MgcpUtil.java @@ -0,0 +1,58 @@ +/* + * 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.mgcp; + +import jain.protocol.ip.mgcp.message.parms.EventName; +import jain.protocol.ip.mgcp.pkg.MgcpEvent; +import org.apache.commons.lang.math.NumberUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by gdubina on 23.06.17. + */ +public final class MgcpUtil { + + public static final int RETURNCODE_PARTIAL = 101; + + private MgcpUtil(){} + + public static Map parseParameters(final String input) { + final Map parameters = new HashMap(); + final String[] tokens = input.split(" "); + for (final String token : tokens) { + final String[] values = token.split("="); + if (values.length == 1) { + parameters.put(values[0], null); + } else if (values.length == 2) { + parameters.put(values[0], values[1]); + } + } + return parameters; + } + + public static boolean isPartialNotify(EventName lastEvent){ + final MgcpEvent event = lastEvent.getEventIdentifier(); + final Map parameters = MgcpUtil.parseParameters(event.getParms()); + return NumberUtils.toInt(parameters.get("rc")) == RETURNCODE_PARTIAL; + } +} diff --git a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AbstractMockMediaGateway.java b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AbstractMockMediaGateway.java index 83e1c70815..80197046a6 100644 --- a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AbstractMockMediaGateway.java +++ b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AbstractMockMediaGateway.java @@ -176,6 +176,8 @@ public void onReceive(final Object message) throws Exception { request(message, sender); } else if (message instanceof JainMgcpResponseEvent) { response(message, sender); + } else { + throw new IllegalArgumentException("Unsupported operation !!!"); } } diff --git a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AsrSignalTest.java b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AsrSignalTest.java new file mode 100644 index 0000000000..bb330cb0e0 --- /dev/null +++ b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AsrSignalTest.java @@ -0,0 +1,82 @@ +/* + * 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.mgcp; + +import org.junit.Before; +import org.junit.Test; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * @author Dmitriy Nadolenko + */ +public class AsrSignalTest { + + public static final String DEFAULT_LANG = "en-US"; + + private String driver; + private List initialPrompts; + private String endInputKey; + private long maximumRecTimer; + private long waitingInputTimer; + private long timeAfterSpeech; + private String hotWords; + + @Before + public void init() { + driver = "no_name_driver"; + initialPrompts = Collections.singletonList(URI.create("hello.wav")); + endInputKey = "#"; + maximumRecTimer = 10L; + waitingInputTimer = 10L; + timeAfterSpeech = 5L; + hotWords = "Wait"; + } + + @Test + public void testFormatting() { + String expectedResult = "ip=hello.wav dr=no_name_driver ln=en-US eik=# mrt=100 wit=100 pst=50 hw=57:61:69:74"; + AsrSignal asrSignal = new AsrSignal(driver, DEFAULT_LANG, initialPrompts, endInputKey, maximumRecTimer, waitingInputTimer, + timeAfterSpeech, hotWords); + String actualResult = asrSignal.toString(); + + assertEquals(expectedResult, actualResult); + } + + @Test + public void testFormattingWithMultiplePrompts() { + initialPrompts = new ArrayList() {{ + add(URI.create("hello.wav")); + add(URI.create("world.wav")); + }}; + String expectedResult = "ip=hello.wav,world.wav dr=no_name_driver ln=en-US eik=# mrt=100 wit=100 pst=50 hw=57:61:69:74"; + AsrSignal asrSignal = new AsrSignal(driver, DEFAULT_LANG, initialPrompts, endInputKey, maximumRecTimer, waitingInputTimer, + timeAfterSpeech, hotWords); + String actualResult = asrSignal.toString(); + + assertEquals(expectedResult, actualResult); + } +} diff --git a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java new file mode 100644 index 0000000000..cd81fc20ec --- /dev/null +++ b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java @@ -0,0 +1,301 @@ +/* + * 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.mgcp; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.JavaTestKit; +import jain.protocol.ip.mgcp.JainMgcpResponseEvent; +import jain.protocol.ip.mgcp.message.NotificationRequest; +import jain.protocol.ip.mgcp.message.NotificationRequestResponse; +import jain.protocol.ip.mgcp.message.Notify; +import jain.protocol.ip.mgcp.message.parms.EventName; +import jain.protocol.ip.mgcp.message.parms.ReturnCode; +import jain.protocol.ip.mgcp.pkg.MgcpEvent; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mobicents.protocols.mgcp.jain.pkg.AUMgcpEvent; +import org.mobicents.protocols.mgcp.jain.pkg.AUPackage; +import org.restcomm.connect.commons.patterns.Observe; +import org.restcomm.connect.commons.patterns.Observing; +import org.restcomm.connect.commons.patterns.StopObserving; +import org.snmp4j.smi.OctetString; + +import java.net.URI; +import java.util.Collections; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * @author Dmitriy Nadolenko + * @version 1.0 + * @since 1.0 + */ +public class IvrAsrEndpointTest { + + private static final String ASR_RESULT_TEXT = "Super_text"; + private static final String ASR_RESULT_TEXT_HEX = new OctetString(ASR_RESULT_TEXT).toHexString(); + private static final String HINTS = "hint 1, hint 2"; + + private static ActorSystem system; + + public IvrAsrEndpointTest() { + super(); + } + + @BeforeClass + public static void before() throws Exception { + system = ActorSystem.create(); + } + + @AfterClass + public static void after() throws Exception { + system.shutdown(); + } + + @Test + @SuppressWarnings("unchecked") + public void testSuccessfulAsrScenario() { + new JavaTestKit(system) { + { + final ActorRef observer = getRef(); + // Create a new mock media gateway to simulate the real thing. + final ActorRef gateway = system.actorOf(new Props(IvrAsrEndpointTest.MockAsrMediaGateway.class)); + // Create a media session. This is just an identifier that groups + // a set of end points, connections, and lists in to one call. + gateway.tell(new CreateMediaSession(), observer); + final MediaGatewayResponse mediaSessionResponse = expectMsgClass(MediaGatewayResponse.class); + assertTrue(mediaSessionResponse.succeeded()); + final MediaSession session = mediaSessionResponse.get(); + // Create an IVR end point. + gateway.tell(new CreateIvrEndpoint(session), observer); + final MediaGatewayResponse endpointResponse = expectMsgClass(MediaGatewayResponse.class); + assertTrue(endpointResponse.succeeded()); + final ActorRef endpoint = endpointResponse.get(); + // Start observing events from the IVR end point. + endpoint.tell(new Observe(observer), observer); + final Observing observingResponse = expectMsgClass(Observing.class); + assertTrue(observingResponse.succeeded()); + + AsrSignal asr = new AsrSignal("no_name_driver", "en-US", Collections.singletonList(URI.create("hello.wav")), "#", 10, 10, 10, HINTS); + endpoint.tell(asr, observer); + final IvrEndpointResponse ivrResponse = expectMsgClass(IvrEndpointResponse.class); + assertTrue(ivrResponse.succeeded()); + assertTrue(ASR_RESULT_TEXT.equals(ivrResponse.get().getResult())); + assertTrue(ivrResponse.get().isAsr()); + + final IvrEndpointResponse ivrResponse2 = expectMsgClass(IvrEndpointResponse.class); + assertTrue(ivrResponse2.succeeded()); + assertTrue(ASR_RESULT_TEXT.equals(ivrResponse2.get().getResult())); + assertTrue(ivrResponse2.get().isAsr()); + + + final IvrEndpointResponse ivrResponse3 = expectMsgClass(IvrEndpointResponse.class); + assertTrue(ivrResponse3.succeeded()); + assertTrue(ivrResponse3.get().getResult().isEmpty()); + assertTrue(ivrResponse2.get().isAsr()); + + // Stop observing events from the IVR end point. + endpoint.tell(new StopObserving(observer), observer); + } + }; + } + + @Test + @SuppressWarnings("unchecked") + public void testFailureScenario() { + new JavaTestKit(system) { + { + final ActorRef observer = getRef(); + // Create a new mock media gateway to simulate the real thing. + final ActorRef gateway = system.actorOf(new Props(IvrAsrEndpointTest.FailingMockAsrMediaGateway.class)); + // Create a media session. This is just an identifier that groups + // a set of end points, connections, and lists in to one call. + gateway.tell(new CreateMediaSession(), observer); + final MediaGatewayResponse mediaSessionResponse = expectMsgClass(MediaGatewayResponse.class); + assertTrue(mediaSessionResponse.succeeded()); + final MediaSession session = mediaSessionResponse.get(); + // Create an IVR end point. + gateway.tell(new CreateIvrEndpoint(session), observer); + final MediaGatewayResponse endpointResponse = expectMsgClass(MediaGatewayResponse.class); + assertTrue(endpointResponse.succeeded()); + final ActorRef endpoint = endpointResponse.get(); + // Start observing events from the IVR end point. + endpoint.tell(new Observe(observer), observer); + final Observing observingResponse = expectMsgClass(Observing.class); + assertTrue(observingResponse.succeeded()); + + AsrSignal asr = new AsrSignal("no_name_driver", "en-US", Collections.singletonList(URI.create("hello.wav")), "#", 10, 10, 10, HINTS); + endpoint.tell(asr, observer); + final IvrEndpointResponse ivrResponse = expectMsgClass(IvrEndpointResponse.class); + assertFalse(ivrResponse.succeeded()); + String errorMessage = "jain.protocol.ip.mgcp.JainIPMgcpException: The IVR request failed with the following error code 300"; + assertTrue(ivrResponse.cause().toString().equals(errorMessage)); + assertTrue(ivrResponse.get() == null); + } + }; + } + + @Test + @SuppressWarnings("unchecked") + public void testEndSignal() { + new JavaTestKit(system) { + { + final ActorRef observer = getRef(); + // Create a new mock media gateway to simulate the real thing. + final ActorRef gateway = system.actorOf(new Props(MockAsrWithEndSignal.class)); + // Create a media session. This is just an identifier that groups + // a set of end points, connections, and lists in to one call. + gateway.tell(new CreateMediaSession(), observer); + final MediaGatewayResponse mediaSessionResponse = expectMsgClass(MediaGatewayResponse.class); + assertTrue(mediaSessionResponse.succeeded()); + final MediaSession session = mediaSessionResponse.get(); + // Create an IVR end point. + gateway.tell(new CreateIvrEndpoint(session), observer); + final MediaGatewayResponse endpointResponse = expectMsgClass(MediaGatewayResponse.class); + assertTrue(endpointResponse.succeeded()); + final ActorRef endpoint = endpointResponse.get(); + // Start observing events from the IVR end point. + endpoint.tell(new Observe(observer), observer); + final Observing observingResponse = expectMsgClass(Observing.class); + assertTrue(observingResponse.succeeded()); + + AsrSignal asr = new AsrSignal("no_name_driver", "en-US", Collections.singletonList(URI.create("hello.wav")), "#", 10, 10, 10, ASR_RESULT_TEXT); + endpoint.tell(asr, observer); + final IvrEndpointResponse ivrResponse = expectMsgClass(IvrEndpointResponse.class); + assertTrue(ivrResponse.succeeded()); + assertTrue(ASR_RESULT_TEXT.equals(ivrResponse.get().getResult())); + assertTrue(ivrResponse.get().isAsr()); + + // EndSignal to IVR + endpoint.tell(new StopEndpoint(AsrSignal.REQUEST_ASR), observer); + + final IvrEndpointResponse ivrResponse2 = expectMsgClass(IvrEndpointResponse.class); + assertTrue(ivrResponse2.succeeded()); + + // Stop observing events from the IVR end point. + endpoint.tell(new StopObserving(observer), observer); + } + }; + } + + + private static final class MockAsrMediaGateway extends AuAbstractMockMediaGateway { + @SuppressWarnings("unused") + public MockAsrMediaGateway() { + super(); + } + + @Override + protected void event(final Object message, final ActorRef sender) { + final ActorRef self = self(); + final Class klass = message.getClass(); + if (NotificationRequest.class.equals(klass)) { + // Send a successful response for this request. + final NotificationRequest request = (NotificationRequest) message; + final JainMgcpResponseEvent response = new NotificationRequestResponse(this, + ReturnCode.Transaction_Executed_Normally); + sender.tell(response, self); + + // Send the notification. + Notify notify = createNotify(request, (int) transactionIdPool.get(), AUMgcpEvent.auoc.withParm("rc=101 asrr=" + ASR_RESULT_TEXT_HEX)); + sender.tell(notify, self); + + notify = createNotify(request, (int) transactionIdPool.get(), AUMgcpEvent.auoc.withParm("rc=101 asrr=" + ASR_RESULT_TEXT_HEX)); + sender.tell(notify, self); + + notify = createNotify(request, (int) transactionIdPool.get(), AUMgcpEvent.auoc.withParm("rc=100")); + sender.tell(notify, self); + } + } + } + + private static final class FailingMockAsrMediaGateway extends AuAbstractMockMediaGateway { + @SuppressWarnings("unused") + public FailingMockAsrMediaGateway() { + super(); + } + + @Override + protected void event(final Object message, final ActorRef sender) { + final ActorRef self = self(); + final Class klass = message.getClass(); + if (NotificationRequest.class.equals(klass)) { + // Send a successful response for this request. + final NotificationRequest request = (NotificationRequest) message; + final JainMgcpResponseEvent response = new NotificationRequestResponse(this, + ReturnCode.Transaction_Executed_Normally); + response.setTransactionHandle(request.getTransactionHandle()); + sender.tell(response, self); + + // Send the notification. + final Notify notify = createNotify(request, (int) transactionIdPool.get(), AUMgcpEvent.auof.withParm("rc=300")); + sender.tell(notify, self); + } + } + } + + private static final class MockAsrWithEndSignal extends AuAbstractMockMediaGateway { + + @SuppressWarnings("unused") + public MockAsrWithEndSignal() { + super(); + } + + @Override + protected void event(final Object message, final ActorRef sender) { + final ActorRef self = self(); + final Class klass = message.getClass(); + if (NotificationRequest.class.equals(klass)) { + // Send a successful response for this request. + final NotificationRequest request = (NotificationRequest) message; + if ("AU/es(sg=asr)".equals(request.getSignalRequests()[0].toString())) { + //handle stop request + final JainMgcpResponseEvent response = new NotificationRequestResponse(this, ReturnCode.Transaction_Executed_Normally); + sender.tell(response, self); + + Notify notify = createNotify(request, (int) transactionIdPool.get(), AUMgcpEvent.auoc.withParm("rc=100")); + sender.tell(notify, self); + return; + } + final JainMgcpResponseEvent response = new NotificationRequestResponse(this, ReturnCode.Transaction_Executed_Normally); + sender.tell(response, self); + // Send the notification. + Notify notify = createNotify(request, (int) transactionIdPool.get(), AUMgcpEvent.auoc.withParm("rc=101 asrr=" + ASR_RESULT_TEXT_HEX)); + sender.tell(notify, self); + } + } + } + + private static abstract class AuAbstractMockMediaGateway extends AbstractMockMediaGateway { + + protected Notify createNotify(final NotificationRequest request, int transactionId, final MgcpEvent event) { + final EventName[] events = {new EventName(AUPackage.AU, event)}; + Notify notify = new Notify(this, request.getEndpointIdentifier(), request.getRequestIdentifier(), events); + notify.setTransactionHandle(transactionId); + return notify; + } + + } +} diff --git a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrEndpointTest.java b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrEndpointTest.java index c9c052979c..6c7e21fc6c 100644 --- a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrEndpointTest.java +++ b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrEndpointTest.java @@ -19,9 +19,10 @@ */ package org.restcomm.connect.mgcp; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import jain.protocol.ip.mgcp.JainMgcpEvent; +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.JavaTestKit; import jain.protocol.ip.mgcp.JainMgcpResponseEvent; import jain.protocol.ip.mgcp.message.NotificationRequest; import jain.protocol.ip.mgcp.message.NotificationRequestResponse; @@ -29,11 +30,6 @@ import jain.protocol.ip.mgcp.message.parms.EventName; import jain.protocol.ip.mgcp.message.parms.ReturnCode; import jain.protocol.ip.mgcp.pkg.MgcpEvent; - -import java.net.URI; -import java.util.ArrayList; -import java.util.List; - import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -43,10 +39,12 @@ import org.restcomm.connect.commons.patterns.Observing; import org.restcomm.connect.commons.patterns.StopObserving; -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.actor.Props; -import akka.testkit.JavaTestKit; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; /** * @author thomas.quintana@telestax.com (Thomas Quintana) @@ -96,7 +94,7 @@ public void testSuccessfulScenario() { announcements.add(URI.create("hello.wav")); final Play play = new Play(announcements, 1); endpoint.tell(play, observer); - final IvrEndpointResponse ivrResponse = expectMsgClass(IvrEndpointResponse.class); + final IvrEndpointResponse ivrResponse = expectMsgClass(IvrEndpointResponse.class); assertTrue(ivrResponse.succeeded()); // Stop observing events from the IVR end point. endpoint.tell(new StopObserving(observer), observer); @@ -132,9 +130,9 @@ public void testSuccessfulScenarioWithDigits() { builder.addPrompt(URI.create("hello.wav")); final PlayCollect playCollect = builder.build(); endpoint.tell(playCollect, observer); - final IvrEndpointResponse ivrResponse = expectMsgClass(IvrEndpointResponse.class); + final IvrEndpointResponse ivrResponse = expectMsgClass(IvrEndpointResponse.class); assertTrue(ivrResponse.succeeded()); - assertTrue("1".equals(ivrResponse.get())); + assertTrue("1".equals((ivrResponse.get()).getResult())); // Stop observing events from the IVR end point. endpoint.tell(new StopObserving(observer), observer); } @@ -169,7 +167,7 @@ public void testFailureScenario() { announcements.add(URI.create("hello.wav")); final Play play = new Play(announcements, 1); endpoint.tell(play, observer); - final IvrEndpointResponse ivrResponse = expectMsgClass(IvrEndpointResponse.class); + final IvrEndpointResponse ivrResponse = expectMsgClass(IvrEndpointResponse.class); assertFalse(ivrResponse.succeeded()); // Stop observing events from the IVR end point. endpoint.tell(new StopObserving(observer), observer); @@ -186,9 +184,6 @@ public MockMediaGateway() { @Override protected void event(final Object message, final ActorRef sender) { final ActorRef self = self(); - if (message instanceof JainMgcpEvent) { - System.out.println(message.toString()); - } final Class klass = message.getClass(); if (NotificationRequest.class.equals(klass)) { // Send a successful response for this request. @@ -196,14 +191,12 @@ protected void event(final Object message, final ActorRef sender) { final JainMgcpResponseEvent response = new NotificationRequestResponse(this, ReturnCode.Transaction_Executed_Normally); sender.tell(response, self); - System.out.println(response.toString()); // Send the notification. final MgcpEvent event = AUMgcpEvent.auoc.withParm("rc=100 dc=1"); final EventName[] events = { new EventName(AUPackage.AU, event) }; final Notify notify = new Notify(this, request.getEndpointIdentifier(), request.getRequestIdentifier(), events); notify.setTransactionHandle((int) transactionIdPool.get()); sender.tell(notify, self); - System.out.println(notify.toString()); } } } @@ -217,9 +210,6 @@ public FailingMockMediaGateway() { @Override protected void event(final Object message, final ActorRef sender) { final ActorRef self = self(); - if (message instanceof JainMgcpEvent) { - System.out.println(message.toString()); - } final Class klass = message.getClass(); if (NotificationRequest.class.equals(klass)) { // Send a successful response for this request. @@ -228,14 +218,12 @@ protected void event(final Object message, final ActorRef sender) { ReturnCode.Transaction_Executed_Normally); response.setTransactionHandle(request.getTransactionHandle()); sender.tell(response, self); - System.out.println(response.toString()); // Send the notification. final MgcpEvent event = AUMgcpEvent.auoc.withParm("rc=300"); final EventName[] events = { new EventName(AUPackage.AU, event) }; final Notify notify = new Notify(this, request.getEndpointIdentifier(), request.getRequestIdentifier(), events); notify.setTransactionHandle((int) transactionIdPool.get()); sender.tell(notify, self); - System.out.println(notify.toString()); } } } diff --git a/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/messages/Collect.java b/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/messages/Collect.java index 4a20b27a18..8a0f4e5d8a 100644 --- a/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/messages/Collect.java +++ b/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/messages/Collect.java @@ -19,30 +19,63 @@ */ package org.restcomm.connect.mscontrol.api.messages; +import org.restcomm.connect.commons.annotations.concurrency.Immutable; + import java.net.URI; import java.util.List; -import org.restcomm.connect.commons.annotations.concurrency.Immutable; - /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ @Immutable public final class Collect { + + public enum Type { + DTMF, SPEECH, DTMF_SPEECH; + + public static Type parseOrDefault(String name, Type defaultValue){ + try { + return "DTMF SPEECH".equalsIgnoreCase(name) ? DTMF_SPEECH : Type.valueOf(name.toUpperCase()); + } catch (Exception e) { + return defaultValue; + } + } + } + + private final Type type; private final List prompts; private final String pattern; private final int timeout; private final String endInputKey; private final int numberOfDigits; + private final String lang; + private final String hints; + private final String driver; - public Collect(final List prompts, final String pattern, final int timeout, final String endInputKey, - final int numberOfDigits) { + public Collect(String driver,final Type type, final List prompts, final String pattern, final int timeout, final String endInputKey, + final int numberOfDigits, final String lang, final String hints) { super(); + this.driver = driver; + this.type = type; this.prompts = prompts; this.pattern = pattern; this.timeout = timeout; this.endInputKey = endInputKey; this.numberOfDigits = numberOfDigits; + this.lang = lang; + this.hints = hints; + } + + public String getDriver() { + return driver; + } + + public Type type() { + return type; + } + + public String lang() { + return lang; } public List prompts() { @@ -77,4 +110,7 @@ public int numberOfDigits() { return numberOfDigits; } + public String getHints() { + return hints; + } } diff --git a/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java b/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java index 09baea9ea7..f118ee6811 100644 --- a/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java +++ b/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java @@ -20,14 +20,15 @@ package org.restcomm.connect.mscontrol.mms; -import java.net.URI; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - +import akka.actor.ActorRef; +import akka.event.Logging; +import akka.event.LoggingAdapter; +import jain.protocol.ip.mgcp.message.parms.ConnectionIdentifier; +import jain.protocol.ip.mgcp.message.parms.ConnectionMode; import jain.protocol.ip.mgcp.pkg.MgcpEvent; +import org.apache.commons.configuration.Configuration; import org.mobicents.protocols.mgcp.jain.pkg.AUMgcpEvent; +import org.restcomm.connect.commons.dao.CollectedResult; import org.restcomm.connect.commons.fsm.Action; import org.restcomm.connect.commons.fsm.FiniteStateMachine; import org.restcomm.connect.commons.fsm.State; @@ -35,6 +36,7 @@ import org.restcomm.connect.commons.patterns.Observe; import org.restcomm.connect.commons.patterns.Observing; import org.restcomm.connect.commons.patterns.StopObserving; +import org.restcomm.connect.mgcp.AsrSignal; import org.restcomm.connect.mgcp.CreateIvrEndpoint; import org.restcomm.connect.mgcp.CreateLink; import org.restcomm.connect.mgcp.DestroyEndpoint; @@ -63,16 +65,15 @@ import org.restcomm.connect.mscontrol.api.messages.Stop; import org.restcomm.connect.mscontrol.api.messages.StopMediaGroup; -import akka.actor.ActorRef; -import akka.event.Logging; -import akka.event.LoggingAdapter; -import jain.protocol.ip.mgcp.message.parms.ConnectionIdentifier; -import jain.protocol.ip.mgcp.message.parms.ConnectionMode; +import java.net.URI; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; /** * @author quintana.thomas@gmail.com (Thomas Quintana) * @author maria.farooq@telestax.com (Maria Farooq) - * */ public class MgcpMediaGroup extends MediaGroup { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); @@ -96,6 +97,8 @@ public class MgcpMediaGroup extends MediaGroup { // FSM. protected FiniteStateMachine fsm; + // The user specific configuration. + Configuration configuration = null; // MGCP runtime stuff. protected final ActorRef gateway; @@ -197,20 +200,29 @@ public MgcpMediaGroup(final ActorRef gateway, final MediaSession session, final protected void collect(final Object message) { final ActorRef self = self(); final Collect request = (Collect) message; - final PlayCollect.Builder builder = PlayCollect.builder(); - for (final URI prompt : request.prompts()) { - builder.addPrompt(prompt); - } - builder.setClearDigitBuffer(true); - builder.setDigitPattern(request.pattern()); - builder.setFirstDigitTimer(request.timeout()); - builder.setInterDigitTimer(request.timeout()); - builder.setEndInputKey(request.endInputKey()); - builder.setMaxNumberOfDigits(request.numberOfDigits()); - this.lastEvent = AUMgcpEvent.aupc; stop(lastEvent); + + Object signal; + if (request.type() == Collect.Type.DTMF) { + final PlayCollect.Builder builder = PlayCollect.builder(); + for (final URI prompt : request.prompts()) { + builder.addPrompt(prompt); + } + builder.setClearDigitBuffer(true); + builder.setDigitPattern(request.pattern()); + builder.setFirstDigitTimer(request.timeout()); + builder.setInterDigitTimer(request.timeout()); + builder.setEndInputKey(request.endInputKey()); + builder.setMaxNumberOfDigits(request.numberOfDigits()); + signal = builder.build(); + this.lastEvent = AUMgcpEvent.aupc; + } else { + this.lastEvent = AsrSignal.REQUEST_ASR; + signal = new AsrSignal(request.getDriver(), request.lang(), request.prompts(), request.endInputKey(), request.timeout(), request.timeout(), + request.timeout(), request.getHints()); + } this.originator = sender(); - ivr.tell(builder.build(), self); + ivr.tell(signal, self); ivrInUse = true; } @@ -220,8 +232,8 @@ protected void play(final Object message) { final List uris = request.uris(); final int iterations = request.iterations(); final org.restcomm.connect.mgcp.Play play = new org.restcomm.connect.mgcp.Play(uris, iterations); - this.lastEvent = AUMgcpEvent.aupa; stop(lastEvent); + this.lastEvent = AUMgcpEvent.aupa; this.originator = sender(); ivr.tell(play, self); ivrInUse = true; @@ -229,20 +241,19 @@ protected void play(final Object message) { @SuppressWarnings("unchecked") protected void notification(final Object message) { - final IvrEndpointResponse response = (IvrEndpointResponse) message; + final IvrEndpointResponse response = (IvrEndpointResponse) message; final ActorRef self = self(); - MediaGroupResponse event = null; + MediaGroupResponse event; if (response.succeeded()) { - event = new MediaGroupResponse(response.get()); + event = new MediaGroupResponse<>(response.get()); } else { - event = new MediaGroupResponse(response.cause(), response.error()); + event = new MediaGroupResponse<>(response.cause(), response.error()); } - // for (final ActorRef observer : observers) { - // observer.tell(event, self); - // } if (originator != null) this.originator.tell(event, self); - ivrInUse = false; + if (!response.get().isPartial()) { + ivrInUse = false; + } } protected void observe(final Object message) { @@ -384,8 +395,8 @@ protected void record(final Object message) { builder.setEndInputKey("null"); } builder.setRecordingId(request.destination()); - this.lastEvent = AUMgcpEvent.aupr; stop(lastEvent); + this.lastEvent = AUMgcpEvent.aupr; this.originator = sender(); ivr.tell(builder.build(), self); ivrInUse = true; From 9473d0b4ed5429dc12654ffc07eb35837df6f606 Mon Sep 17 00:00:00 2001 From: Eugene Lapin Date: Tue, 11 Jul 2017 16:26:23 +0300 Subject: [PATCH 02/34] ASR configuration documents update --- .../src/main/asciidoc/configuration/asr/asr.adoc | 13 +++++++++++++ .../src/main/asciidoc/configuration/index.adoc | 4 ++++ 2 files changed, 17 insertions(+) create mode 100644 restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/asr/asr.adoc diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/asr/asr.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/asr/asr.adoc new file mode 100644 index 0000000000..1824b8a559 --- /dev/null +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/asr/asr.adoc @@ -0,0 +1,13 @@ +[[intro]] += Automatic Speech Recognition Integration + +In order to enable ASR functionality an appropriate configuration has to be added. There are list of available drivers supported by mediaserver and a default one, which can be used by Restcomm. These are environment variables you need to set in restcomm.conf file + +[source,shell] +---- +MG_ASR_DRIVERS="google-api,yahoo-api" +MG_ASR_DRIVER_DEFAULT="google-api" +---- + +**MG_ASR_DRIVERS**: comma separated list of drivers names supported by mediaserver +**MG_ASR_DRIVER_DEFAULT**: name of the default driver to use diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/index.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/index.adoc index 08305af8c4..b4038e2478 100644 --- a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/index.adoc +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/index.adoc @@ -79,6 +79,10 @@ There is two different ways to install Restcomm Connect. Either through Docker o * <> +=== Automatic Speech Recognition Integration + +* <> + == Contributor Resources * <> From bf831e4f1df74ac03a2eec2fb7b720312fec84ef Mon Sep 17 00:00:00 2001 From: Eugene Lapin Date: Fri, 14 Jul 2017 15:39:32 +0300 Subject: [PATCH 03/34] Remove dependency to snmp4j lib --- restcomm/restcomm.mgcp/pom.xml | 6 ------ .../main/java/org/restcomm/connect/mgcp/AsrSignal.java | 4 ++-- .../java/org/restcomm/connect/mgcp/IvrEndpoint.java | 10 ++++++++-- .../org/restcomm/connect/mgcp/IvrAsrEndpointTest.java | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/restcomm/restcomm.mgcp/pom.xml b/restcomm/restcomm.mgcp/pom.xml index 25dc74ad8a..b31ba3363d 100644 --- a/restcomm/restcomm.mgcp/pom.xml +++ b/restcomm/restcomm.mgcp/pom.xml @@ -73,12 +73,6 @@ provided - - org.snmp4j - snmp4j - 2.5.6 - - junit junit diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java index 2ca76a012e..418f1aa2f7 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java @@ -23,7 +23,7 @@ import jain.protocol.ip.mgcp.pkg.MgcpEvent; import org.mobicents.protocols.mgcp.jain.pkg.AUMgcpEvent; import org.restcomm.connect.commons.annotations.concurrency.Immutable; -import org.snmp4j.smi.OctetString; +import org.apache.commons.codec.binary.Hex; import java.net.URI; import java.util.List; @@ -104,7 +104,7 @@ public String toString() { if (hotWords != null) { if (buffer.length() > 0) buffer.append(SPACE_CHARACTER); - buffer.append("hw=").append(new OctetString(hotWords).toHexString()); + buffer.append("hw=").append(Hex.encodeHexString(hotWords.getBytes())); } return buffer.toString(); } diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java index 99234d85de..3fc8e8f9d0 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java @@ -35,13 +35,14 @@ import jain.protocol.ip.mgcp.message.parms.ReturnCode; import jain.protocol.ip.mgcp.pkg.MgcpEvent; import jain.protocol.ip.mgcp.pkg.PackageName; +import org.apache.commons.codec.DecoderException; import org.apache.commons.lang.StringUtils; import org.mobicents.protocols.mgcp.jain.pkg.AUMgcpEvent; import org.mobicents.protocols.mgcp.jain.pkg.AUPackage; import org.restcomm.connect.commons.dao.CollectedResult; import org.restcomm.connect.commons.patterns.Observe; import org.restcomm.connect.commons.patterns.StopObserving; -import org.snmp4j.smi.OctetString; +import org.apache.commons.codec.binary.Hex; import java.util.Map; @@ -210,7 +211,12 @@ private void notification(final Object message) { if (parameters.containsKey("asrr")) { String asrr = parameters.get("asrr"); if (!StringUtils.isEmpty(asrr)) { - asrr = OctetString.fromHexString(asrr).toString(); + try { + asrr = new String(Hex.decodeHex(asrr.toCharArray())); + } catch (DecoderException e) { + logger.error("asrr parameter cannot be decoded"); + fail(code); + } } // Notify the observers that the event successfully completed. final IvrEndpointResponse result = new IvrEndpointResponse(new CollectedResult(asrr, true, true)); diff --git a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java index cd81fc20ec..336e9e2364 100644 --- a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java +++ b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java @@ -39,7 +39,7 @@ import org.restcomm.connect.commons.patterns.Observe; import org.restcomm.connect.commons.patterns.Observing; import org.restcomm.connect.commons.patterns.StopObserving; -import org.snmp4j.smi.OctetString; +import org.apache.commons.codec.binary.Hex; import java.net.URI; import java.util.Collections; @@ -55,7 +55,7 @@ public class IvrAsrEndpointTest { private static final String ASR_RESULT_TEXT = "Super_text"; - private static final String ASR_RESULT_TEXT_HEX = new OctetString(ASR_RESULT_TEXT).toHexString(); + private static final String ASR_RESULT_TEXT_HEX = Hex.encodeHexString(ASR_RESULT_TEXT.getBytes()); private static final String HINTS = "hint 1, hint 2"; private static ActorSystem system; From 1c6a1fbebab43716c037816f49f06404027d2a97 Mon Sep 17 00:00:00 2001 From: Eugene Lapin Date: Mon, 17 Jul 2017 15:42:43 +0300 Subject: [PATCH 04/34] Merge with master --- .idea/codeStyleSettings.xml | 6 +- .../as7-config-scripts/restcomm/advanced.conf | 3 + .../restcomm/autoconfig.d/config-SecureSSL.sh | 6 +- .../restcomm/autoconfig.d/config-dashboard.sh | 30 ++ .../restcomm/autoconfig.d/config-rvd.sh | 2 +- .../connect/application/Bootstrapper.java | 4 +- .../org/restcomm/connect/asr/ISpeechAsr.java | 9 +- .../commons/amazonS3/S3AccessTool.java | 21 +- .../connect/commons/cache/DiskCache.java | 4 +- .../RestcommSupervisorStrategy.java | 12 +- .../faulttolerance/RestcommUntypedActor.java | 35 ++ .../SupervisorActorCreationStressTest.java | 4 +- .../faulttolerance/tool/MyUntypedActor.java | 14 +- .../faulttolerance/tool/SimpleActor.java | 4 +- .../commons/patterns/ObserverPatternTest.java | 17 +- ...arted with Restcomm-Connect and Mysql.adoc | 9 +- .../restcomm/connect/email/EmailService.java | 12 +- .../restcomm/connect/fax/InterfaxService.java | 17 +- .../connect/http/AccountsEndpoint.java | 9 +- .../restcomm/connect/http/CallsEndpoint.java | 5 +- .../connect/http/EmailMessagesEndpoint.java | 8 +- .../connect/http/SmsMessagesEndpoint.java | 12 +- .../connect/http/client/Downloader.java | 6 +- .../resolver/RcmlserverResolver.java | 93 +++++ .../resolver/RcmlserverResolverTest.java | 62 ++++ .../interpreter/AudioPlayerInterpreter.java | 4 +- .../interpreter/BaseVoiceInterpreter.java | 48 ++- .../interpreter/ConfVoiceInterpreter.java | 50 +-- .../ConfVoiceInterpreterBuilder.java | 83 ----- .../ConfVoiceInterpreterParams.java | 154 ++++++++ .../connect/interpreter/SmsInterpreter.java | 47 +-- .../interpreter/SmsInterpreterBuilder.java | 103 ------ .../interpreter/SmsInterpreterParams.java | 153 ++++++++ .../interpreter/SubVoiceInterpreter.java | 58 ++- .../SubVoiceInterpreterBuilder.java | 143 -------- .../SubVoiceInterpreterParams.java | 241 +++++++++++++ .../connect/interpreter/VoiceInterpreter.java | 110 +++--- .../interpreter/VoiceInterpreterBuilder.java | 183 ---------- .../interpreter/VoiceInterpreterParams.java | 338 ++++++++++++++++++ .../connect/interpreter/rcml/Parser.java | 10 +- .../{rcml => }/GatherSpeechTest.java | 36 +- .../org/restcomm/connect/mgcp/Connection.java | 31 +- .../connect/mgcp/GenericEndpoint.java | 22 +- .../restcomm/connect/mgcp/IvrEndpoint.java | 22 +- .../java/org/restcomm/connect/mgcp/Link.java | 31 +- .../restcomm/connect/mgcp/MediaGateway.java | 18 +- .../restcomm/connect/mgcp/MockConnection.java | 4 +- .../connect/mgcp/MockMediaGateway.java | 3 +- .../mgcp/AbstractMockMediaGateway.java | 5 +- .../restcomm/connect/mgcp/EndpointTest.java | 21 +- .../monitoringservice/MonitoringService.java | 32 +- ...ferenceMediaResourceControllerGeneric.java | 8 +- .../mrb/MediaResourceBrokerGeneric.java | 38 +- .../connect/mscontrol/api/MediaGroup.java | 4 +- .../mscontrol/api/MediaServerController.java | 7 +- .../api/MediaServerControllerFactory.java | 20 +- .../jsr309/Jsr309ControllerFactory.java | 24 +- .../mscontrol/mms/MmsBridgeController.java | 7 +- .../mscontrol/mms/MmsCallController.java | 7 +- .../mms/MmsConferenceController.java | 17 +- .../mscontrol/mms/MmsControllerFactory.java | 24 +- .../org/restcomm/connect/sms/SmsService.java | 25 +- .../restcomm/connect/sms/SmsServiceProxy.java | 2 +- .../org/restcomm/connect/sms/SmsSession.java | 22 +- .../connect/sms/smpp/SmppInterpreter.java | 49 +-- .../sms/smpp/SmppInterpreterBuilder.java | 83 ----- .../sms/smpp/SmppInterpreterParams.java | 153 ++++++++ .../connect/sms/smpp/SmppMessageHandler.java | 33 +- .../connect/sms/smpp/SmppService.java | 38 +- .../telephony/api/util/B2BUAHelper.java | 8 +- .../restcomm/connect/telephony/Bridge.java | 40 +-- .../connect/telephony/BridgeManager.java | 10 +- .../org/restcomm/connect/telephony/Call.java | 46 ++- .../connect/telephony/CallManager.java | 103 +++--- .../connect/telephony/CallManagerProxy.java | 7 +- .../connect/telephony/Conference.java | 9 +- .../connect/telephony/ConferenceCenter.java | 10 +- .../connect/telephony/proxy/ProxyManager.java | 36 +- .../telephony/ua/UserAgentManager.java | 8 +- .../ActorFaultToleranceTest.java | 212 ----------- .../ActorSupervisorStrategyTest.java | 110 ++++++ .../DialRecordingS3UploadTest_Secure.java | 6 +- .../telephony/DialRecordingTest.java | 83 ++++- .../telephony/DialStatusCallbackTest.java | 31 +- .../tts/acapela/AcapelaSpeechSynthesizer.java | 25 +- .../connect/tts/att/AttSpeechSynthesizer.java | 22 +- .../awspolly/AWSPollySpeechSyntetizer.java | 19 +- .../voicerss/VoiceRSSSpeechSynthesizer.java | 31 +- .../src/main/webapp/conf/dashboard.json | 3 +- .../src/main/webapp/lib/jquery/README.md | 7 + .../ussd/interpreter/UssdInterpreter.java | 59 ++- .../interpreter/UssdInterpreterBuilder.java | 126 ------- .../interpreter/UssdInterpreterParams.java | 202 +++++++++++ .../connect/ussd/telephony/UssdCall.java | 69 ++-- .../ussd/telephony/UssdCallManager.java | 59 ++- 95 files changed, 2508 insertions(+), 1748 deletions(-) create mode 100644 restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-dashboard.sh create mode 100644 restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/faulttolerance/RestcommUntypedActor.java create mode 100644 restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/client/rcmlserver/resolver/RcmlserverResolver.java create mode 100644 restcomm/restcomm.http/src/test/java/org/restcomm/connect/http/client/rcmlserver/resolver/RcmlserverResolverTest.java delete mode 100644 restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/ConfVoiceInterpreterBuilder.java create mode 100644 restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/ConfVoiceInterpreterParams.java delete mode 100644 restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SmsInterpreterBuilder.java create mode 100644 restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SmsInterpreterParams.java delete mode 100644 restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SubVoiceInterpreterBuilder.java create mode 100644 restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SubVoiceInterpreterParams.java delete mode 100644 restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreterBuilder.java create mode 100644 restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreterParams.java rename restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/{rcml => }/GatherSpeechTest.java (94%) delete mode 100644 restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppInterpreterBuilder.java create mode 100644 restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppInterpreterParams.java delete mode 100644 restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/faultTolerance/ActorFaultToleranceTest.java create mode 100644 restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/faultTolerance/ActorSupervisorStrategyTest.java delete mode 100644 restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/interpreter/UssdInterpreterBuilder.java create mode 100644 restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/interpreter/UssdInterpreterParams.java diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml index c4c954319c..7fb8ed00de 100644 --- a/.idea/codeStyleSettings.xml +++ b/.idea/codeStyleSettings.xml @@ -2,7 +2,11 @@ diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/advanced.conf b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/advanced.conf index faf5b58436..70190f78f8 100644 --- a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/advanced.conf +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/advanced.conf @@ -143,3 +143,6 @@ HTTP_RESPONSE_TIMEOUT=6000 # If set to true RestComm will NOT use cache for *.wav files playback.If set to false RestComm will use cache for *.wav files playback. CACHE_NO_WAV=false + +#MSS Configuration +TLS_CLIENT_AUTH_TYPE="Disabled" #Possible values Enabled, Want, Disabled,DisabledAll \ No newline at end of file diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-SecureSSL.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-SecureSSL.sh index e25d9e9e39..64f2c755af 100755 --- a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-SecureSSL.sh +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-SecureSSL.sh @@ -142,8 +142,8 @@ CertConfigure(){ MssStackConf(){ FILE=$RESTCOMM_CONF/mss-sip-stack.properties - if grep -q 'gov.nist.javax.sip.TLS_CLIENT_AUTH_TYPE=Disabled' "$FILE"; then - sed -i '/gov.nist.javax.sip.TLS_CLIENT_AUTH_TYPE=Disabled/,+5d' $FILE + if grep -q "gov.nist.javax.sip.TLS_CLIENT_AUTH_TYPE=${TLS_CLIENT_AUTH_TYPE}" "$FILE"; then + sed -i '/gov.nist.javax.sip.TLS_CLIENT_AUTH_TYPE='"$TLS_CLIENT_AUTH_TYPE"'/,+5d' $FILE fi if [[ "$TRUSTSTORE_FILE" = /* ]]; then @@ -157,7 +157,7 @@ MssStackConf(){ sed -i '/org.mobicents.ha.javax.sip.LOCAL_SSL_PORT='"$HTTPS_PORT"'/ a \ - \gov.nist.javax.sip.TLS_CLIENT_AUTH_TYPE=Disabled\ + \gov.nist.javax.sip.TLS_CLIENT_AUTH_TYPE='"$TLS_CLIENT_AUTH_TYPE"'\ \javax.net.ssl.keyStore='"$TRUSTSTORE_LOCATION"'\ \javax.net.ssl.keyStorePassword='" $TRUSTSTORE_PASSWORD"'\ \javax.net.ssl.trustStorePassword='"$TRUSTSTORE_PASSWORD"'\ diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-dashboard.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-dashboard.sh new file mode 100644 index 0000000000..ec8c1b1117 --- /dev/null +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-dashboard.sh @@ -0,0 +1,30 @@ +#!/bin/bash +## +## Configures dashboard.json based on global configuration options in restcomm.conf and advanced.conf. +## +## requirements: +## +## RESTCOMM_HOME env variable to be set +## dashboard.json should be in place (under $RESTCOMM_HOME/standalone/deployments/restcomm-management.war) +## +## Author: otsakir@gmail.com - Orestis Tsakiridis + +echo "Configuring Dashboard..." + + +# MAIN +if [ -z "$RESTCOMM_HOME" ] +then + echo "RESTCOMM_HOME env variable not set. Aborting." + exit 1 +fi + + +# Variables +DASHBOARD_ROOT="$RESTCOMM_HOME"/standalone/deployments/restcomm-management.war +DASHBOARD_JSON_FILE="$DASHBOARD_ROOT"/conf/dashboard.json + +sed -i "s|\"rvdUrl\":\"[^\"]*\"|\"rvdUrl\":\"$RVD_URL/restcomm-rvd\"|" "$DASHBOARD_JSON_FILE" + +echo "Dasboard configured:" +cat $DASHBOARD_JSON_FILE \ No newline at end of file diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-rvd.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-rvd.sh index e3ff7593e9..c1274db6de 100755 --- a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-rvd.sh +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-rvd.sh @@ -56,7 +56,7 @@ fi echo "Configuring RVD" -if [ "$RVD_VIDEO_SUPPORT" = true || "$RVD_VIDEO_SUPPORT" = TRUE || "$RVD_VIDEO_SUPPORT" = True ] ; then +if [[ "$RVD_VIDEO_SUPPORT" = true || "$RVD_VIDEO_SUPPORT" = TRUE || "$RVD_VIDEO_SUPPORT" = True ]] ; then updateVideoSupport true else updateVideoSupport false diff --git a/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/Bootstrapper.java b/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/Bootstrapper.java index 475cb295af..594743871a 100644 --- a/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/Bootstrapper.java +++ b/restcomm/restcomm.application/src/main/java/org/restcomm/connect/application/Bootstrapper.java @@ -78,7 +78,7 @@ private MediaServerControllerFactory mediaServerControllerFactory(final Configur try { settings = configuration.subset("media-server-manager"); ActorRef mrb = mediaResourceBroker(settings, storage, loader); - factory = new MmsControllerFactory(system, mrb); + factory = new MmsControllerFactory(mrb); } catch (UnknownHostException e) { throw new ServletException(e); } @@ -98,7 +98,7 @@ private MediaServerControllerFactory mediaServerControllerFactory(final Configur // Create JSR 309 factory MsControlFactory msControlFactory = driver.getFactory(properties); MediaServerInfo mediaServerInfo = mediaServerInfo(settings); - factory = new Jsr309ControllerFactory(system, mediaServerInfo, msControlFactory); + factory = new Jsr309ControllerFactory(mediaServerInfo, msControlFactory); } catch (UnknownHostException | MsControlException e) { throw new ServletException(e); } diff --git a/restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/ISpeechAsr.java b/restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/ISpeechAsr.java index bbd32cd10d..4473ea2736 100644 --- a/restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/ISpeechAsr.java +++ b/restcomm/restcomm.asr/src/main/java/org/restcomm/connect/asr/ISpeechAsr.java @@ -20,23 +20,22 @@ package org.restcomm.connect.asr; import akka.actor.ActorRef; -import akka.actor.UntypedActor; - import com.iSpeech.SpeechResult; import com.iSpeech.iSpeechRecognizer; -import static com.iSpeech.iSpeechRecognizer.*; import com.iSpeech.iSpeechRecognizer.SpeechRecognizerEvent; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import java.io.File; import java.util.HashMap; import java.util.Map; -import org.apache.commons.configuration.Configuration; +import static com.iSpeech.iSpeechRecognizer.FREEFORM_DICTATION; /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ -public final class ISpeechAsr extends UntypedActor implements SpeechRecognizerEvent { +public final class ISpeechAsr extends RestcommUntypedActor implements SpeechRecognizerEvent { private static final Map languages = new HashMap(); static { languages.put("en", "en-US"); diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/amazonS3/S3AccessTool.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/amazonS3/S3AccessTool.java index eb9a9560db..db07a3aa5e 100644 --- a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/amazonS3/S3AccessTool.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/amazonS3/S3AccessTool.java @@ -29,6 +29,7 @@ import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3Client; import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import com.amazonaws.services.s3.S3ClientOptions; import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest; import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.model.PutObjectRequest; @@ -86,6 +87,7 @@ public AmazonS3 getS3client() { s3client = new AmazonS3Client(awsCreds); s3client.setRegion(Region.getRegion(Regions.fromName(bucketRegion))); s3client.setEndpoint(testingUrl); + s3client.setS3ClientOptions(S3ClientOptions.builder().setPathStyleAccess(true).disableChunkedEncoding().build()); } else { s3client = AmazonS3ClientBuilder.standard().withRegion(Regions.fromName(bucketRegion)) .withCredentials(new AWSStaticCredentialsProvider(awsCreds)).build(); @@ -102,7 +104,9 @@ public URI uploadFile(final String fileToUpload) { logger.info("S3 Region: "+bucketRegion.toString()); } try { - if (testing && (!testingUrl.isEmpty() || !testingUrl.equals(""))) { + URI fileUri = URI.create(fileToUpload); + File file = new File(fileUri); + if (!file.exists() && testing && (!testingUrl.isEmpty() || !testingUrl.equals(""))) { // s3client.setEndpoint(testingUrl); // s3client.setS3ClientOptions(new S3ClientOptions().withPathStyleAccess(true)); FileUtils.touch(new File(URI.create(fileToUpload))); @@ -111,13 +115,22 @@ public URI uploadFile(final String fileToUpload) { bucket.append(bucketName); if (folder != null && !folder.isEmpty()) bucket.append("/").append(folder); - URI fileUri = URI.create(fileToUpload); if (logger.isInfoEnabled()) { logger.info("File to upload to S3: " + fileUri.toString()); } - File file = new File(fileUri); while (!FileUtils.waitFor(file, 30)){} + if (testing) { + try { + if (logger.isInfoEnabled()) { + logger.info("Will thread sleep for 1 minute simulating the long operation of FileUtils.waitFor"); + } + Thread.sleep(60000); + } catch (Exception e) { + logger.error("Exception while sleepig simulating the long operation waiting for the file"); + + } + } if (file.exists()) { PutObjectRequest putRequest = new PutObjectRequest(bucket.toString(), file.getName(), file); ObjectMetadata metadata = new ObjectMetadata(); @@ -190,4 +203,4 @@ private void removeLocalFile(final File file) { } } } -} \ No newline at end of file +} diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/DiskCache.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/DiskCache.java index fffd6cfcad..b3f739dc0d 100644 --- a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/DiskCache.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/cache/DiskCache.java @@ -20,12 +20,12 @@ package org.restcomm.connect.commons.cache; import akka.actor.ActorRef; -import akka.actor.UntypedActor; import akka.event.Logging; import akka.event.LoggingAdapter; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.apache.shiro.crypto.hash.Sha256Hash; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import java.io.File; import java.io.FileNotFoundException; @@ -39,7 +39,7 @@ /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ -public final class DiskCache extends UntypedActor { +public final class DiskCache extends RestcommUntypedActor { // Logger. private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/faulttolerance/RestcommSupervisorStrategy.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/faulttolerance/RestcommSupervisorStrategy.java index 746c1c642f..56c783b190 100644 --- a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/faulttolerance/RestcommSupervisorStrategy.java +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/faulttolerance/RestcommSupervisorStrategy.java @@ -20,9 +20,9 @@ public class RestcommSupervisorStrategy implements SupervisorStrategyConfigurato private static Logger logger = Logger.getLogger(RestcommSupervisorStrategy.class); - final SupervisorStrategy.Directive strategy = resume(); + static final SupervisorStrategy.Directive strategy = resume(); - RestcommFaultToleranceStrategy defaultStrategy = new RestcommFaultToleranceStrategy(10, Duration.create("1 minute"), + static RestcommFaultToleranceStrategy defaultStrategy = new RestcommFaultToleranceStrategy(10, Duration.create("1 minute"), new RestcommFaultToleranceDecider()); @Override @@ -30,7 +30,11 @@ public SupervisorStrategy create() { return defaultStrategy; } - private class RestcommFaultToleranceStrategy extends OneForOneStrategy { + public static SupervisorStrategy getStrategy() { + return defaultStrategy; + } + + private static class RestcommFaultToleranceStrategy extends OneForOneStrategy { public RestcommFaultToleranceStrategy(int maxNrOfRetries, Duration withinTimeRange, Function function) { super(maxNrOfRetries, withinTimeRange, function); @@ -51,7 +55,7 @@ public boolean handleFailure(ActorContext context, ActorRef child, Throwable cau // } } - private class RestcommFaultToleranceDecider implements Function { + private static class RestcommFaultToleranceDecider implements Function { @Override // - 2nd the Supervisor strategy will execute the Decider apply() to check what to do with the exception diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/faulttolerance/RestcommUntypedActor.java b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/faulttolerance/RestcommUntypedActor.java new file mode 100644 index 0000000000..559b33e6d8 --- /dev/null +++ b/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/faulttolerance/RestcommUntypedActor.java @@ -0,0 +1,35 @@ +/* + * 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.commons.faulttolerance; + +import akka.actor.SupervisorStrategy; +import akka.actor.UntypedActor; + +/** + * @author oleg.agafonov@telestax.com (Oleg Agafonov) + */ +public abstract class RestcommUntypedActor extends UntypedActor { + + @Override + public SupervisorStrategy supervisorStrategy() { + return RestcommSupervisorStrategy.getStrategy(); + } +} diff --git a/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/faulttolerance/SupervisorActorCreationStressTest.java b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/faulttolerance/SupervisorActorCreationStressTest.java index c5a4a09001..cede0393c6 100644 --- a/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/faulttolerance/SupervisorActorCreationStressTest.java +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/faulttolerance/SupervisorActorCreationStressTest.java @@ -16,9 +16,7 @@ import org.junit.Test; import org.restcomm.connect.commons.faulttolerance.tool.ActorCreatingThread; -import akka.actor.ActorRef; import akka.actor.ActorSystem; -import akka.actor.Props; /** * @author mariafarooq @@ -46,7 +44,7 @@ public static void beforeClass() throws Exception { actorFailureCount = new AtomicInteger(); } - @Test + @Test public void testCreateSampleAkkaActor() throws ConfigurationException, MalformedURLException, UnknownHostException, InterruptedException { ExecutorService executor = Executors.newFixedThreadPool(nThreads); for (int i = 0; i < THREAD_COUNT; i++) { diff --git a/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/faulttolerance/tool/MyUntypedActor.java b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/faulttolerance/tool/MyUntypedActor.java index 098e8404dc..22e018a867 100644 --- a/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/faulttolerance/tool/MyUntypedActor.java +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/faulttolerance/tool/MyUntypedActor.java @@ -1,20 +1,14 @@ package org.restcomm.connect.commons.faulttolerance.tool; -import static akka.pattern.Patterns.ask; - -import java.util.concurrent.TimeUnit; - -import akka.actor.ActorSystem; -import org.restcomm.connect.commons.faulttolerance.SupervisorActorCreationStressTest; - import akka.actor.ActorRef; +import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.UntypedActor; import akka.actor.UntypedActorFactory; import akka.event.Logging; import akka.event.LoggingAdapter; -import scala.concurrent.Await; -import scala.concurrent.duration.Duration; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; +import org.restcomm.connect.commons.faulttolerance.SupervisorActorCreationStressTest; /** * MyUntypedActor represent a restcomm-connect class that request supervisor to create actor for it @@ -22,7 +16,7 @@ * @author mariafarooq * */ -public class MyUntypedActor extends UntypedActor { +public class MyUntypedActor extends RestcommUntypedActor { private LoggingAdapter logger = Logging.getLogger(getContext().system(), this); private final ActorSystem system; diff --git a/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/faulttolerance/tool/SimpleActor.java b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/faulttolerance/tool/SimpleActor.java index 352f75b1be..d126731961 100644 --- a/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/faulttolerance/tool/SimpleActor.java +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/faulttolerance/tool/SimpleActor.java @@ -1,6 +1,6 @@ package org.restcomm.connect.commons.faulttolerance.tool; -import akka.actor.UntypedActor; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; /** * SampleActor: a simple actor to be created @@ -8,7 +8,7 @@ * @author mariafarooq * */ -public class SimpleActor extends UntypedActor { +public class SimpleActor extends RestcommUntypedActor { public SimpleActor(){ } diff --git a/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/patterns/ObserverPatternTest.java b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/patterns/ObserverPatternTest.java index eb5f4f449a..1f60838767 100644 --- a/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/patterns/ObserverPatternTest.java +++ b/restcomm/restcomm.commons/src/test/java/org/restcomm/connect/commons/patterns/ObserverPatternTest.java @@ -22,20 +22,17 @@ import akka.actor.ActorRef; import akka.actor.ActorSystem; import akka.actor.Props; -import akka.actor.UntypedActor; import akka.testkit.JavaTestKit; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import java.util.ArrayList; import java.util.List; -import static org.junit.Assert.*; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.restcomm.connect.commons.patterns.Observe; -import org.restcomm.connect.commons.patterns.Observing; -import org.restcomm.connect.commons.patterns.StopObserving; -import org.restcomm.connect.commons.patterns.TooManyObserversException; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; /** * @author thomas.quintana@telestax.com (Thomas Quintana) @@ -108,7 +105,7 @@ public void testTooManyObserversException() { private static final class BroadcastHelloWorld { } - private static final class ObservableActor extends UntypedActor { + private static final class ObservableActor extends RestcommUntypedActor { private final List listeners; @SuppressWarnings("unused") diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/How to get started with Restcomm-Connect and Mysql.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/How to get started with Restcomm-Connect and Mysql.adoc index a91ece62a2..ff9b867294 100644 --- a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/How to get started with Restcomm-Connect and Mysql.adoc +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/configuration/How to get started with Restcomm-Connect and Mysql.adoc @@ -15,9 +15,9 @@ the following tutorial will show how to get started with Restcomm and Mysql._ == Step 1 - Download Mysql Java Connector and Configure Java Connector * Download mysql java connector as explained link:http://mvnrepository.com/artifact/mysql/mysql-connector-java[HERE] -* Create the following folder stucture mkdir -p $RESTCOMM_HOME/modules/org/mariadb/jdbc/main -* Download the myqls jar file into the main directory, cp mysql-connector-java-5.1.40.jar $RESTCOMM_HOME/modules/org/mariadb/jdbc/main -* create a the file module.xml *vi $RESTCOMM_HOME/modules/org/mariadb/jdbc/main/module.xml* make sure the content of the module.xml looks like the one below with the appropriate mysql connector jar file name. +* Create the following folder stucture mkdir -p $RESTCOMM_HOME/modules/org/mysql/jdbc/main +* Download the myqls jar file into the main directory, cp mysql-connector-java-5.1.40.jar $RESTCOMM_HOME/modules/org/mysql/jdbc/main +* create a the file module.xml *vi $RESTCOMM_HOME/modules/org/mysql/jdbc/main/module.xml* make sure the content of the module.xml looks like the one below with the appropriate mysql connector jar file name. [source,bash] ---- @@ -103,8 +103,7 @@ show tables; GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.1.%' IDENTIFIED BY 'YourMysqlDBPwd' WITH GRANT OPTION; then save the changes as follows - -GRANT ALL PRIVILEGES; +FLUSH PRIVILEGES; The above command will allow your use to be able to access the DB on 192.168.1.x subnet The is important if you have multiple Restcomm instances in the same subnet and they will need to Replicate DB on a MASTER-MASTER format diff --git a/restcomm/restcomm.email/src/main/java/org/restcomm/connect/email/EmailService.java b/restcomm/restcomm.email/src/main/java/org/restcomm/connect/email/EmailService.java index 73dde39d59..3dc8a186b1 100644 --- a/restcomm/restcomm.email/src/main/java/org/restcomm/connect/email/EmailService.java +++ b/restcomm/restcomm.email/src/main/java/org/restcomm/connect/email/EmailService.java @@ -20,19 +20,20 @@ package org.restcomm.connect.email; import akka.actor.ActorRef; -import akka.actor.UntypedActor; import akka.event.Logging; import akka.event.LoggingAdapter; import org.apache.commons.configuration.Configuration; -import org.restcomm.connect.email.api.EmailRequest; -import org.restcomm.connect.email.api.EmailResponse; -import org.restcomm.connect.email.api.Mail; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.patterns.Observe; import org.restcomm.connect.commons.patterns.Observing; import org.restcomm.connect.commons.patterns.StopObserving; +import org.restcomm.connect.email.api.EmailRequest; +import org.restcomm.connect.email.api.EmailResponse; +import org.restcomm.connect.email.api.Mail; import javax.mail.Message; import javax.mail.MessagingException; +import javax.mail.NoSuchProviderException; import javax.mail.PasswordAuthentication; import javax.mail.Session; import javax.mail.Transport; @@ -41,13 +42,12 @@ import java.util.ArrayList; import java.util.List; import java.util.Properties; -import javax.mail.NoSuchProviderException; /** * @author liblefty@gmail.com (Lefteris Banos) */ -public class EmailService extends UntypedActor { +public class EmailService extends RestcommUntypedActor { final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); private final List observers; diff --git a/restcomm/restcomm.fax/src/main/java/org/restcomm/connect/fax/InterfaxService.java b/restcomm/restcomm.fax/src/main/java/org/restcomm/connect/fax/InterfaxService.java index 8f434cfbb9..0a320b3753 100644 --- a/restcomm/restcomm.fax/src/main/java/org/restcomm/connect/fax/InterfaxService.java +++ b/restcomm/restcomm.fax/src/main/java/org/restcomm/connect/fax/InterfaxService.java @@ -20,14 +20,6 @@ package org.restcomm.connect.fax; import akka.actor.ActorRef; -import akka.actor.UntypedActor; - -import java.io.File; -import java.net.URI; -import java.net.URLConnection; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - import org.apache.commons.configuration.Configuration; import org.apache.http.Header; import org.apache.http.HttpHeaders; @@ -45,11 +37,18 @@ import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; import org.apache.http.util.EntityUtils; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; + +import java.io.File; +import java.net.URI; +import java.net.URLConnection; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ -public final class InterfaxService extends UntypedActor { +public final class InterfaxService extends RestcommUntypedActor { private static final String url = "https://rest.interfax.net/outbound/faxes?faxNumber="; private final TrustStrategy strategy; diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AccountsEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AccountsEndpoint.java index 4ced8a1fda..b876c8c1df 100644 --- a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AccountsEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/AccountsEndpoint.java @@ -62,13 +62,8 @@ import java.util.ArrayList; import java.util.List; -import static javax.ws.rs.core.MediaType.APPLICATION_JSON; -import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; -import static javax.ws.rs.core.MediaType.APPLICATION_XML; -import static javax.ws.rs.core.MediaType.APPLICATION_XML_TYPE; -import static javax.ws.rs.core.Response.Status.BAD_REQUEST; -import static javax.ws.rs.core.Response.Status.CONFLICT; -import static javax.ws.rs.core.Response.Status.NOT_FOUND; +import static javax.ws.rs.core.MediaType.*; +import static javax.ws.rs.core.Response.Status.*; import static javax.ws.rs.core.Response.ok; import static javax.ws.rs.core.Response.status; diff --git a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/CallsEndpoint.java b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/CallsEndpoint.java index 052f4605bd..3d0c6e6566 100644 --- a/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/CallsEndpoint.java +++ b/restcomm/restcomm.http/src/main/java/org/restcomm/connect/http/CallsEndpoint.java @@ -81,6 +81,7 @@ import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; +import java.util.LinkedList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; @@ -350,7 +351,7 @@ protected Response putCall(final String accountSid, final MultivaluedMap statusCallbackEvent = new ArrayList(); + List statusCallbackEvent = new LinkedList(); statusCallbackEvent.add("initiated"); statusCallbackEvent.add("ringing"); statusCallbackEvent.add("answered"); @@ -377,7 +378,7 @@ protected Response putCall(final String accountSid, final MultivaluedMap + * + */ + +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.interpreter/src/main/java/org/restcomm/connect/interpreter/AudioPlayerInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/AudioPlayerInterpreter.java index 758cf9c900..14284931f5 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/AudioPlayerInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/AudioPlayerInterpreter.java @@ -19,12 +19,12 @@ */ package org.restcomm.connect.interpreter; -import akka.actor.UntypedActor; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ -public final class AudioPlayerInterpreter extends UntypedActor { +public final class AudioPlayerInterpreter extends RestcommUntypedActor { public AudioPlayerInterpreter() { super(); } diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java index e9cd310420..105103e6dc 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java @@ -21,7 +21,6 @@ import akka.actor.Actor; import akka.actor.ActorRef; -import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.UntypedActor; import akka.actor.UntypedActorContext; @@ -49,6 +48,7 @@ import org.restcomm.connect.commons.configuration.RestcommConfiguration; import org.restcomm.connect.commons.dao.CollectedResult; import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.fsm.Action; import org.restcomm.connect.commons.fsm.FiniteStateMachine; import org.restcomm.connect.commons.fsm.State; @@ -135,7 +135,7 @@ * @author gvagenas@telestax.com * @author pavel.slegr@telestax.com */ -public abstract class BaseVoiceInterpreter extends UntypedActor { +public abstract class BaseVoiceInterpreter extends RestcommUntypedActor { // Logger. private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); @@ -144,8 +144,6 @@ public abstract class BaseVoiceInterpreter extends UntypedActor { static final Pattern PATTERN = Pattern.compile("[\\*#0-9]{1,12}"); static String EMAIL_SENDER = "restcomm@restcomm.org"; - protected final ActorSystem system; - // States for the FSM. // ========================== final State uninitialized; @@ -268,7 +266,6 @@ public BaseVoiceInterpreter() { super(); restcommConfiguration = RestcommConfiguration.getInstance(); final ActorRef source = self(); - this.system = context().system(); // 20 States in common uninitialized = new State("uninitialized", null, null); acquiringAsrInfo = new State("acquiring asr info", new AcquiringAsrInfo(source), null); @@ -433,7 +430,7 @@ public Actor create() throws Exception { return new ISpeechAsr(configuration); } }); - return system.actorOf(props); + return getContext().actorOf(props); } @SuppressWarnings("unchecked") @@ -482,7 +479,7 @@ public Actor create() throws Exception { return new InterfaxService(configuration); } }); - return system.actorOf(props); + return getContext().actorOf(props); } //Callback using the Akka ask pattern (http://doc.akka.io/docs/akka/2.2.5/java/untyped-actors.html#Ask__Send-And-Receive-Future) will force VoiceInterpter to wait until @@ -551,7 +548,7 @@ public UntypedActor create() throws Exception { return new DiskCacheFactory(configuration).getDiskCache(path, uri); } }); - return system.actorOf(props); + return getContext().actorOf(props); } protected ActorRef downloader() { @@ -563,7 +560,7 @@ public UntypedActor create() throws Exception { return new Downloader(); } }); - return system.actorOf(props); + return getContext().actorOf(props); } String e164(final String number) { @@ -596,7 +593,7 @@ public Actor create() throws Exception { return new EmailService(configuration); } }); - return system.actorOf(props); + return getContext().actorOf(props); } private Notification notification(final int log, final int error, final String message) { @@ -661,18 +658,18 @@ public UntypedActor create() throws IOException { return new Parser(xml, self()); } }); - return system.actorOf(props); + return getContext().actorOf(props); } void postCleanup() { if (smsSessions.isEmpty() && outstandingAsrRequests == 0) { final UntypedActorContext context = getContext(); if (parser != null) - system.stop(parser); + getContext().stop(parser); context.stop(self()); } if (downloader != null && !downloader.isTerminated()) { - system.stop(downloader); + getContext().stop(downloader); } } @@ -829,7 +826,7 @@ public Actor create() throws Exception { return (UntypedActor) Class.forName(classpath).getConstructor(Configuration.class).newInstance(ttsConf); } }); - return system.actorOf(props); + return getContext().actorOf(props); } abstract class AbstractAction implements Action { @@ -1883,6 +1880,10 @@ public void execute(final Object message) throws Exception { if (duration.equals(0.0)) { final DateTime end = DateTime.now(); duration = new Double((end.getMillis() - callRecord.getStartTime().getMillis()) / 1000); + if (logger.isDebugEnabled()) { + String msg = String.format("Recording duration %s, startTime %s endTime %s", duration, callRecord.getStartTime().getMillis(), end.getMillis()); + logger.debug(msg); + } } else if(logger.isDebugEnabled()) { logger.debug("File already exists, length: "+ (new File(recordingUri).length())); } @@ -1963,8 +1964,10 @@ public void execute(final Object message) throws Exception { logger.error(exception.getMessage(), exception); } } - } else if(logger.isInfoEnabled()){ - logger.info("AsrService is not enabled"); + } else { + if(logger.isDebugEnabled()){ + logger.debug("AsrService is not enabled"); + } } // If action is present redirect to the action URI. @@ -2047,15 +2050,10 @@ public void execute(final Object message) throws Exception { // final StopInterpreter stop = new StopInterpreter(); // source.tell(stop, source); } - } - if (CallStateChanged.class.equals(klass) ) { - if (action == null || action.isEmpty()) { - source.tell(new StopInterpreter(), source); - } else { - // Ask the parser for the next action to take. - final GetNextVerb next = new GetNextVerb(); - parser.tell(next, source); - } + } else { + //Action is null here + final GetNextVerb next = new GetNextVerb(); + parser.tell(next, source); } // A little clean up. recordingSid = null; diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/ConfVoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/ConfVoiceInterpreter.java index cc204935c9..3ab740f54e 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/ConfVoiceInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/ConfVoiceInterpreter.java @@ -2,7 +2,6 @@ import akka.actor.Actor; import akka.actor.ActorRef; -import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.ReceiveTimeout; import akka.actor.UntypedActor; @@ -24,6 +23,7 @@ import org.restcomm.connect.commons.cache.DiskCacheResponse; import org.restcomm.connect.commons.cache.HashGenerator; import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.fsm.Action; import org.restcomm.connect.commons.fsm.FiniteStateMachine; import org.restcomm.connect.commons.fsm.State; @@ -73,7 +73,7 @@ import static org.restcomm.connect.interpreter.rcml.Verbs.play; import static org.restcomm.connect.interpreter.rcml.Verbs.say; -public class ConfVoiceInterpreter extends UntypedActor { +public class ConfVoiceInterpreter extends RestcommUntypedActor { private static final int ERROR_NOTIFICATION = 0; private static final int WARNING_NOTIFICATION = 1; static String EMAIL_SENDER; @@ -146,15 +146,10 @@ public class ConfVoiceInterpreter extends UntypedActor { private ActorRef originalInterpreter; - private ActorSystem system; - - public ConfVoiceInterpreter(final Configuration configuration, final Sid account, final String version, final URI url, - final String method, final String emailAddress, final ActorRef conference, final DaoManager storage, - final CallInfo callInfo) { + public ConfVoiceInterpreter(final ConfVoiceInterpreterParams params) { super(); - this.system = context().system(); source = self(); uninitialized = new State("uninitialized", null, null); @@ -233,14 +228,14 @@ public ConfVoiceInterpreter(final Configuration configuration, final Sid account // Initialize the FSM. this.fsm = new FiniteStateMachine(uninitialized, transitions); // Initialize the runtime stuff. - this.accountId = account; - this.version = version; - this.url = url; - this.method = method; - this.emailAddress = emailAddress; - this.configuration = configuration; - - this.storage = storage; + this.accountId = params.getAccount(); + this.version = params.getVersion(); + this.url = params.getUrl(); + this.method = params.getMethod(); + this.emailAddress = params.getEmailAddress(); + this.configuration = params.getConfiguration(); + + this.storage = params.getStorage(); this.synthesizer = tts(configuration.subset("speech-synthesizer")); final Configuration runtime = configuration.subset("runtime-settings"); String path = runtime.getString("cache-path"); @@ -257,8 +252,17 @@ public ConfVoiceInterpreter(final Configuration configuration, final Sid account this.cache = cache(path, uri); this.downloader = downloader(); - this.callInfo = callInfo; - this.conference = conference; + this.callInfo = params.getCallInfo(); + this.conference = params.getConference(); + } + + public static Props props(final ConfVoiceInterpreterParams params) { + return new Props(new UntypedActorFactory() { + @Override + public Actor create() throws Exception { + return new ConfVoiceInterpreter(params); + } + }); } private ActorRef cache(final String path, final String uri) { @@ -270,7 +274,7 @@ public UntypedActor create() throws Exception { return new DiskCacheFactory(configuration).getDiskCache(path, uri); } }); - return system.actorOf(props); + return getContext().actorOf(props); } private ActorRef downloader() { @@ -282,7 +286,7 @@ public UntypedActor create() throws Exception { return new Downloader(); } }); - return system.actorOf(props); + return getContext().actorOf(props); } private String e164(final String number) { @@ -311,7 +315,7 @@ public Actor create() throws Exception { return new EmailService(configuration); } }); - return system.actorOf(props); + return getContext().actorOf(props); } private Notification notification(final int log, final int error, final String message) { @@ -510,7 +514,7 @@ public UntypedActor create() throws Exception { return new Parser(xml, self()); } }); - return system.actorOf(props); + return getContext().actorOf(props); } private void postCleanup() { @@ -584,7 +588,7 @@ public Actor create() throws Exception { return (UntypedActor) Class.forName(classpath).getConstructor(Configuration.class).newInstance(configuration); } }); - return system.actorOf(props); + return getContext().actorOf(props); } private abstract class AbstractAction implements Action { diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/ConfVoiceInterpreterBuilder.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/ConfVoiceInterpreterBuilder.java deleted file mode 100644 index 20467fcc14..0000000000 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/ConfVoiceInterpreterBuilder.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.restcomm.connect.interpreter; - -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.actor.Props; -import akka.actor.UntypedActor; -import akka.actor.UntypedActorFactory; -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.restcomm.connect.commons.dao.Sid; -import org.restcomm.connect.dao.DaoManager; -import org.restcomm.connect.telephony.api.CallInfo; - -import java.net.URI; - -public class ConfVoiceInterpreterBuilder { - - private Logger logger = Logger.getLogger(ConfVoiceInterpreterBuilder.class); - private ActorSystem system; - private Configuration configuration; - private Sid account; - private String version; - private URI url; - private String method; - private String emailAddress; - private ActorRef conference; - private DaoManager storage; - private CallInfo callInfo; - - public ConfVoiceInterpreterBuilder(final ActorSystem system) { - super(); - this.system = system; - } - - public ActorRef build() { - final Props props = new Props(new UntypedActorFactory() { - private static final long serialVersionUID = 1L; - @Override - public UntypedActor create() throws Exception { - return new ConfVoiceInterpreter(configuration, account, version, url, method, emailAddress, conference, - storage, callInfo); - } - }); - return system.actorOf(props); - } - - public void setConfiguration(final Configuration configuration) { - this.configuration = configuration; - } - - public void setAccount(final Sid account) { - this.account = account; - } - - public void setVersion(final String version) { - this.version = version; - } - - public void setUrl(final URI url) { - this.url = url; - } - - public void setMethod(final String method) { - this.method = method; - } - - public void setEmailAddress(final String emailAddress) { - this.emailAddress = emailAddress; - } - - public void setConference(final ActorRef conference) { - this.conference = conference; - } - - public void setStorage(final DaoManager storage) { - this.storage = storage; - } - - public void setCallInfo(CallInfo callInfo) { - this.callInfo = callInfo; - } - -} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/ConfVoiceInterpreterParams.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/ConfVoiceInterpreterParams.java new file mode 100644 index 0000000000..8c492a921b --- /dev/null +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/ConfVoiceInterpreterParams.java @@ -0,0 +1,154 @@ +/* + * 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.interpreter; + +import akka.actor.ActorRef; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.telephony.api.CallInfo; + +import java.net.URI; + +/** + * @author oleg.agafonov@telestax.com (Oleg Agafonov) + */ +public final class ConfVoiceInterpreterParams { + + private Configuration configuration; + private Sid account; + private String version; + private URI url; + private String method; + private String emailAddress; + private ActorRef conference; + private DaoManager storage; + private CallInfo callInfo; + + private ConfVoiceInterpreterParams(Configuration configuration, Sid account, String version, URI url, String method, String emailAddress, ActorRef conference, DaoManager storage, CallInfo callInfo) { + this.configuration = configuration; + this.account = account; + this.version = version; + this.url = url; + this.method = method; + this.emailAddress = emailAddress; + this.conference = conference; + this.storage = storage; + this.callInfo = callInfo; + } + + public Configuration getConfiguration() { + return configuration; + } + + public Sid getAccount() { + return account; + } + + public String getVersion() { + return version; + } + + public URI getUrl() { + return url; + } + + public String getMethod() { + return method; + } + + public String getEmailAddress() { + return emailAddress; + } + + public ActorRef getConference() { + return conference; + } + + public DaoManager getStorage() { + return storage; + } + + public CallInfo getCallInfo() { + return callInfo; + } + + public static class ConfVoiceInterpreterParamsBuilder { + private Configuration configuration; + private Sid account; + private String version; + private URI url; + private String method; + private String emailAddress; + private ActorRef conference; + private DaoManager storage; + private CallInfo callInfo; + + public ConfVoiceInterpreterParamsBuilder setConfiguration(Configuration configuration) { + this.configuration = configuration; + return this; + } + + public ConfVoiceInterpreterParamsBuilder setAccount(Sid account) { + this.account = account; + return this; + } + + public ConfVoiceInterpreterParamsBuilder setVersion(String version) { + this.version = version; + return this; + } + + public ConfVoiceInterpreterParamsBuilder setUrl(URI url) { + this.url = url; + return this; + } + + public ConfVoiceInterpreterParamsBuilder setMethod(String method) { + this.method = method; + return this; + } + + public ConfVoiceInterpreterParamsBuilder setEmailAddress(String emailAddress) { + this.emailAddress = emailAddress; + return this; + } + + public ConfVoiceInterpreterParamsBuilder setConference(ActorRef conference) { + this.conference = conference; + return this; + } + + public ConfVoiceInterpreterParamsBuilder setStorage(DaoManager storage) { + this.storage = storage; + return this; + } + + public ConfVoiceInterpreterParamsBuilder setCallInfo(CallInfo callInfo) { + this.callInfo = callInfo; + return this; + } + + public ConfVoiceInterpreterParams biuld() { + return new ConfVoiceInterpreterParams(configuration, account, version, url, method, emailAddress, conference, storage, callInfo); + } + } +} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SmsInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SmsInterpreter.java index fde93038a9..d43da8647f 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SmsInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SmsInterpreter.java @@ -21,7 +21,6 @@ import akka.actor.Actor; import akka.actor.ActorRef; -import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.UntypedActor; import akka.actor.UntypedActorContext; @@ -40,6 +39,7 @@ import org.apache.http.message.BasicNameValuePair; import org.joda.time.DateTime; import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.fsm.Action; import org.restcomm.connect.commons.fsm.FiniteStateMachine; import org.restcomm.connect.commons.fsm.State; @@ -92,14 +92,13 @@ /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ -public final class SmsInterpreter extends UntypedActor { +public final class SmsInterpreter extends RestcommUntypedActor { private static final int ERROR_NOTIFICATION = 0; private static final int WARNING_NOTIFICATION = 1; static String EMAIL_SENDER; // Logger private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); - private final ActorSystem system; // States for the FSM. private final State uninitialized; private final State acquiringLastSmsRequest; @@ -149,12 +148,9 @@ public final class SmsInterpreter extends UntypedActor { private ConcurrentHashMap customHttpHeaderMap = new ConcurrentHashMap(); private ConcurrentHashMap customRequestHeaderMap; - public SmsInterpreter(final ActorRef service, final Configuration configuration, final DaoManager storage, - final Sid accountId, final String version, final URI url, final String method, final URI fallbackUrl, - final String fallbackMethod) { + public SmsInterpreter(final SmsInterpreterParams params) { super(); final ActorRef source = self(); - this.system = context().system(); uninitialized = new State("uninitialized", null, null); acquiringLastSmsRequest = new State("acquiring last sms event", new AcquiringLastSmsEvent(source), null); downloadingRcml = new State("downloading rcml", new DownloadingRcml(source), null); @@ -210,22 +206,31 @@ public SmsInterpreter(final ActorRef service, final Configuration configuration, // Initialize the FSM. this.fsm = new FiniteStateMachine(uninitialized, transitions); // Initialize the runtime stuff. - this.service = service; + this.service = params.getSmsService(); this.downloader = downloader(); - this.storage = storage; - this.emailconfiguration = configuration.subset("smtp-service"); - this.runtime = configuration.subset("runtime-settings"); - this.configuration = configuration.subset("sms-aggregator"); - this.accountId = accountId; - this.version = version; - this.url = url; - this.method = method; - this.fallbackUrl = fallbackUrl; - this.fallbackMethod = fallbackMethod; + this.storage = params.getStorage(); + this.emailconfiguration = params.getConfiguration().subset("smtp-service"); + this.runtime = params.getConfiguration().subset("runtime-settings"); + this.configuration = params.getConfiguration().subset("sms-aggregator"); + this.accountId = params.getAccountId(); + this.version = params.getVersion(); + this.url = params.getUrl(); + this.method = params.getMethod(); + this.fallbackUrl = params.getFallbackUrl(); + this.fallbackMethod = params.getFallbackMethod(); this.sessions = new HashMap(); this.normalizeNumber = runtime.getBoolean("normalize-numbers-for-outbound-calls"); } + public static Props props(final SmsInterpreterParams params) { + return new Props(new UntypedActorFactory() { + @Override + public Actor create() throws Exception { + return new SmsInterpreter(params); + } + }); + } + private ActorRef downloader() { final Props props = new Props(new UntypedActorFactory() { private static final long serialVersionUID = 1L; @@ -235,7 +240,7 @@ public UntypedActor create() throws Exception { return new Downloader(); } }); - return system.actorOf(props); + return getContext().actorOf(props); } ActorRef mailer(final Configuration configuration) { @@ -247,7 +252,7 @@ public Actor create() throws Exception { return new EmailService(configuration); } }); - return system.actorOf(props); + return getContext().actorOf(props); } protected String format(final String number) { @@ -444,7 +449,7 @@ public UntypedActor create() throws Exception { return new Parser(xml, self()); } }); - return system.actorOf(props); + return getContext().actorOf(props); } private void response(final Object message) { diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SmsInterpreterBuilder.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SmsInterpreterBuilder.java deleted file mode 100644 index 2a30bc37a3..0000000000 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SmsInterpreterBuilder.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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.interpreter; - -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.actor.Props; -import akka.actor.UntypedActor; -import akka.actor.UntypedActorFactory; -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.restcomm.connect.commons.dao.Sid; -import org.restcomm.connect.dao.DaoManager; - -import java.net.URI; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public final class SmsInterpreterBuilder { - private static Logger logger = Logger.getLogger(SmsInterpreterBuilder.class); - private final ActorSystem system; - private Configuration configuration; - private ActorRef service; - private DaoManager storage; - private Sid accountId; - private String version; - private URI url; - private String method; - private URI fallbackUrl; - private String fallbackMethod; - - public SmsInterpreterBuilder(final ActorSystem system) { - super(); - this.system = system; - } - - public ActorRef build() { - final Props props = new Props(new UntypedActorFactory() { - private static final long serialVersionUID = 1L; - - @Override - public UntypedActor create() throws Exception { - return new SmsInterpreter(service, configuration, storage, accountId, version, url, method, fallbackUrl, - fallbackMethod); - } - }); - return system.actorOf(props); - } - - public void setConfiguration(final Configuration configuration) { - this.configuration = configuration; - } - - public void setSmsService(final ActorRef service) { - this.service = service; - } - - public void setStorage(final DaoManager storage) { - this.storage = storage; - } - - public void setAccount(final Sid accountId) { - this.accountId = accountId; - } - - public void setUrl(final URI url) { - this.url = url; - } - - public void setMethod(final String method) { - this.method = method; - } - - public void setFallbackUrl(final URI fallbackUrl) { - this.fallbackUrl = fallbackUrl; - } - - public void setFallbackMethod(final String fallbackMethod) { - this.fallbackMethod = fallbackMethod; - } - - public void setVersion(final String version) { - this.version = version; - } -} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SmsInterpreterParams.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SmsInterpreterParams.java new file mode 100644 index 0000000000..fce4827df8 --- /dev/null +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SmsInterpreterParams.java @@ -0,0 +1,153 @@ +/* + * 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.interpreter; + +import akka.actor.ActorRef; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.DaoManager; + +import java.net.URI; + +/** + * @author oleg.agafonov@telestax.com (Oleg Agafonov) + */ +public final class SmsInterpreterParams { + + private Configuration configuration; + private ActorRef smsService; + private DaoManager storage; + private Sid accountId; + private String version; + private URI url; + private String method; + private URI fallbackUrl; + private String fallbackMethod; + + private SmsInterpreterParams(Configuration configuration, ActorRef smsService, DaoManager storage, Sid accountId, String version, URI url, String method, URI fallbackUrl, String fallbackMethod) { + this.configuration = configuration; + this.smsService = smsService; + this.storage = storage; + this.accountId = accountId; + this.version = version; + this.url = url; + this.method = method; + this.fallbackUrl = fallbackUrl; + this.fallbackMethod = fallbackMethod; + } + + public Configuration getConfiguration() { + return configuration; + } + + public ActorRef getSmsService() { + return smsService; + } + + public DaoManager getStorage() { + return storage; + } + + public Sid getAccountId() { + return accountId; + } + + public String getVersion() { + return version; + } + + public URI getUrl() { + return url; + } + + public String getMethod() { + return method; + } + + public URI getFallbackUrl() { + return fallbackUrl; + } + + public String getFallbackMethod() { + return fallbackMethod; + } + + public static final class Builder { + private Configuration configuration; + private ActorRef smsService; + private DaoManager storage; + private Sid accountId; + private String version; + private URI url; + private String method; + private URI fallbackUrl; + private String fallbackMethod; + + public Builder setConfiguration(Configuration configuration) { + this.configuration = configuration; + return this; + } + + public Builder setSmsService(ActorRef smsService) { + this.smsService = smsService; + return this; + } + + public Builder setStorage(DaoManager storage) { + this.storage = storage; + return this; + } + + public Builder setAccountId(Sid accountId) { + this.accountId = accountId; + return this; + } + + public Builder setVersion(String version) { + this.version = version; + return this; + } + + public Builder setUrl(URI url) { + this.url = url; + return this; + } + + public Builder setMethod(String method) { + this.method = method; + return this; + } + + public Builder setFallbackUrl(URI fallbackUrl) { + this.fallbackUrl = fallbackUrl; + return this; + } + + public Builder setFallbackMethod(String fallbackMethod) { + this.fallbackMethod = fallbackMethod; + return this; + } + + public SmsInterpreterParams build() { + return new SmsInterpreterParams(configuration, smsService, storage, accountId, version, url, method, fallbackUrl, fallbackMethod); + } + } +} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SubVoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SubVoiceInterpreter.java index 6625e2a238..e3b2a69ef2 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SubVoiceInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SubVoiceInterpreter.java @@ -19,10 +19,12 @@ */ package org.restcomm.connect.interpreter; +import akka.actor.Actor; import akka.actor.ActorRef; -import akka.actor.ActorSystem; +import akka.actor.Props; import akka.actor.ReceiveTimeout; import akka.actor.UntypedActorContext; +import akka.actor.UntypedActorFactory; import akka.event.Logging; import akka.event.LoggingAdapter; @@ -40,7 +42,6 @@ import org.restcomm.connect.commons.fsm.Transition; import org.restcomm.connect.commons.telephony.CreateCallType; import org.restcomm.connect.dao.CallDetailRecordsDao; -import org.restcomm.connect.dao.DaoManager; import org.restcomm.connect.dao.NotificationsDao; import org.restcomm.connect.dao.entities.Notification; import org.restcomm.connect.fax.FaxResponse; @@ -95,19 +96,7 @@ public final class SubVoiceInterpreter extends BaseVoiceInterpreter { private Boolean hangupOnEnd = false; private ActorRef originalInterpreter; - public SubVoiceInterpreter(final ActorSystem system, final Configuration configuration, final Sid account, final Sid phone, final String version, - final URI url, final String method, final URI fallbackUrl, final String fallbackMethod, final URI statusCallback, - final String statusCallbackMethod, final String emailAddress, final ActorRef callManager, - final ActorRef conferenceManager, final ActorRef sms, final DaoManager storage) { - - this(configuration, account, phone, version, url, method, fallbackUrl, fallbackMethod, statusCallback, - statusCallbackMethod, emailAddress, callManager, conferenceManager, sms, storage, false); - } - - public SubVoiceInterpreter(final Configuration configuration, final Sid account, final Sid phone, final String version, - final URI url, final String method, final URI fallbackUrl, final String fallbackMethod, final URI statusCallback, - final String statusCallbackMethod, final String emailAddress, final ActorRef callManager, - final ActorRef conferenceManager, final ActorRef sms, final DaoManager storage, final Boolean hangupOnEnd) { + public SubVoiceInterpreter(SubVoiceInterpreterParams params) { super(); source = self(); downloadingRcml = new State("downloading rcml", new DownloadingRcml(source), null); @@ -161,23 +150,23 @@ public SubVoiceInterpreter(final Configuration configuration, final Sid account, // Initialize the FSM. this.fsm = new FiniteStateMachine(uninitialized, transitions); // Initialize the runtime stuff. - this.accountId = account; - this.phoneId = phone; - this.version = version; - this.url = url; - this.method = method; - this.fallbackUrl = fallbackUrl; - this.fallbackMethod = fallbackMethod; - this.viStatusCallback = statusCallback; - this.viStatusCallbackMethod = statusCallbackMethod; - this.emailAddress = emailAddress; - this.configuration = configuration; - this.callManager = callManager; + this.accountId = params.getAccount(); + this.phoneId = params.getPhone(); + this.version = params.getVersion(); + this.url = params.getUrl(); + this.method = params.getMethod(); + this.fallbackUrl = params.getFallbackUrl(); + this.fallbackMethod = params.getFallbackMethod(); + this.viStatusCallback = params.getStatusCallback(); + this.viStatusCallbackMethod = params.getStatusCallbackMethod(); + this.emailAddress = params.getEmailAddress(); + this.configuration = params.getConfiguration(); + this.callManager = params.getCallManager(); // this.asrService = asr(configuration.subset("speech-recognizer")); // this.faxService = fax(configuration.subset("fax-service")); - this.smsService = sms; + this.smsService = params.getSmsService(); this.smsSessions = new HashMap(); - this.storage = storage; + this.storage = params.getStorage(); // this.synthesizer = tts(configuration.subset("speech-synthesizer")); final Configuration runtime = configuration.subset("runtime-settings"); // String path = runtime.getString("cache-path"); @@ -198,7 +187,16 @@ public SubVoiceInterpreter(final Configuration configuration, final Sid account, // uri = uri + accountId.toString(); // this.cache = cache(path, uri); this.downloader = downloader(); - this.hangupOnEnd = hangupOnEnd; + this.hangupOnEnd = params.getHangupOnEnd(); + } + + public static Props props(final SubVoiceInterpreterParams params) { + return new Props(new UntypedActorFactory() { + @Override + public Actor create() throws Exception { + return new SubVoiceInterpreter(params); + } + }); } private Notification notification(final int log, final int error, final String message) { diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SubVoiceInterpreterBuilder.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SubVoiceInterpreterBuilder.java deleted file mode 100644 index 4c1a387395..0000000000 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SubVoiceInterpreterBuilder.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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.interpreter; - -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.actor.Props; -import akka.actor.UntypedActor; -import akka.actor.UntypedActorFactory; -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.restcomm.connect.commons.dao.Sid; -import org.restcomm.connect.dao.DaoManager; - -import java.net.URI; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - */ -public final class SubVoiceInterpreterBuilder { - private Logger logger = Logger.getLogger(SubVoiceInterpreterBuilder.class); - private final ActorSystem system; - private Configuration configuration; - private DaoManager storage; - private ActorRef calls; - private ActorRef conferences; - private ActorRef sms; - private Sid account; - private Sid phone; - private String version; - private URI url; - private String method; - private URI fallbackUrl; - private String fallbackMethod; - private URI statusCallback; - private String statusCallbackMethod; - private String emailAddress; - - private Boolean hangupOnEnd = false; - - /** - * @author thomas.quintana@telestax.com (Thomas Quintana) - */ - public SubVoiceInterpreterBuilder(final ActorSystem system) { - super(); - this.system = system; - } - - public ActorRef build() { - final Props props = new Props(new UntypedActorFactory() { - private static final long serialVersionUID = 1L; - - @Override - public UntypedActor create() throws Exception { - return new SubVoiceInterpreter(configuration, account, phone, version, url, method, fallbackUrl, - fallbackMethod, statusCallback, statusCallbackMethod, emailAddress, calls, conferences, sms, storage, - hangupOnEnd); - } - }); - return system.actorOf(props); - } - - public void setConfiguration(final Configuration configuration) { - this.configuration = configuration; - } - - public void setStorage(final DaoManager storage) { - this.storage = storage; - } - - public void setCallManager(final ActorRef calls) { - this.calls = calls; - } - - public void setConferenceManager(final ActorRef conferences) { - this.conferences = conferences; - } - - public void setSmsService(final ActorRef sms) { - this.sms = sms; - } - - public void setAccount(final Sid account) { - this.account = account; - } - - public void setPhone(final Sid phone) { - this.phone = phone; - } - - public void setUrl(final URI url) { - this.url = url; - } - - public void setMethod(final String method) { - this.method = method; - } - - public void setFallbackUrl(final URI fallbackUrl) { - this.fallbackUrl = fallbackUrl; - } - - public void setFallbackMethod(final String fallbackMethod) { - this.fallbackMethod = fallbackMethod; - } - - public void setStatusCallback(final URI statusCallback) { - this.statusCallback = statusCallback; - } - - public void setStatusCallbackMethod(final String statusCallbackMethod) { - this.statusCallbackMethod = statusCallbackMethod; - } - - public void setEmailAddress(final String emailAddress) { - this.emailAddress = emailAddress; - } - - public void setVersion(final String version) { - this.version = version; - } - - public void setHangupOnEnd(final Boolean hangupOnEnd) { - this.hangupOnEnd = hangupOnEnd; - } -} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SubVoiceInterpreterParams.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SubVoiceInterpreterParams.java new file mode 100644 index 0000000000..b79a5e2cb2 --- /dev/null +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/SubVoiceInterpreterParams.java @@ -0,0 +1,241 @@ +/* + * 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.interpreter; + +import akka.actor.ActorRef; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.DaoManager; + +import java.net.URI; + +/** + * @author oleg.agafonov@telestax.com (Oleg Agafonov) + */ +public final class SubVoiceInterpreterParams { + + private Configuration configuration; + private DaoManager storage; + private ActorRef callManager; + private ActorRef conferenceCenter; + private ActorRef smsService; + private Sid account; + private Sid phone; + private String version; + private URI url; + private String method; + private URI fallbackUrl; + private String fallbackMethod; + private URI statusCallback; + private String statusCallbackMethod; + private String emailAddress; + + private Boolean hangupOnEnd; + + private SubVoiceInterpreterParams(Configuration configuration, DaoManager storage, ActorRef callManager, ActorRef conferenceCenter, ActorRef smsService, Sid account, Sid phone, String version, URI url, String method, URI fallbackUrl, String fallbackMethod, URI statusCallback, String statusCallbackMethod, String emailAddress, Boolean hangupOnEnd) { + this.configuration = configuration; + this.storage = storage; + this.callManager = callManager; + this.conferenceCenter = conferenceCenter; + this.smsService = smsService; + this.account = account; + this.phone = phone; + this.version = version; + this.url = url; + this.method = method; + this.fallbackUrl = fallbackUrl; + this.fallbackMethod = fallbackMethod; + this.statusCallback = statusCallback; + this.statusCallbackMethod = statusCallbackMethod; + this.emailAddress = emailAddress; + this.hangupOnEnd = hangupOnEnd; + } + + public Configuration getConfiguration() { + return configuration; + } + + public DaoManager getStorage() { + return storage; + } + + public ActorRef getCallManager() { + return callManager; + } + + public ActorRef getConferenceCenter() { + return conferenceCenter; + } + + public ActorRef getSmsService() { + return smsService; + } + + public Sid getAccount() { + return account; + } + + public Sid getPhone() { + return phone; + } + + public String getVersion() { + return version; + } + + public URI getUrl() { + return url; + } + + public String getMethod() { + return method; + } + + public URI getFallbackUrl() { + return fallbackUrl; + } + + public String getFallbackMethod() { + return fallbackMethod; + } + + public URI getStatusCallback() { + return statusCallback; + } + + public String getStatusCallbackMethod() { + return statusCallbackMethod; + } + + public String getEmailAddress() { + return emailAddress; + } + + public Boolean getHangupOnEnd() { + return hangupOnEnd; + } + + public static final class Builder { + private Configuration configuration; + private DaoManager storage; + private ActorRef callManager; + private ActorRef conferenceCenter; + private ActorRef smsService; + private Sid account; + private Sid phone; + private String version; + private URI url; + private String method; + private URI fallbackUrl; + private String fallbackMethod; + private URI statusCallback; + private String statusCallbackMethod; + private String emailAddress; + private Boolean hangupOnEnd = false; + + public Builder() { + } + + public Builder setConfiguration(Configuration configuration) { + this.configuration = configuration; + return this; + } + + public Builder setStorage(DaoManager storage) { + this.storage = storage; + return this; + } + + public Builder setCallManager(ActorRef callManager) { + this.callManager = callManager; + return this; + } + + public Builder setConferenceCenter(ActorRef conferenceCenter) { + this.conferenceCenter = conferenceCenter; + return this; + } + + public Builder setSmsService(ActorRef smsService) { + this.smsService = smsService; + return this; + } + + public Builder setAccount(Sid account) { + this.account = account; + return this; + } + + public Builder setPhone(Sid phone) { + this.phone = phone; + return this; + } + + public Builder setVersion(String version) { + this.version = version; + return this; + } + + public Builder setUrl(URI url) { + this.url = url; + return this; + } + + public Builder setMethod(String method) { + this.method = method; + return this; + } + + public Builder setFallbackUrl(URI fallbackUrl) { + this.fallbackUrl = fallbackUrl; + return this; + } + + public Builder setFallbackMethod(String fallbackMethod) { + this.fallbackMethod = fallbackMethod; + return this; + } + + public Builder setStatusCallback(URI statusCallback) { + this.statusCallback = statusCallback; + return this; + } + + public Builder setStatusCallbackMethod(String statusCallbackMethod) { + this.statusCallbackMethod = statusCallbackMethod; + return this; + } + + public Builder setEmailAddress(String emailAddress) { + this.emailAddress = emailAddress; + return this; + } + + public Builder setHangupOnEnd(Boolean hangupOnEnd) { + this.hangupOnEnd = hangupOnEnd; + return this; + } + + public SubVoiceInterpreterParams build() { + return new SubVoiceInterpreterParams(configuration, storage, callManager, conferenceCenter, smsService, account, phone, version, url, method, fallbackUrl, fallbackMethod, statusCallback, statusCallbackMethod, emailAddress, hangupOnEnd); + } + } +} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java index 9ddb8c45d7..99f444e217 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java @@ -19,14 +19,16 @@ */ package org.restcomm.connect.interpreter; +import akka.actor.Actor; import akka.actor.ActorRef; +import akka.actor.Props; import akka.actor.ReceiveTimeout; import akka.actor.UntypedActorContext; +import akka.actor.UntypedActorFactory; import akka.event.Logging; import akka.event.LoggingAdapter; import akka.pattern.AskTimeoutException; import akka.util.Timeout; - import org.apache.commons.configuration.Configuration; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpStatus; @@ -51,7 +53,6 @@ import org.restcomm.connect.commons.telephony.CreateCallType; import org.restcomm.connect.commons.util.UriUtils; import org.restcomm.connect.dao.CallDetailRecordsDao; -import org.restcomm.connect.dao.DaoManager; import org.restcomm.connect.dao.NotificationsDao; import org.restcomm.connect.dao.entities.CallDetailRecord; import org.restcomm.connect.dao.entities.Notification; @@ -110,7 +111,6 @@ import org.restcomm.connect.telephony.api.StopBridge; import org.restcomm.connect.telephony.api.StopConference; import org.restcomm.connect.tts.api.SpeechSynthesizerResponse; - import scala.concurrent.Await; import scala.concurrent.Future; import scala.concurrent.duration.Duration; @@ -119,7 +119,6 @@ import javax.servlet.sip.SipServletRequest; import javax.servlet.sip.SipServletResponse; import javax.servlet.sip.SipSession; - import java.io.IOException; import java.math.BigDecimal; import java.net.MalformedURLException; @@ -130,6 +129,7 @@ import java.util.Currency; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -224,12 +224,7 @@ public class VoiceInterpreter extends BaseVoiceInterpreter { private String conferenceNameWithAccountAndFriendlyName; private Sid callSid; - public VoiceInterpreter(final Configuration configuration, final Sid account, final Sid phone, final String version, - final URI url, final String method, final URI fallbackUrl, final String fallbackMethod, final URI viStatusCallback, - final String statusCallbackMethod, final String referTarget, final String transferor, final String transferee, - final String emailAddress, final ActorRef callManager, - final ActorRef conferenceManager, final ActorRef bridgeManager, final ActorRef sms, final DaoManager storage, final ActorRef monitoring, final String rcml, - final boolean asImsUa, final String imsUaLogin, final String imsUaPassword) { + VoiceInterpreter(VoiceInterpreterParams params) { super(); final ActorRef source = self(); downloadingRcml = new State("downloading rcml", new DownloadingRcml(source), null); @@ -416,35 +411,44 @@ public VoiceInterpreter(final Configuration configuration, final Sid account, fi // Initialize the FSM. this.fsm = new FiniteStateMachine(uninitialized, transitions); // Initialize the runtime stuff. - this.accountId = account; - this.phoneId = phone; - this.version = version; - this.url = url; - this.method = method; - this.fallbackUrl = fallbackUrl; - this.fallbackMethod = fallbackMethod; - this.viStatusCallback = viStatusCallback; - this.viStatusCallbackMethod = statusCallbackMethod; - this.referTarget = referTarget; - this.transferor = transferor; - this.transferee = transferee; - this.emailAddress = emailAddress; - this.configuration = configuration; - this.callManager = callManager; - this.conferenceCenter = conferenceManager; - this.bridgeManager = bridgeManager; - this.smsService = sms; + this.accountId = params.getAccount(); + this.phoneId = params.getPhone(); + this.version = params.getVersion(); + this.url = params.getUrl(); + this.method = params.getMethod(); + this.fallbackUrl = params.getFallbackUrl(); + this.fallbackMethod = params.getFallbackMethod(); + this.viStatusCallback = params.getStatusCallback(); + this.viStatusCallbackMethod = params.getStatusCallbackMethod(); + this.referTarget = params.getReferTarget(); + this.transferor = params.getTransferor(); + this.transferee = params.getTransferee(); + this.emailAddress = params.getEmailAddress(); + this.configuration = params.getConfiguration(); + this.callManager = params.getCallManager(); + this.conferenceCenter = params.getConferenceCenter(); + this.bridgeManager = params.getBridgeManager(); + this.smsService = params.getSmsService(); this.smsSessions = new HashMap(); - this.storage = storage; + this.storage = params.getStorage(); final Configuration runtime = configuration.subset("runtime-settings"); playMusicForConference = Boolean.parseBoolean(runtime.getString("play-music-for-conference","false")); this.enable200OkDelay = this.configuration.subset("runtime-settings").getBoolean("enable-200-ok-delay",false); this.downloader = downloader(); - this.monitoring = monitoring; - this.rcml = rcml; - this.asImsUa = asImsUa; - this.imsUaLogin = imsUaLogin; - this.imsUaPassword = imsUaPassword; + this.monitoring = params.getMonitoring(); + this.rcml = params.getRcml(); + this.asImsUa = params.isAsImsUa(); + this.imsUaLogin = params.getImsUaLogin(); + this.imsUaPassword = params.getImsUaPassword(); + } + + public static Props props(final VoiceInterpreterParams params) { + return new Props(new UntypedActorFactory() { + @Override + public Actor create() throws Exception { + return new VoiceInterpreter(params); + } + }); } private boolean is(State state) { @@ -2103,7 +2107,7 @@ else if (CallManagerResponse.class.equals(klass) && !((CallManagerResponse)messa URI statusCallback = null; String statusCallbackMethod = "POST"; - List statusCallbackEvent = null; + List statusCallbackEvent = new LinkedList(); if (child.hasAttribute("statusCallback")) { statusCallback = new URI(child.attribute("statusCallback").value()); @@ -2113,9 +2117,9 @@ else if (CallManagerResponse.class.equals(klass) && !((CallManagerResponse)messa statusCallbackMethod = child.attribute("statusCallbackMethod").value(); } if (child.hasAttribute("statusCallbackEvent")) { - statusCallbackEvent = Arrays.asList(child.attribute("statusCallbackEvent").value().replaceAll("\\s+","").split(",")); + statusCallbackEvent.addAll(Arrays.asList(child.attribute("statusCallbackEvent").value().replaceAll("\\s+","").split(","))); } else { - statusCallbackEvent = new ArrayList(); + statusCallbackEvent = new LinkedList(); statusCallbackEvent.add("initiated"); statusCallbackEvent.add("ringing"); statusCallbackEvent.add("answered"); @@ -2324,15 +2328,21 @@ private void recordConference() { @SuppressWarnings("unchecked") private void executeDialAction(final Object message, final ActorRef outboundCall) { - if (!dialActionExecuted && verb != null && Verbs.dial.equals(verb.name())) { + Attribute attribute = null; + if (verb != null && Verbs.dial.equals(verb.name())) { + attribute = verb.attribute("action"); + } else { + if (logger.isInfoEnabled()) { + logger.info("Either Verb is null OR not Dial, Dial Action will not be executed"); + } + } + if (attribute != null && !dialActionExecuted) { if(logger.isInfoEnabled()){ logger.info("Proceeding to execute Dial Action attribute"); } this.dialActionExecuted = true; final List parameters = parameters(); - Attribute attribute = verb.attribute("action"); - if (call != null) { try { if(logger.isInfoEnabled()) { @@ -2497,9 +2507,13 @@ else if (message instanceof ReceiveTimeout) { return; } } - } else if (verb == null) { - if(logger.isInfoEnabled()) { - logger.info("Dial action didn't executed because verb is null"); + } else { + if (logger.isInfoEnabled()) { + if (attribute == null) { + logger.info("DialAction URL is null, DialAction will not be executed"); + } else { + logger.info("DialAction has already been executed"); + } } } } @@ -3123,7 +3137,7 @@ public void execute(final Object message) throws Exception { callManager.tell(new DestroyCall(call), super.source); if (outboundCall != null) { callManager.tell(new DestroyCall(outboundCall), super.source); - } if (sender != call) { + } if (sender != call && !sender.equals(self())) { callManager.tell(new DestroyCall(sender), super.source); } } else { @@ -3175,7 +3189,7 @@ public void postStop() { call = null; } - system.stop(self()); + getContext().stop(self()); postCleanup(); } if(asImsUa){ @@ -3242,7 +3256,7 @@ private ActorRef buildSubVoiceInterpreter(Tag child) throws MalformedURLExceptio method = "POST"; } - final SubVoiceInterpreterBuilder builder = new SubVoiceInterpreterBuilder(system); + final SubVoiceInterpreterParams.Builder builder = new SubVoiceInterpreterParams.Builder(); builder.setConfiguration(configuration); builder.setStorage(storage); builder.setCallManager(super.source); @@ -3251,7 +3265,9 @@ private ActorRef buildSubVoiceInterpreter(Tag child) throws MalformedURLExceptio builder.setVersion(version); builder.setUrl(url); builder.setMethod(method); - return builder.build(); + + final Props props = SubVoiceInterpreter.props(builder.build()); + return getContext().actorOf(props); } @Override diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreterBuilder.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreterBuilder.java deleted file mode 100644 index 8dccef29d5..0000000000 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreterBuilder.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * 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.interpreter; - -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.actor.Props; -import akka.actor.UntypedActor; -import akka.actor.UntypedActorFactory; -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.restcomm.connect.commons.dao.Sid; -import org.restcomm.connect.dao.DaoManager; - -import java.net.URI; - -/** - * @author quintana.thomas@gmail.com (Thomas Quintana) - * @author gvagenas@gmail.com (George Vagenas) - */ -public final class VoiceInterpreterBuilder { - private static Logger logger = Logger.getLogger(VoiceInterpreterBuilder.class); - private ActorSystem system; - private Configuration configuration; - private DaoManager storage; - private ActorRef calls; - private ActorRef conferences; - private ActorRef bridges; - private ActorRef sms; - private Sid account; - private Sid phone; - private String version; - private URI url; - private String method; - private URI fallbackUrl; - private String fallbackMethod; - private URI statusCallback; - private String statusCallbackMethod; - private String referTarget; - private String emailAddress; - private ActorRef monitoring; - private String rcml; - - // IMS authentication - private boolean asImsUa; - private String imsUaLogin; - private String imsUaPassword; - private String transferor; - private String transferee; - - /** - * @author thomas.quintana@telestax.com (Thomas Quintana) - */ - public VoiceInterpreterBuilder(final ActorSystem system) { - super(); - this.system = system; - } - - public ActorRef build() { - final Props props = new Props(new UntypedActorFactory() { - private static final long serialVersionUID = 1L; - - @Override - public UntypedActor create() throws Exception { - return new VoiceInterpreter(configuration, account, phone, version, url, method, fallbackUrl, fallbackMethod, - statusCallback, statusCallbackMethod, referTarget, transferor, transferee, emailAddress, calls, conferences, bridges, sms, storage, monitoring, rcml, - asImsUa, imsUaLogin, imsUaPassword); - } - }); - return system.actorOf(props); - } - - public void setConfiguration(final Configuration configuration) { - this.configuration = configuration; - } - - public void setStorage(final DaoManager storage) { - this.storage = storage; - } - - public void setCallManager(final ActorRef calls) { - this.calls = calls; - } - - public void setConferenceManager(final ActorRef conferences) { - this.conferences = conferences; - } - - public void setBridgeManager(final ActorRef bridges) { - this.bridges = bridges; - } - - public void setSmsService(final ActorRef sms) { - this.sms = sms; - } - - public void setAccount(final Sid account) { - this.account = account; - } - - public void setPhone(final Sid phone) { - this.phone = phone; - } - - public void setUrl(final URI url) { - this.url = url; - } - - public void setMethod(final String method) { - this.method = method; - } - - public void setFallbackUrl(final URI fallbackUrl) { - this.fallbackUrl = fallbackUrl; - } - - public void setFallbackMethod(final String fallbackMethod) { - this.fallbackMethod = fallbackMethod; - } - - public void setStatusCallback(final URI statusCallback) { - this.statusCallback = statusCallback; - } - - public void setStatusCallbackMethod(final String statusCallbackMethod) { - this.statusCallbackMethod = statusCallbackMethod; - } - - public void setReferTarget(final String referTarget) { - this.referTarget = referTarget; - } - - public void setEmailAddress(final String emailAddress) { - this.emailAddress = emailAddress; - } - - public void setVersion(final String version) { - this.version = version; - } - - public void setMonitoring(ActorRef monitoring) { - this.monitoring = monitoring; - } - - public void setRcml(final String rcml) { this.rcml = rcml; } - - public void setAsImsUa(boolean asImsUa) { - this.asImsUa = asImsUa; - } - - public void setImsUaLogin(String imsUaLogin) { - this.imsUaLogin = imsUaLogin; - } - - public void setImsUaPassword(String imsUaPassword) { - this.imsUaPassword = imsUaPassword; - } - - public void setTransferor (String transferor) { - this.transferor = transferor; - } - - public void setTransferee (String transferee) { - this.transferee = transferee; - } -} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreterParams.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreterParams.java new file mode 100644 index 0000000000..edf9999ae1 --- /dev/null +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreterParams.java @@ -0,0 +1,338 @@ +/* + * 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.interpreter; + +import akka.actor.ActorRef; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.DaoManager; + +import java.net.URI; + +/** + * @author oleg.agafonov@telestax.com (Oleg Agafonov) + */ +public final class VoiceInterpreterParams { + + private Configuration configuration; + private DaoManager storage; + private ActorRef callManager; + private ActorRef conferenceCenter; + private ActorRef bridgeManager; + private ActorRef smsService; + private Sid account; + private Sid phone; + private String version; + private URI url; + private String method; + private URI fallbackUrl; + private String fallbackMethod; + private URI statusCallback; + private String statusCallbackMethod; + private String referTarget; + private String emailAddress; + private ActorRef monitoring; + private String rcml; + + // IMS authentication + private boolean asImsUa; + private String imsUaLogin; + private String imsUaPassword; + private String transferor; + private String transferee; + + private VoiceInterpreterParams(Configuration configuration, DaoManager storage, ActorRef callManager, ActorRef conferences, ActorRef bridgeManager, ActorRef smsService, Sid account, Sid phone, String version, URI url, String method, URI fallbackUrl, String fallbackMethod, URI statusCallback, String statusCallbackMethod, String referTarget, String emailAddress, ActorRef monitoring, String rcml, boolean asImsUa, String imsUaLogin, String imsUaPassword, String transferor, String transferee) { + this.configuration = configuration; + this.storage = storage; + this.callManager = callManager; + this.conferenceCenter = conferences; + this.bridgeManager = bridgeManager; + this.smsService = smsService; + this.account = account; + this.phone = phone; + this.version = version; + this.url = url; + this.method = method; + this.fallbackUrl = fallbackUrl; + this.fallbackMethod = fallbackMethod; + this.statusCallback = statusCallback; + this.statusCallbackMethod = statusCallbackMethod; + this.referTarget = referTarget; + this.emailAddress = emailAddress; + this.monitoring = monitoring; + this.rcml = rcml; + this.asImsUa = asImsUa; + this.imsUaLogin = imsUaLogin; + this.imsUaPassword = imsUaPassword; + this.transferor = transferor; + this.transferee = transferee; + } + + public Configuration getConfiguration() { + return configuration; + } + + public DaoManager getStorage() { + return storage; + } + + public ActorRef getCallManager() { + return callManager; + } + + public ActorRef getConferenceCenter() { + return conferenceCenter; + } + + public ActorRef getBridgeManager() { + return bridgeManager; + } + + public ActorRef getSmsService() { + return smsService; + } + + public Sid getAccount() { + return account; + } + + public Sid getPhone() { + return phone; + } + + public String getVersion() { + return version; + } + + public URI getUrl() { + return url; + } + + public String getMethod() { + return method; + } + + public URI getFallbackUrl() { + return fallbackUrl; + } + + public String getFallbackMethod() { + return fallbackMethod; + } + + public URI getStatusCallback() { + return statusCallback; + } + + public String getStatusCallbackMethod() { + return statusCallbackMethod; + } + + public String getReferTarget() { + return referTarget; + } + + public String getEmailAddress() { + return emailAddress; + } + + public ActorRef getMonitoring() { + return monitoring; + } + + public String getRcml() { + return rcml; + } + + public boolean isAsImsUa() { + return asImsUa; + } + + public String getImsUaLogin() { + return imsUaLogin; + } + + public String getImsUaPassword() { + return imsUaPassword; + } + + public String getTransferor() { + return transferor; + } + + public String getTransferee() { + return transferee; + } + + public static final class Builder { + private Configuration configuration; + private DaoManager storage; + private ActorRef callManager; + private ActorRef conferenceCenter; + private ActorRef bridgeManager; + private ActorRef smsService; + private Sid account; + private Sid phone; + private String version; + private URI url; + private String method; + private URI fallbackUrl; + private String fallbackMethod; + private URI statusCallback; + private String statusCallbackMethod; + private String referTarget; + private String emailAddress; + private ActorRef monitoring; + private String rcml; + private boolean asImsUa; + private String imsUaLogin; + private String imsUaPassword; + private String transferor; + private String transferee; + + public Builder() { + } + + public Builder setConfiguration(Configuration configuration) { + this.configuration = configuration; + return this; + } + + public Builder setStorage(DaoManager storage) { + this.storage = storage; + return this; + } + + public Builder setCallManager(ActorRef callManager) { + this.callManager = callManager; + return this; + } + + public Builder setConferenceCenter(ActorRef conferenceCenter) { + this.conferenceCenter = conferenceCenter; + return this; + } + + public Builder setBridgeManager(ActorRef bridgeManager) { + this.bridgeManager = bridgeManager; + return this; + } + + public Builder setSmsService(ActorRef smsService) { + this.smsService = smsService; + return this; + } + + public Builder setAccount(Sid account) { + this.account = account; + return this; + } + + public Builder setPhone(Sid phone) { + this.phone = phone; + return this; + } + + public Builder setVersion(String version) { + this.version = version; + return this; + } + + public Builder setUrl(URI url) { + this.url = url; + return this; + } + + public Builder setMethod(String method) { + this.method = method; + return this; + } + + public Builder setFallbackUrl(URI fallbackUrl) { + this.fallbackUrl = fallbackUrl; + return this; + } + + public Builder setFallbackMethod(String fallbackMethod) { + this.fallbackMethod = fallbackMethod; + return this; + } + + public Builder setStatusCallback(URI statusCallback) { + this.statusCallback = statusCallback; + return this; + } + + public Builder setStatusCallbackMethod(String statusCallbackMethod) { + this.statusCallbackMethod = statusCallbackMethod; + return this; + } + + public Builder setReferTarget(String referTarget) { + this.referTarget = referTarget; + return this; + } + + public Builder setEmailAddress(String emailAddress) { + this.emailAddress = emailAddress; + return this; + } + + public Builder setMonitoring(ActorRef monitoring) { + this.monitoring = monitoring; + return this; + } + + public Builder setRcml(String rcml) { + this.rcml = rcml; + return this; + } + + public Builder setAsImsUa(boolean asImsUa) { + this.asImsUa = asImsUa; + return this; + } + + public Builder setImsUaLogin(String imsUaLogin) { + this.imsUaLogin = imsUaLogin; + return this; + } + + public Builder setImsUaPassword(String imsUaPassword) { + this.imsUaPassword = imsUaPassword; + return this; + } + + public Builder setTransferor(String transferor) { + this.transferor = transferor; + return this; + } + + public Builder setTransferee(String transferee) { + this.transferee = transferee; + return this; + } + + public VoiceInterpreterParams build() { + return new VoiceInterpreterParams(configuration, storage, callManager, conferenceCenter, bridgeManager, smsService, account, phone, version, url, method, fallbackUrl, fallbackMethod, statusCallback, statusCallbackMethod, referTarget, emailAddress, monitoring, rcml, asImsUa, imsUaLogin, imsUaPassword, transferor, transferee); + } + } +} diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/rcml/Parser.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/rcml/Parser.java index 6e2a86a0ac..a49b3a3270 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/rcml/Parser.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/rcml/Parser.java @@ -20,9 +20,12 @@ package org.restcomm.connect.interpreter.rcml; import akka.actor.ActorRef; -import akka.actor.UntypedActor; import org.apache.log4j.Logger; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -32,15 +35,12 @@ import java.util.List; import java.util.Stack; -import javax.xml.stream.XMLInputFactory; import static javax.xml.stream.XMLStreamConstants.*; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ -public final class Parser extends UntypedActor { +public final class Parser extends RestcommUntypedActor { private static Logger logger = Logger.getLogger(Parser.class); private Tag document; private Iterator iterator; diff --git a/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/rcml/GatherSpeechTest.java b/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java similarity index 94% rename from restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/rcml/GatherSpeechTest.java rename to restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java index a3bb8442db..f23d7ceec9 100644 --- a/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/rcml/GatherSpeechTest.java +++ b/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java @@ -18,7 +18,7 @@ * */ -package org.restcomm.connect.interpreter.rcml; +package org.restcomm.connect.interpreter; import akka.actor.Actor; import akka.actor.ActorRef; @@ -51,8 +51,7 @@ import org.restcomm.connect.http.client.DownloaderResponse; import org.restcomm.connect.http.client.HttpRequestDescriptor; import org.restcomm.connect.http.client.HttpResponseDescriptor; -import org.restcomm.connect.interpreter.StartInterpreter; -import org.restcomm.connect.interpreter.VoiceInterpreter; +import org.restcomm.connect.interpreter.rcml.MockedActor; import org.restcomm.connect.interpreter.rcml.domain.GatherAttributes; import org.restcomm.connect.mscontrol.api.messages.Collect; import org.restcomm.connect.mscontrol.api.messages.MediaGroupResponse; @@ -156,31 +155,22 @@ private ActorRef createVoiceInterpreter(final ActorRef observer) { final ActorRef callManager = new MockedActor("callManager").asRef(system); + final VoiceInterpreterParams.Builder builder = new VoiceInterpreterParams.Builder(); + builder.setConfiguration(configuration); + builder.setStorage(storage); + builder.setCallManager(callManager); + builder.setAccount(new Sid("ACae6e420f425248d6a26948c17a9e2acf")); + builder.setVersion("2012-04-24"); + builder.setUrl(requestUri); + builder.setMethod("GET"); + builder.setAsImsUa(false); + final Props props = new Props(new UntypedActorFactory() { private static final long serialVersionUID = 1L; @Override public Actor create() throws Exception { - return new VoiceInterpreter(configuration, - new Sid("ACae6e420f425248d6a26948c17a9e2acf"), - null, - "2012-04-24", - requestUri, "GET", - null, null, - null, - null, - null, - null, - null, - null, - callManager, - null, - null, - null, - storage, - null, - null, - false, null, null) { + return new VoiceInterpreter(builder.build()) { @Override protected ActorRef downloader() { return observer; diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/Connection.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/Connection.java index cee9591993..4cfed505a3 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/Connection.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/Connection.java @@ -19,23 +19,8 @@ */ package org.restcomm.connect.mgcp; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import org.restcomm.connect.commons.fsm.Action; -import org.restcomm.connect.commons.fsm.FiniteStateMachine; -import org.restcomm.connect.commons.fsm.State; -import org.restcomm.connect.commons.fsm.Transition; -import org.restcomm.connect.commons.patterns.Observe; -import org.restcomm.connect.commons.patterns.Observing; -import org.restcomm.connect.commons.patterns.StopObserving; - import akka.actor.ActorRef; import akka.actor.ReceiveTimeout; -import akka.actor.UntypedActor; import akka.actor.UntypedActorContext; import akka.event.Logging; import akka.event.LoggingAdapter; @@ -54,12 +39,26 @@ import jain.protocol.ip.mgcp.message.parms.LocalOptionValue; import jain.protocol.ip.mgcp.message.parms.NotifiedEntity; import jain.protocol.ip.mgcp.message.parms.ReturnCode; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; +import org.restcomm.connect.commons.fsm.Action; +import org.restcomm.connect.commons.fsm.FiniteStateMachine; +import org.restcomm.connect.commons.fsm.State; +import org.restcomm.connect.commons.fsm.Transition; +import org.restcomm.connect.commons.patterns.Observe; +import org.restcomm.connect.commons.patterns.Observing; +import org.restcomm.connect.commons.patterns.StopObserving; import scala.concurrent.duration.Duration; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ -public final class Connection extends UntypedActor { +public final class Connection extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); // Finite state machine stuff. private final State uninitialized; diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/GenericEndpoint.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/GenericEndpoint.java index 066c68564b..5efbc24668 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/GenericEndpoint.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/GenericEndpoint.java @@ -19,33 +19,31 @@ */ package org.restcomm.connect.mgcp; +import akka.actor.ActorRef; +import akka.actor.ReceiveTimeout; +import akka.event.Logging; +import akka.event.LoggingAdapter; import jain.protocol.ip.mgcp.JainMgcpResponseEvent; import jain.protocol.ip.mgcp.message.DeleteConnection; import jain.protocol.ip.mgcp.message.parms.EndpointIdentifier; import jain.protocol.ip.mgcp.message.parms.NotifiedEntity; import jain.protocol.ip.mgcp.message.parms.ReturnCode; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; +import org.restcomm.connect.commons.patterns.Observe; +import org.restcomm.connect.commons.patterns.Observing; +import org.restcomm.connect.commons.patterns.StopObserving; +import scala.concurrent.duration.Duration; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import org.restcomm.connect.commons.patterns.Observe; -import org.restcomm.connect.commons.patterns.Observing; -import org.restcomm.connect.commons.patterns.StopObserving; - -import scala.concurrent.duration.Duration; -import akka.actor.ActorRef; -import akka.actor.ReceiveTimeout; -import akka.actor.UntypedActor; -import akka.event.Logging; -import akka.event.LoggingAdapter; - /** * @author quintana.thomas@gmail.com (Thomas Quintana) * @author maria.farooq@telestax.com (Maria Farooq) */ -public abstract class GenericEndpoint extends UntypedActor { +public abstract class GenericEndpoint extends RestcommUntypedActor { protected final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java index 3fc8e8f9d0..595b216571 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java @@ -36,14 +36,15 @@ import jain.protocol.ip.mgcp.pkg.MgcpEvent; import jain.protocol.ip.mgcp.pkg.PackageName; import org.apache.commons.codec.DecoderException; +import org.apache.commons.codec.binary.Hex; import org.apache.commons.lang.StringUtils; import org.mobicents.protocols.mgcp.jain.pkg.AUMgcpEvent; import org.mobicents.protocols.mgcp.jain.pkg.AUPackage; import org.restcomm.connect.commons.dao.CollectedResult; import org.restcomm.connect.commons.patterns.Observe; import org.restcomm.connect.commons.patterns.StopObserving; -import org.apache.commons.codec.binary.Hex; +import java.util.HashMap; import java.util.Map; import static jain.protocol.ip.mgcp.message.parms.ReturnCode.Transaction_Executed_Normally; @@ -55,13 +56,11 @@ public final class IvrEndpoint extends GenericEndpoint { private static final PackageName PACKAGE_NAME = AUPackage.AU; private static final RequestedEvent[] REQUESTED_EVENTS = new RequestedEvent[2]; - static { - final RequestedAction[] action = new RequestedAction[]{RequestedAction.NotifyImmediately}; + final RequestedAction[] action = new RequestedAction[] { RequestedAction.NotifyImmediately }; REQUESTED_EVENTS[0] = new RequestedEvent(new EventName(PACKAGE_NAME, AUMgcpEvent.auoc), action); REQUESTED_EVENTS[1] = new RequestedEvent(new EventName(PACKAGE_NAME, AUMgcpEvent.auof), action); } - private static final String EMPTY_STRING = new String(); private static final String DEFAULT_REQUEST_ID = "0"; @@ -69,7 +68,7 @@ public final class IvrEndpoint extends GenericEndpoint { protected static String ivrEndpointName = "mobicents/ivr/$"; public IvrEndpoint(final ActorRef gateway, final MediaSession session, final NotifiedEntity agent, final String domain, long timeout, String endpointName) { - super(gateway, session, agent, new EndpointIdentifier(endpointName == null ? ivrEndpointName : endpointName, domain), timeout); + super(gateway, session, agent, new EndpointIdentifier(endpointName==null?ivrEndpointName:endpointName, domain), timeout); this.agent = agent; } @@ -236,4 +235,17 @@ private void notification(final Object message) { } } + private Map parse(final String input) { + final Map parameters = new HashMap(); + final String[] tokens = input.split(" "); + for (final String token : tokens) { + final String[] values = token.split("="); + if (values.length == 1) { + parameters.put(values[0], null); + } else if (values.length == 2) { + parameters.put(values[0], values[1]); + } + } + return parameters; + } } diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/Link.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/Link.java index bd6e01d1da..052fac01f2 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/Link.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/Link.java @@ -19,23 +19,8 @@ */ package org.restcomm.connect.mgcp; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import org.restcomm.connect.commons.fsm.Action; -import org.restcomm.connect.commons.fsm.FiniteStateMachine; -import org.restcomm.connect.commons.fsm.State; -import org.restcomm.connect.commons.fsm.Transition; -import org.restcomm.connect.commons.patterns.Observe; -import org.restcomm.connect.commons.patterns.Observing; -import org.restcomm.connect.commons.patterns.StopObserving; - import akka.actor.ActorRef; import akka.actor.ReceiveTimeout; -import akka.actor.UntypedActor; import akka.actor.UntypedActorContext; import akka.event.Logging; import akka.event.LoggingAdapter; @@ -50,12 +35,26 @@ import jain.protocol.ip.mgcp.message.parms.EndpointIdentifier; import jain.protocol.ip.mgcp.message.parms.NotifiedEntity; import jain.protocol.ip.mgcp.message.parms.ReturnCode; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; +import org.restcomm.connect.commons.fsm.Action; +import org.restcomm.connect.commons.fsm.FiniteStateMachine; +import org.restcomm.connect.commons.fsm.State; +import org.restcomm.connect.commons.fsm.Transition; +import org.restcomm.connect.commons.patterns.Observe; +import org.restcomm.connect.commons.patterns.Observing; +import org.restcomm.connect.commons.patterns.StopObserving; import scala.concurrent.duration.Duration; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ -public final class Link extends UntypedActor { +public final class Link extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); // Finite state machine stuff. private final State uninitialized; diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MediaGateway.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MediaGateway.java index 29074e45c2..2acd13bce5 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MediaGateway.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MediaGateway.java @@ -20,7 +20,6 @@ package org.restcomm.connect.mgcp; import akka.actor.Actor; import akka.actor.ActorRef; -import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.UntypedActor; import akka.actor.UntypedActorContext; @@ -40,6 +39,7 @@ import jain.protocol.ip.mgcp.message.parms.ConnectionIdentifier; import jain.protocol.ip.mgcp.message.parms.EventName; import jain.protocol.ip.mgcp.message.parms.NotifiedEntity; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.util.RevolvingCounter; import java.net.InetAddress; @@ -50,7 +50,7 @@ /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ -public final class MediaGateway extends UntypedActor implements JainMgcpListener { +public final class MediaGateway extends RestcommUntypedActor implements JainMgcpListener { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); // MediaGateway connection information. private String name; @@ -77,13 +77,11 @@ public final class MediaGateway extends UntypedActor implements JainMgcpListener private RevolvingCounter requestIdPool; private RevolvingCounter sessionIdPool; private RevolvingCounter transactionIdPool; - private ActorSystem system; public MediaGateway() { super(); notificationListeners = new ConcurrentHashMap(); responseListeners = new ConcurrentHashMap(); - system = context().system(); } private ActorRef getConnection(final Object message) { @@ -99,7 +97,7 @@ public UntypedActor create() throws Exception { return new Connection(gateway, session, agent, timeout); } }); - return system.actorOf(props); + return getContext().actorOf(props); } private ActorRef getBridgeEndpoint(final Object message) { @@ -127,7 +125,7 @@ public Actor create() throws Exception { } }); } - return system.actorOf(props); + return getContext().actorOf(props); } private ActorRef getConferenceEndpoint(final Object message) { @@ -143,7 +141,7 @@ public UntypedActor create() throws Exception { return new ConferenceEndpoint(gateway, session, agent, domain, timeout, endpointName); } }); - return system.actorOf(props); + return getContext().actorOf(props); } private MediaGatewayInfo getInfo(final Object message) { @@ -163,7 +161,7 @@ public UntypedActor create() throws Exception { return new IvrEndpoint(gateway, session, agent, domain, timeout, endpointName); } }); - return system.actorOf(props); + return getContext().actorOf(props); } private ActorRef getLink(final Object message) { @@ -179,7 +177,7 @@ public UntypedActor create() throws Exception { return new Link(gateway, session, agent, timeout, connectionIdentifier); } }); - return system.actorOf(props); + return getContext().actorOf(props); } private ActorRef getPacketRelayEndpoint(final Object message) { @@ -194,7 +192,7 @@ public UntypedActor create() throws Exception { return new PacketRelayEndpoint(gateway, session, agent, domain, timeout); } }); - return system.actorOf(props); + return getContext().actorOf(props); } private MediaSession getSession() { diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MockConnection.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MockConnection.java index 76c6fd3ffc..4430bfc9cb 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MockConnection.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MockConnection.java @@ -21,7 +21,6 @@ import akka.actor.ActorRef; import akka.actor.ReceiveTimeout; -import akka.actor.UntypedActor; import akka.actor.UntypedActorContext; import akka.event.Logging; import akka.event.LoggingAdapter; @@ -40,6 +39,7 @@ import jain.protocol.ip.mgcp.message.parms.LocalOptionValue; import jain.protocol.ip.mgcp.message.parms.NotifiedEntity; import jain.protocol.ip.mgcp.message.parms.ReturnCode; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.fsm.Action; import org.restcomm.connect.commons.fsm.FiniteStateMachine; import org.restcomm.connect.commons.fsm.State; @@ -58,7 +58,7 @@ /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ -public final class MockConnection extends UntypedActor { +public final class MockConnection extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); // Finite state machine stuff. private final State uninitialized; diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MockMediaGateway.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MockMediaGateway.java index 1c3ab818c1..f6b3985261 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MockMediaGateway.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/MockMediaGateway.java @@ -47,6 +47,7 @@ import jain.protocol.ip.mgcp.pkg.MgcpEvent; import org.mobicents.protocols.mgcp.jain.pkg.AUMgcpEvent; import org.mobicents.protocols.mgcp.jain.pkg.AUPackage; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.util.RevolvingCounter; import javax.sdp.SdpFactory; @@ -59,7 +60,7 @@ /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ -public class MockMediaGateway extends UntypedActor { +public class MockMediaGateway extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); // Session description for the mock media gateway. private static final String sdp = "v=0\n" + "o=- 1362546170756 1 IN IP4 192.168.1.100\n" + "s=Mobicents Media Server\n" diff --git a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AbstractMockMediaGateway.java b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AbstractMockMediaGateway.java index 80197046a6..8f9eccfa1f 100644 --- a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AbstractMockMediaGateway.java +++ b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AbstractMockMediaGateway.java @@ -24,19 +24,18 @@ import akka.actor.Props; import akka.actor.UntypedActor; import akka.actor.UntypedActorFactory; - import jain.protocol.ip.mgcp.JainMgcpCommandEvent; import jain.protocol.ip.mgcp.JainMgcpResponseEvent; import jain.protocol.ip.mgcp.message.NotificationRequest; import jain.protocol.ip.mgcp.message.parms.NotifiedEntity; - +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.util.RevolvingCounter; /** * @author thomas.quintana@telestax.com (Thomas Quintana) * @author maria.farooq@telestax.com (Maria Farooq) */ -public abstract class AbstractMockMediaGateway extends UntypedActor { +public abstract class AbstractMockMediaGateway extends RestcommUntypedActor { // Call agent. protected NotifiedEntity agent; // Media gateway domain name. diff --git a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/EndpointTest.java b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/EndpointTest.java index e09afe0580..2707b87391 100644 --- a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/EndpointTest.java +++ b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/EndpointTest.java @@ -19,17 +19,6 @@ */ package org.restcomm.connect.mgcp; -import static org.junit.Assert.assertTrue; - -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mobicents.protocols.mgcp.jain.pkg.AUMgcpEvent; -import org.mobicents.protocols.mgcp.jain.pkg.AUPackage; -import org.restcomm.connect.commons.patterns.Observe; -import org.restcomm.connect.commons.patterns.Observing; -import org.restcomm.connect.commons.patterns.StopObserving; - import akka.actor.ActorRef; import akka.actor.ActorSystem; import akka.actor.Props; @@ -44,6 +33,16 @@ import jain.protocol.ip.mgcp.message.parms.EventName; import jain.protocol.ip.mgcp.message.parms.ReturnCode; import jain.protocol.ip.mgcp.pkg.MgcpEvent; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mobicents.protocols.mgcp.jain.pkg.AUMgcpEvent; +import org.mobicents.protocols.mgcp.jain.pkg.AUPackage; +import org.restcomm.connect.commons.patterns.Observe; +import org.restcomm.connect.commons.patterns.Observing; +import org.restcomm.connect.commons.patterns.StopObserving; + +import static org.junit.Assert.assertTrue; /** * @author maria.farooq@telestax.com (Maria Farooq) diff --git a/restcomm/restcomm.monitoring.service/src/main/java/org/restcomm/connect/monitoringservice/MonitoringService.java b/restcomm/restcomm.monitoring.service/src/main/java/org/restcomm/connect/monitoringservice/MonitoringService.java index 9f7a672829..7f84bcc6ae 100644 --- a/restcomm/restcomm.monitoring.service/src/main/java/org/restcomm/connect/monitoringservice/MonitoringService.java +++ b/restcomm/restcomm.monitoring.service/src/main/java/org/restcomm/connect/monitoringservice/MonitoringService.java @@ -21,10 +21,10 @@ package org.restcomm.connect.monitoringservice; import akka.actor.ActorRef; -import akka.actor.UntypedActor; import akka.event.Logging; import akka.event.LoggingAdapter; import org.restcomm.connect.commons.configuration.RestcommConfiguration; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.patterns.Observing; import org.restcomm.connect.commons.patterns.StopObserving; import org.restcomm.connect.dao.DaoManager; @@ -55,7 +55,7 @@ /** * @author gvagenas */ -public class MonitoringService extends UntypedActor{ +public class MonitoringService extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); private DaoManager daoManager; @@ -124,7 +124,7 @@ public void onReceive(Object message) throws Exception { final ActorRef self = self(); final ActorRef sender = sender(); if(logger.isInfoEnabled()){ - logger.info("MonitoringService Processing Message: \"" + klass.getName() + " sender : "+ sender.getClass()+" self is terminated: "+self.isTerminated()); + logger.info("MonitoringService, path: \""+self.path()+"\" Processing Message: \"" + klass.getName() + "\" sender : "+ sender.getClass()+"\" self is terminated: "+self.isTerminated()+"\""); } if (InstanceId.class.equals(klass)) { @@ -171,14 +171,14 @@ private void onGetCall(Object message, ActorRef self, ActorRef sender) throws Se // required in case the Contact Header of the INVITE doesn't contain any user part // as it is the case for Restcomm SDKs if (logger.isDebugEnabled()) { - logger.debug("onGetCall Another try on removing the user part from " + location); + logger.debug("MonitoringService onGetCall Another try on removing the user part from " + location); } int indexOfAt = location.indexOf("@"); int indexOfColumn = location.indexOf(":"); String newLocation = location.substring(0, indexOfColumn+1).concat(location.substring(indexOfAt+1)); call = callLocationMap.get(newLocation); if (logger.isDebugEnabled()) { - logger.debug("onGetCall call " + call + " found for new Location " + newLocation); + logger.debug("MonitoringService onGetCall call " + call + " found for new Location " + newLocation); } } if (call != null) { @@ -230,19 +230,19 @@ private void onUserRegistration(UserRegistration userRegistration, ActorRef self registeredUsers.put(userRegistration.getUser(), userRegistration.getAddress()); } catch (Exception e) { if (logger.isDebugEnabled()) { - logger.debug("There was an issue during the process of UserRegistration message, "+e); + logger.debug("MonitoringService There was an issue during the process of UserRegistration message, "+e); } } } else { if (registeredUsers.containsKey(userRegistration.getUser())) { registeredUsers.remove(userRegistration.getUser()); if (logger.isDebugEnabled()) { - String msg = String.format("User %s removed from registered users", userRegistration.getUser()); + String msg = String.format("MonitoringService User %s removed from registered users", userRegistration.getUser()); logger.debug(msg); } } else { if (logger.isDebugEnabled()) { - String msg = String.format("User %s was not removed because is not in the registered users", userRegistration.getUser()); + String msg = String.format("MonitoringService User %s was not removed because is not in the registered users", userRegistration.getUser()); logger.debug(msg); } } @@ -275,12 +275,14 @@ private void onStopObserving(StopObserving message, ActorRef self, ActorRef send } if (callInfo.direction().equalsIgnoreCase("inbound")) { if (logger.isDebugEnabled()) { - logger.debug("Removed inbound call from: "+callInfo.from()+" to: "+callInfo.to()); + String msg = String.format("MonitoringService Removed inbound call from: %s to: %s, currently liveCalls: %d", callInfo.from(), callInfo.to(),callDetailsMap.size()); + logger.debug(msg); } incomingCallDetailsMap.remove(senderPath); } else { if (logger.isDebugEnabled()) { - logger.debug("Removed outbound call from: "+callInfo.from()+" to: "+callInfo.to()); + String msg = String.format("MonitoringService Removed outbound call from: %s to: %s, currently liveCallS: %d ", callInfo.from(), callInfo.to(),callDetailsMap.size()); + logger.debug(msg); } outgoingCallDetailsMap.remove(senderPath); } @@ -301,13 +303,13 @@ private void onCallResponse(CallResponse message, ActorRef self, Actor } if (callInfo.direction().equalsIgnoreCase("inbound")) { if (logger.isDebugEnabled()) { - logger.debug("New inbound call from: "+callInfo.from()+" to: "+callInfo.to()); + logger.debug("MonitoringService New inbound call from: "+callInfo.from()+" to: "+callInfo.to()); } incomingCallDetailsMap.put(senderPath, callInfo); incomingCallsUpToNow.incrementAndGet(); } else { if (logger.isDebugEnabled()) { - logger.debug("New outbound call from: "+callInfo.from()+" to: "+callInfo.to()); + logger.debug("MonitoringService New outbound call from: "+callInfo.from()+" to: "+callInfo.to()); } outgoingCallDetailsMap.put(senderPath, callInfo); outgoingCallsUpToNow.incrementAndGet(); @@ -351,7 +353,7 @@ private void onCallStateChanged(CallStateChanged message, ActorRef self, ActorRe notFoundCalls.incrementAndGet(); } } else if(logger.isInfoEnabled()){ - logger.info("CallInfo was not in the store for Call: "+senderPath); + logger.info("MonitoringService CallInfo was not in the store for Call: "+senderPath); } } else { logger.error("MonitoringService, SenderPath or storage is null."); @@ -389,7 +391,7 @@ private void onGetStatistics (GetStatistics message, ActorRef self, ActorRef sen averageCallDurationLastHour = daoManager.getCallDetailRecordsDao().getAverageCallDurationLastHour(instanceId.getId()); } catch (Exception e) { if (logger.isDebugEnabled()) { - logger.debug("Exception during the query for AVG Call Duration: "+e.getStackTrace()); + logger.debug("MonitoringService Exception during the query for AVG Call Duration: "+e.getStackTrace()); } } @@ -434,7 +436,7 @@ private void onGetStatistics (GetStatistics message, ActorRef self, ActorRef sen try { callDetailsUri = new URI(String.format("/restcomm/%s/Accounts/%s/Supervisor.json/livecalls", RestcommConfiguration.getInstance().getMain().getApiVersion(), message.getAccountSid())); } catch (URISyntaxException e) { - logger.error("Problem while trying to create the LiveCalls detail URI"); + logger.error("MonitoringService Problem while trying to create the LiveCalls detail URI"); } callInfoList = new MonitoringServiceResponse(instanceId, null, countersMap, durationMap, false, callDetailsUri); } diff --git a/restcomm/restcomm.mrb/src/main/java/org/restcomm/connect/mrb/ConferenceMediaResourceControllerGeneric.java b/restcomm/restcomm.mrb/src/main/java/org/restcomm/connect/mrb/ConferenceMediaResourceControllerGeneric.java index 7765ce469f..90544b0424 100644 --- a/restcomm/restcomm.mrb/src/main/java/org/restcomm/connect/mrb/ConferenceMediaResourceControllerGeneric.java +++ b/restcomm/restcomm.mrb/src/main/java/org/restcomm/connect/mrb/ConferenceMediaResourceControllerGeneric.java @@ -21,7 +21,6 @@ package org.restcomm.connect.mrb; import akka.actor.ActorRef; -import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.UntypedActor; import akka.actor.UntypedActorFactory; @@ -30,6 +29,7 @@ import org.apache.commons.configuration.Configuration; import org.joda.time.DateTime; import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.fsm.Action; import org.restcomm.connect.commons.fsm.FiniteStateMachine; import org.restcomm.connect.commons.fsm.State; @@ -66,7 +66,7 @@ /** * @author maria.farooq@telestax.com (Maria Farooq) */ -public class ConferenceMediaResourceControllerGeneric extends UntypedActor{ +public class ConferenceMediaResourceControllerGeneric extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); @@ -101,12 +101,10 @@ public class ConferenceMediaResourceControllerGeneric extends UntypedActor{ // Observer pattern protected final List observers; protected ActorRef mrb; - protected ActorSystem system; public ConferenceMediaResourceControllerGeneric(ActorRef localMediaGateway, final Configuration configuration, final DaoManager storage, final ActorRef mrb){ super(); final ActorRef source = self(); - this.system = context().system(); // Initialize the states for the FSM. this.uninitialized = new State("uninitialized", null, null); this.creatingMediaGroup = new State("creating media group", new CreatingMediaGroup(source), null); @@ -382,7 +380,7 @@ public UntypedActor create() throws Exception { return new MgcpMediaGroup(localMediaGateway, localMediaSession, localConfernceEndpoint); } }); - return system.actorOf(props); + return getContext().actorOf(props); } @Override diff --git a/restcomm/restcomm.mrb/src/main/java/org/restcomm/connect/mrb/MediaResourceBrokerGeneric.java b/restcomm/restcomm.mrb/src/main/java/org/restcomm/connect/mrb/MediaResourceBrokerGeneric.java index 15b5144255..b89065c683 100644 --- a/restcomm/restcomm.mrb/src/main/java/org/restcomm/connect/mrb/MediaResourceBrokerGeneric.java +++ b/restcomm/restcomm.mrb/src/main/java/org/restcomm/connect/mrb/MediaResourceBrokerGeneric.java @@ -20,17 +20,20 @@ */ package org.restcomm.connect.mrb; -import java.net.InetAddress; -import java.net.URI; -import java.net.UnknownHostException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - +import akka.actor.ActorRef; +import akka.actor.Props; +import akka.actor.UntypedActor; +import akka.actor.UntypedActorFactory; +import akka.event.Logging; +import akka.event.LoggingAdapter; +import jain.protocol.ip.mgcp.CreateProviderException; +import jain.protocol.ip.mgcp.JainMgcpProvider; +import jain.protocol.ip.mgcp.JainMgcpStack; import org.apache.commons.configuration.Configuration; import org.joda.time.DateTime; import org.mobicents.protocols.mgcp.stack.JainMgcpStackImpl; import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.loader.ObjectFactory; import org.restcomm.connect.dao.CallDetailRecordsDao; import org.restcomm.connect.dao.ConferenceDetailRecordsDao; @@ -48,20 +51,17 @@ import org.restcomm.connect.mrb.api.StartMediaResourceBroker; import org.restcomm.connect.telephony.api.ConferenceStateChanged; -import akka.actor.ActorRef; -import akka.actor.Props; -import akka.actor.UntypedActor; -import akka.actor.UntypedActorFactory; -import akka.event.Logging; -import akka.event.LoggingAdapter; -import jain.protocol.ip.mgcp.CreateProviderException; -import jain.protocol.ip.mgcp.JainMgcpProvider; -import jain.protocol.ip.mgcp.JainMgcpStack; +import java.net.InetAddress; +import java.net.URI; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * @author maria.farooq@telestax.com (Maria Farooq) */ -public class MediaResourceBrokerGeneric extends UntypedActor{ +public class MediaResourceBrokerGeneric extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); @@ -144,7 +144,7 @@ public UntypedActor create() throws Exception { return (UntypedActor) new ObjectFactory(loader).getObjectInstance(classpath); } }); - return context().system().actorOf(props); + return getContext().actorOf(props); } /** @@ -201,7 +201,7 @@ public UntypedActor create() throws Exception { return new ConferenceMediaResourceControllerGeneric(localMediaGateway, configuration, storage, self()); } }); - return context().system().actorOf(props); + return getContext().actorOf(props); } /** diff --git a/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/MediaGroup.java b/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/MediaGroup.java index 9c43235262..484faadc5f 100644 --- a/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/MediaGroup.java +++ b/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/MediaGroup.java @@ -19,11 +19,11 @@ */ package org.restcomm.connect.mscontrol.api; -import akka.actor.UntypedActor; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ -public abstract class MediaGroup extends UntypedActor { +public abstract class MediaGroup extends RestcommUntypedActor { } diff --git a/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/MediaServerController.java b/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/MediaServerController.java index 03fbc029fb..527aacb6e0 100644 --- a/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/MediaServerController.java +++ b/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/MediaServerController.java @@ -19,17 +19,16 @@ */ package org.restcomm.connect.mscontrol.api; -import org.restcomm.connect.commons.fsm.Action; - import akka.actor.ActorRef; -import akka.actor.UntypedActor; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; +import org.restcomm.connect.commons.fsm.Action; /** * Controls the flow of media sessions. * * @author Henrique Rosa (henrique.rosa@telestax.com) */ -public abstract class MediaServerController extends UntypedActor { +public abstract class MediaServerController extends RestcommUntypedActor { protected MediaServerController() { super(); diff --git a/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/MediaServerControllerFactory.java b/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/MediaServerControllerFactory.java index 846ea1101d..aaa74d9c8d 100644 --- a/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/MediaServerControllerFactory.java +++ b/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/MediaServerControllerFactory.java @@ -21,7 +21,7 @@ package org.restcomm.connect.mscontrol.api; -import akka.actor.ActorRef; +import akka.actor.Props; /** * @author Henrique Rosa (henrique.rosa@telestax.com) @@ -30,24 +30,24 @@ public interface MediaServerControllerFactory { /** - * Provides a new Media Server Controller for a Call. + * Provides a new Media Server Controller Props for a Call. * - * @return The media server controller + * @return The media server controller props */ - ActorRef provideCallController(); + Props provideCallControllerProps(); /** - * Provides a new Media Server Controller for a Conference. + * Provides a new Media Server Controller Props for a Conference. * - * @return The media server controller + * @return The media server controller props */ - ActorRef provideConferenceController(); + Props provideConferenceControllerProps(); /** - * Provides a new Media Server Controller for a Bridge. + * Provides a new Media Server Controller Props for a Bridge. * - * @return The media server controller + * @return The media server controller props */ - ActorRef provideBridgeController(); + Props provideBridgeControllerProps(); } diff --git a/restcomm/restcomm.mscontrol.jsr309/src/main/java/org/restcomm/connect/mscontrol/jsr309/Jsr309ControllerFactory.java b/restcomm/restcomm.mscontrol.jsr309/src/main/java/org/restcomm/connect/mscontrol/jsr309/Jsr309ControllerFactory.java index 3b4ba29bd6..2bc37af188 100644 --- a/restcomm/restcomm.mscontrol.jsr309/src/main/java/org/restcomm/connect/mscontrol/jsr309/Jsr309ControllerFactory.java +++ b/restcomm/restcomm.mscontrol.jsr309/src/main/java/org/restcomm/connect/mscontrol/jsr309/Jsr309ControllerFactory.java @@ -22,8 +22,6 @@ package org.restcomm.connect.mscontrol.jsr309; import akka.actor.Actor; -import akka.actor.ActorRef; -import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.UntypedActorFactory; import org.apache.log4j.Logger; @@ -39,8 +37,6 @@ public class Jsr309ControllerFactory implements MediaServerControllerFactory { private static Logger logger = Logger.getLogger(Jsr309ControllerFactory.class); - // Actor supervisor - private final ActorSystem system; // JSR-309 private final MsControlFactory msControlFactory; @@ -53,10 +49,7 @@ public class Jsr309ControllerFactory implements MediaServerControllerFactory { // Media Server Info private final MediaServerInfo mediaServerInfo; - public Jsr309ControllerFactory(ActorSystem system, MediaServerInfo mediaServerInfo, MsControlFactory msControlFactory) { - // Actor supervisor - this.system = system; - + public Jsr309ControllerFactory(MediaServerInfo mediaServerInfo, MsControlFactory msControlFactory) { // Factories this.msControlFactory = msControlFactory; this.callControllerFactory = new CallControllerFactory(); @@ -68,21 +61,18 @@ public Jsr309ControllerFactory(ActorSystem system, MediaServerInfo mediaServerIn } @Override - public ActorRef provideCallController() { - final Props props = new Props(this.callControllerFactory); - return system.actorOf(props); + public Props provideCallControllerProps() { + return new Props(this.callControllerFactory); } @Override - public ActorRef provideConferenceController() { - final Props props = new Props(this.conferenceControllerFactory); - return system.actorOf(props); + public Props provideConferenceControllerProps() { + return new Props(this.conferenceControllerFactory); } @Override - public ActorRef provideBridgeController() { - final Props props = new Props(this.bridgeControllerFactory); - return system.actorOf(props); + public Props provideBridgeControllerProps() { + return new Props(this.bridgeControllerFactory); } private final class CallControllerFactory implements UntypedActorFactory { diff --git a/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MmsBridgeController.java b/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MmsBridgeController.java index c1bdba0fa2..e5aef04d07 100644 --- a/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MmsBridgeController.java +++ b/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MmsBridgeController.java @@ -22,7 +22,6 @@ package org.restcomm.connect.mscontrol.mms; import akka.actor.ActorRef; -import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.UntypedActor; import akka.actor.UntypedActorFactory; @@ -82,7 +81,6 @@ public class MmsBridgeController extends MediaServerController { // Logging private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); - private final ActorSystem system; // Finite State Machine private final FiniteStateMachine fsm; private final State uninitialized; @@ -116,9 +114,8 @@ public class MmsBridgeController extends MediaServerController { private Sid callSid; - public MmsBridgeController(final ActorRef mrb, final ActorSystem system) { + public MmsBridgeController(final ActorRef mrb) { final ActorRef self = self(); - this.system = system; // Finite states this.uninitialized = new State("uninitialized", null, null); @@ -445,7 +442,7 @@ public UntypedActor create() throws Exception { return new MgcpMediaGroup(mediaGateway, mediaSession, endpoint); } }); - return system.actorOf(props); + return getContext().actorOf(props); } @Override diff --git a/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MmsCallController.java b/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MmsCallController.java index 153ac3d674..0bb3f6d959 100644 --- a/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MmsCallController.java +++ b/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MmsCallController.java @@ -22,7 +22,6 @@ package org.restcomm.connect.mscontrol.mms; import akka.actor.ActorRef; -import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.UntypedActor; import akka.actor.UntypedActorFactory; @@ -154,7 +153,6 @@ public class MmsCallController extends MediaServerController { // TODO rename following variable to 'mediaGateway' private ActorRef mediaGateway; private final ActorRef mrb; - private final ActorSystem system; private MediaGatewayInfo gatewayInfo; private MediaSession session; private ActorRef bridgeEndpoint; @@ -181,10 +179,9 @@ public class MmsCallController extends MediaServerController { private ConnectionIdentifier connectionIdentifier; //public MmsCallController(final List mediaGateways, final Configuration configuration) { - public MmsCallController(final ActorRef mrb, final ActorSystem system) { + public MmsCallController(final ActorRef mrb) { super(); final ActorRef source = self(); - this.system = system; // Initialize the states for the FSM. this.uninitialized = new State("uninitialized", null, null); @@ -315,7 +312,7 @@ public UntypedActor create() throws Exception { return new MgcpMediaGroup(mediaGateway, session, bridgeEndpoint); } }); - return system.actorOf(props); + return getContext().actorOf(props); } private void startRecordingCall() throws Exception { diff --git a/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MmsConferenceController.java b/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MmsConferenceController.java index ec7a10c741..a4199027ce 100644 --- a/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MmsConferenceController.java +++ b/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MmsConferenceController.java @@ -21,11 +21,10 @@ package org.restcomm.connect.mscontrol.mms; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - +import akka.actor.ActorRef; +import akka.event.Logging; +import akka.event.LoggingAdapter; +import jain.protocol.ip.mgcp.message.parms.ConnectionMode; import org.mobicents.servlet.restcomm.mscontrol.messages.MediaServerConferenceControllerStateChanged; import org.restcomm.connect.commons.annotations.concurrency.Immutable; import org.restcomm.connect.commons.dao.Sid; @@ -62,10 +61,10 @@ import org.restcomm.connect.mscontrol.api.messages.StopMediaGroup; import org.restcomm.connect.mscontrol.api.messages.StopRecording; -import akka.actor.ActorRef; -import akka.event.Logging; -import akka.event.LoggingAdapter; -import jain.protocol.ip.mgcp.message.parms.ConnectionMode; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; /** * @author Henrique Rosa (henrique.rosa@telestax.com) diff --git a/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MmsControllerFactory.java b/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MmsControllerFactory.java index f599a48f90..4f160a8293 100644 --- a/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MmsControllerFactory.java +++ b/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MmsControllerFactory.java @@ -23,7 +23,6 @@ import akka.actor.Actor; import akka.actor.ActorRef; -import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.UntypedActorFactory; import org.apache.log4j.Logger; @@ -38,15 +37,13 @@ public class MmsControllerFactory implements MediaServerControllerFactory { private static Logger logger = Logger.getLogger(MmsControllerFactory.class); - private final ActorSystem system; private final CallControllerFactory callControllerFactory; private final ConferenceControllerFactory conferenceControllerFactory; private final BridgeControllerFactory bridgeControllerFactory; private final ActorRef mrb; - public MmsControllerFactory(ActorSystem system, ActorRef mrb) { + public MmsControllerFactory(ActorRef mrb) { super(); - this.system = system; this.callControllerFactory = new CallControllerFactory(); this.conferenceControllerFactory = new ConferenceControllerFactory(); this.bridgeControllerFactory = new BridgeControllerFactory(); @@ -54,21 +51,18 @@ public MmsControllerFactory(ActorSystem system, ActorRef mrb) { } @Override - public ActorRef provideCallController() { - final Props props = new Props(this.callControllerFactory); - return system.actorOf(props); + public Props provideCallControllerProps() { + return new Props(this.callControllerFactory); } @Override - public ActorRef provideConferenceController() { - final Props props = new Props(this.conferenceControllerFactory); - return system.actorOf(props); + public Props provideConferenceControllerProps() { + return new Props(this.conferenceControllerFactory); } @Override - public ActorRef provideBridgeController() { - final Props props = new Props(this.bridgeControllerFactory); - return system.actorOf(props); + public Props provideBridgeControllerProps() { + return new Props(this.bridgeControllerFactory); } private final class CallControllerFactory implements UntypedActorFactory { @@ -77,7 +71,7 @@ private final class CallControllerFactory implements UntypedActorFactory { @Override public Actor create() throws Exception { - return new MmsCallController(mrb, system); + return new MmsCallController(mrb); } } @@ -100,7 +94,7 @@ private final class BridgeControllerFactory implements UntypedActorFactory { @Override public Actor create() throws Exception { - return new MmsBridgeController(mrb, system); + return new MmsBridgeController(mrb); } } 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 49622b5027..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 @@ -27,13 +27,14 @@ import akka.actor.UntypedActorFactory; import akka.event.Logging; import akka.event.LoggingAdapter; - import com.google.i18n.phonenumbers.PhoneNumberUtil; 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; import org.restcomm.connect.dao.AccountsDao; import org.restcomm.connect.dao.ApplicationsDao; @@ -54,7 +55,9 @@ 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.interpreter.SmsInterpreterBuilder; +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; import org.restcomm.connect.monitoringservice.MonitoringService; import org.restcomm.connect.sms.api.CreateSmsSession; @@ -75,7 +78,6 @@ import javax.servlet.sip.SipServletRequest; import javax.servlet.sip.SipServletResponse; import javax.servlet.sip.SipURI; - import java.io.IOException; import java.math.BigDecimal; import java.net.URI; @@ -89,7 +91,7 @@ * @author quintana.thomas@gmail.com (Thomas Quintana) * @author jean.deruelle@telestax.com */ -public final class SmsService extends UntypedActor { +public final class SmsService extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); private final ActorSystem system; @@ -291,16 +293,18 @@ private boolean redirectToHostedSmsApp(final ActorRef self, final SipServletRequ URI appUri = number.getSmsUrl(); ActorRef interpreter = null; if (appUri != null || number.getSmsApplicationSid() != null) { - final SmsInterpreterBuilder builder = new SmsInterpreterBuilder(system); + final SmsInterpreterParams.Builder builder = new SmsInterpreterParams.Builder(); builder.setSmsService(self); builder.setConfiguration(configuration); builder.setStorage(storage); - builder.setAccount(number.getAccountSid()); + builder.setAccountId(number.getAccountSid()); builder.setVersion(number.getApiVersion()); 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)); } @@ -315,7 +319,8 @@ private boolean redirectToHostedSmsApp(final ActorRef self, final SipServletRequ builder.setFallbackUrl(UriUtils.resolve(number.getSmsFallbackUrl())); builder.setFallbackMethod(number.getSmsFallbackMethod()); } - interpreter = builder.build(); + final Props props = SmsInterpreter.props(builder.build()); + interpreter = getContext().actorOf(props); } //TODO:do extensions check here too? final ActorRef session = session(this.configuration); @@ -420,7 +425,7 @@ public UntypedActor create() throws Exception { return new SmsSession(p_configuration, sipFactory, outboundInterface(), storage, monitoringService, servletContext); } }); - return system.actorOf(props); + return getContext().actorOf(props); } // used for sending warning and error logs to notification engine and to the console diff --git a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsServiceProxy.java b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsServiceProxy.java index dde5057a78..578b8029e3 100644 --- a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsServiceProxy.java +++ b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsServiceProxy.java @@ -86,7 +86,7 @@ private ActorRef smppService(final Configuration configuration, final SipFactory private static final long serialVersionUID = 1L; @Override public UntypedActor create() throws Exception { - return new SmppService(system, configuration, factory, storage, context, smppMessageHandler); + return new SmppService(configuration, factory, storage, context, smppMessageHandler); } }); return system.actorOf(props); diff --git a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsSession.java b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsSession.java index 4b4cc4f3b2..244a4cba42 100644 --- a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsSession.java +++ b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/SmsSession.java @@ -20,29 +20,29 @@ package org.restcomm.connect.sms; import akka.actor.ActorRef; -import akka.actor.UntypedActor; import akka.event.Logging; import akka.event.LoggingAdapter; import com.cloudhopper.commons.charset.Charset; import com.cloudhopper.commons.charset.CharsetUtil; import com.cloudhopper.commons.util.ByteArrayUtil; -import com.cloudhopper.smpp.tlv.Tlv; import com.cloudhopper.smpp.SmppConstants; +import com.cloudhopper.smpp.tlv.Tlv; import com.google.common.collect.ImmutableMap; import org.apache.commons.configuration.Configuration; -import org.restcomm.connect.sms.api.GetLastSmsRequest; -import org.restcomm.connect.sms.api.SmsSessionAttribute; -import org.restcomm.connect.sms.api.SmsSessionInfo; -import org.restcomm.connect.sms.api.SmsSessionRequest; -import org.restcomm.connect.sms.api.SmsSessionResponse; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; +import org.restcomm.connect.commons.patterns.Observe; +import org.restcomm.connect.commons.patterns.Observing; +import org.restcomm.connect.commons.patterns.StopObserving; import org.restcomm.connect.dao.ClientsDao; import org.restcomm.connect.dao.DaoManager; import org.restcomm.connect.dao.RegistrationsDao; import org.restcomm.connect.dao.entities.Client; import org.restcomm.connect.dao.entities.Registration; -import org.restcomm.connect.commons.patterns.Observe; -import org.restcomm.connect.commons.patterns.Observing; -import org.restcomm.connect.commons.patterns.StopObserving; +import org.restcomm.connect.sms.api.GetLastSmsRequest; +import org.restcomm.connect.sms.api.SmsSessionAttribute; +import org.restcomm.connect.sms.api.SmsSessionInfo; +import org.restcomm.connect.sms.api.SmsSessionRequest; +import org.restcomm.connect.sms.api.SmsSessionResponse; import org.restcomm.connect.sms.smpp.SmppClientOpsThread; import org.restcomm.connect.sms.smpp.SmppInboundMessageEntity; import org.restcomm.connect.sms.smpp.SmppMessageHandler; @@ -69,7 +69,7 @@ /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ -public final class SmsSession extends UntypedActor { +public final class SmsSession extends RestcommUntypedActor { // Logger private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); // Runtime stuff. diff --git a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppInterpreter.java b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppInterpreter.java index 0a39bc7bdf..b92bb786cd 100644 --- a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppInterpreter.java +++ b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppInterpreter.java @@ -2,7 +2,6 @@ import akka.actor.Actor; import akka.actor.ActorRef; -import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.UntypedActor; import akka.actor.UntypedActorContext; @@ -20,6 +19,7 @@ import org.apache.log4j.Logger; import org.joda.time.DateTime; import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.fsm.Action; import org.restcomm.connect.commons.fsm.FiniteStateMachine; import org.restcomm.connect.commons.fsm.State; @@ -69,11 +69,9 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import static org.restcomm.connect.interpreter.rcml.Verbs.email; -import static org.restcomm.connect.interpreter.rcml.Verbs.redirect; -import static org.restcomm.connect.interpreter.rcml.Verbs.sms; +import static org.restcomm.connect.interpreter.rcml.Verbs.*; -public class SmppInterpreter extends UntypedActor { +public class SmppInterpreter extends RestcommUntypedActor { private static final int ERROR_NOTIFICATION = 0; @@ -84,7 +82,6 @@ public class SmppInterpreter extends UntypedActor { // private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); // States for the FSM. - private final ActorSystem system; private final State uninitialized; private final State acquiringLastSmsRequest; private final State downloadingRcml; @@ -131,11 +128,8 @@ public class SmppInterpreter extends UntypedActor { private ConcurrentHashMap customHttpHeaderMap = new ConcurrentHashMap(); private ConcurrentHashMap customRequestHeaderMap; - public SmppInterpreter(final ActorRef smppMessageHandler, final Configuration configuration, final DaoManager storage, - final Sid accountId, final String version, final URI url, final String method, final URI fallbackUrl, - final String fallbackMethod) { + public SmppInterpreter(final SmppInterpreterParams params) { super(); - system = context().system(); final ActorRef source = self(); uninitialized = new State("uninitialized", null, null); acquiringLastSmsRequest = new State("acquiring last sms event", new AcquiringLastSmsEvent(source), null); @@ -192,21 +186,30 @@ public SmppInterpreter(final ActorRef smppMessageHandler, final Configuration co // Initialize the FSM. this.fsm = new FiniteStateMachine(uninitialized, transitions); // Initialize the runtime stuff. - this.smppMessageHandler = smppMessageHandler; + this.smppMessageHandler = params.getSmsService(); this.downloader = downloader(); - this.storage = storage; - this.runtime = configuration.subset("runtime-settings"); - this.configuration = configuration.subset("sms-aggregator"); - this.accountId = accountId; - this.version = version; - this.url = url; - this.method = method; - this.fallbackUrl = fallbackUrl; - this.fallbackMethod = fallbackMethod; + this.storage = params.getStorage(); + this.runtime = params.getConfiguration().subset("runtime-settings"); + this.configuration = params.getConfiguration().subset("sms-aggregator"); + this.accountId = params.getAccountId(); + this.version = params.getVersion(); + this.url = params.getUrl(); + this.method = params.getMethod(); + this.fallbackUrl = params.getFallbackUrl(); + this.fallbackMethod = params.getFallbackMethod(); this.sessions = new HashMap(); this.normalizeNumber = runtime.getBoolean("normalize-numbers-for-outbound-calls"); } + public static Props props(final SmppInterpreterParams params) { + return new Props(new UntypedActorFactory() { + @Override + public Actor create() throws Exception { + return new SmppInterpreter(params); + } + }); + } + private ActorRef downloader() { final Props props = new Props(new UntypedActorFactory() { private static final long serialVersionUID = 1L; @@ -215,7 +218,7 @@ public UntypedActor create() throws Exception { return new Downloader(); } }); - return system.actorOf(props); + return getContext().actorOf(props); } ActorRef mailer(final Configuration configuration) { @@ -226,7 +229,7 @@ public Actor create() throws Exception { return new EmailService(configuration); } }); - return system.actorOf(props); + return getContext().actorOf(props); } protected String format(final String number) { @@ -420,7 +423,7 @@ public UntypedActor create() throws Exception { return new Parser(xml, self()); } }); - return system.actorOf(props); + return getContext().actorOf(props); } private void response(final Object message) { diff --git a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppInterpreterBuilder.java b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppInterpreterBuilder.java deleted file mode 100644 index 6e2279b18d..0000000000 --- a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppInterpreterBuilder.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.restcomm.connect.sms.smpp; - -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.actor.Props; -import akka.actor.UntypedActor; -import akka.actor.UntypedActorFactory; -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.restcomm.connect.commons.dao.Sid; -import org.restcomm.connect.dao.DaoManager; - -import java.net.URI; - -public class SmppInterpreterBuilder { - - private static Logger logger = Logger.getLogger(SmppInterpreterBuilder.class); - private final ActorSystem system; - private Configuration configuration; - private ActorRef service; - private DaoManager storage; - private Sid accountId; - private String version; - private URI url; - private String method; - private URI fallbackUrl; - private String fallbackMethod; - - public SmppInterpreterBuilder(final ActorSystem system) { - super(); - this.system = system; - } - - public ActorRef build() { - final Props props = new Props(new UntypedActorFactory() { - private static final long serialVersionUID = 1L; - - @Override - public UntypedActor create() throws Exception { - return new SmppInterpreter(service, configuration, storage, accountId, version, url, method, fallbackUrl, - fallbackMethod); - } - }); - return system.actorOf(props); - } - - public void setConfiguration(final Configuration configuration) { - this.configuration = configuration; - } - - public void setSmsService(final ActorRef service) { - this.service = service; - } - - public void setStorage(final DaoManager storage) { - this.storage = storage; - } - - public void setAccount(final Sid accountId) { - this.accountId = accountId; - } - - public void setUrl(final URI url) { - this.url = url; - } - - public void setMethod(final String method) { - this.method = method; - } - - public void setFallbackUrl(final URI fallbackUrl) { - this.fallbackUrl = fallbackUrl; - } - - public void setFallbackMethod(final String fallbackMethod) { - this.fallbackMethod = fallbackMethod; - } - - public void setVersion(final String version) { - this.version = version; - } - -} diff --git a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppInterpreterParams.java b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppInterpreterParams.java new file mode 100644 index 0000000000..a7150a83eb --- /dev/null +++ b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppInterpreterParams.java @@ -0,0 +1,153 @@ +/* + * 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.sms.smpp; + +import akka.actor.ActorRef; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.DaoManager; + +import java.net.URI; + +/** + * @author oleg.agafonov@telestax.com (Oleg Agafonov) + */ +public final class SmppInterpreterParams { + + private Configuration configuration; + private ActorRef smsService; + private DaoManager storage; + private Sid accountId; + private String version; + private URI url; + private String method; + private URI fallbackUrl; + private String fallbackMethod; + + private SmppInterpreterParams(Configuration configuration, ActorRef smsService, DaoManager storage, Sid accountId, String version, URI url, String method, URI fallbackUrl, String fallbackMethod) { + this.configuration = configuration; + this.smsService = smsService; + this.storage = storage; + this.accountId = accountId; + this.version = version; + this.url = url; + this.method = method; + this.fallbackUrl = fallbackUrl; + this.fallbackMethod = fallbackMethod; + } + + public Configuration getConfiguration() { + return configuration; + } + + public ActorRef getSmsService() { + return smsService; + } + + public DaoManager getStorage() { + return storage; + } + + public Sid getAccountId() { + return accountId; + } + + public String getVersion() { + return version; + } + + public URI getUrl() { + return url; + } + + public String getMethod() { + return method; + } + + public URI getFallbackUrl() { + return fallbackUrl; + } + + public String getFallbackMethod() { + return fallbackMethod; + } + + public static final class Builder { + private Configuration configuration; + private ActorRef smsService; + private DaoManager storage; + private Sid accountId; + private String version; + private URI url; + private String method; + private URI fallbackUrl; + private String fallbackMethod; + + public Builder setConfiguration(Configuration configuration) { + this.configuration = configuration; + return this; + } + + public Builder setSmsService(ActorRef smsService) { + this.smsService = smsService; + return this; + } + + public Builder setStorage(DaoManager storage) { + this.storage = storage; + return this; + } + + public Builder setAccountId(Sid accountId) { + this.accountId = accountId; + return this; + } + + public Builder setVersion(String version) { + this.version = version; + return this; + } + + public Builder setUrl(URI url) { + this.url = url; + return this; + } + + public Builder setMethod(String method) { + this.method = method; + return this; + } + + public Builder setFallbackUrl(URI fallbackUrl) { + this.fallbackUrl = fallbackUrl; + return this; + } + + public Builder setFallbackMethod(String fallbackMethod) { + this.fallbackMethod = fallbackMethod; + return this; + } + + public SmppInterpreterParams build() { + return new SmppInterpreterParams(configuration, smsService, storage, accountId, version, url, method, fallbackUrl, fallbackMethod); + } + } +} 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 a9f826ee02..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 @@ -1,27 +1,27 @@ package org.restcomm.connect.sms.smpp; import akka.actor.ActorRef; -import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.UntypedActor; import akka.actor.UntypedActorContext; import akka.actor.UntypedActorFactory; import akka.event.Logging; import akka.event.LoggingAdapter; - import com.cloudhopper.commons.charset.CharsetUtil; import com.cloudhopper.smpp.pdu.SubmitSm; +import com.cloudhopper.smpp.tlv.Tlv; import com.cloudhopper.smpp.type.Address; import com.cloudhopper.smpp.type.RecoverablePduException; import com.cloudhopper.smpp.type.SmppChannelException; import com.cloudhopper.smpp.type.SmppInvalidArgumentException; import com.cloudhopper.smpp.type.SmppTimeoutException; import com.cloudhopper.smpp.type.UnrecoverablePduException; -import com.cloudhopper.smpp.tlv.Tlv; 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; import org.restcomm.connect.dao.AccountsDao; import org.restcomm.connect.dao.ApplicationsDao; @@ -29,13 +29,12 @@ import org.restcomm.connect.dao.IncomingPhoneNumbersDao; import org.restcomm.connect.dao.entities.Application; import org.restcomm.connect.dao.entities.IncomingPhoneNumber; -//import org.restcomm.connect.extension.api.ExtensionRequest; -//import org.restcomm.connect.extension.api.ExtensionResponse; import org.restcomm.connect.extension.api.ExtensionType; import org.restcomm.connect.extension.api.IExtensionCreateSmsSessionRequest; 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; @@ -48,16 +47,17 @@ import javax.servlet.sip.SipFactory; import javax.servlet.sip.SipServlet; import javax.servlet.sip.SipURI; - import java.io.IOException; import java.net.URI; -import java.util.List; import java.util.Collection; +import java.util.List; + +//import org.restcomm.connect.extension.api.ExtensionRequest; +//import org.restcomm.connect.extension.api.ExtensionResponse; -public class SmppMessageHandler extends UntypedActor { +public class SmppMessageHandler extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); - private final ActorSystem system = getContext().system(); private final ServletContext servletContext; private final DaoManager storage; private final Configuration configuration; @@ -160,16 +160,18 @@ private boolean redirectToHostedSmsApp(final ActorRef self, final SmppInboundMes URI appUri = number.getSmsUrl(); - final SmppInterpreterBuilder builder = new SmppInterpreterBuilder(system); + final SmppInterpreterParams.Builder builder = new SmppInterpreterParams.Builder(); builder.setSmsService(self); builder.setConfiguration(configuration); builder.setStorage(storage); - builder.setAccount(number.getAccountSid()); + builder.setAccountId(number.getAccountSid()); builder.setVersion(number.getApiVersion()); 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 { @@ -182,7 +184,8 @@ private boolean redirectToHostedSmsApp(final ActorRef self, final SmppInboundMes builder.setFallbackUrl(UriUtils.resolve(number.getSmsFallbackUrl())); builder.setFallbackMethod(number.getSmsFallbackMethod()); } - interpreter = builder.build(); + final Props props = SmppInterpreter.props(builder.build()); + interpreter = getContext().actorOf(props); Configuration cfg = this.configuration; //Extension final ActorRef session = session(cfg); @@ -221,7 +224,7 @@ public UntypedActor create() throws Exception { return new SmsSession(p_configuration, sipFactory, outboundInterface(), storage, monitoringService, servletContext); } }); - return system.actorOf(props); + return getContext().actorOf(props); } public void outbound(SmppOutboundMessageEntity request) throws SmppInvalidArgumentException, IOException { diff --git a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppService.java b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppService.java index aa17a989fc..1851a63029 100644 --- a/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppService.java +++ b/restcomm/restcomm.sms/src/main/java/org/restcomm/connect/sms/smpp/SmppService.java @@ -20,8 +20,20 @@ package org.restcomm.connect.sms.smpp; -import static javax.servlet.sip.SipServlet.OUTBOUND_INTERFACES; +import akka.actor.ActorRef; +import akka.event.Logging; +import akka.event.LoggingAdapter; +import com.cloudhopper.smpp.SmppBindType; +import com.cloudhopper.smpp.impl.DefaultSmppClient; +import com.cloudhopper.smpp.type.Address; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; +import org.restcomm.connect.dao.DaoManager; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.sip.SipFactory; +import javax.servlet.sip.SipURI; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; @@ -30,23 +42,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.atomic.AtomicInteger; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.sip.SipFactory; -import javax.servlet.sip.SipURI; - -import akka.actor.ActorRef; -import org.apache.commons.configuration.Configuration; -import org.restcomm.connect.dao.DaoManager; - -import akka.actor.ActorSystem; -import akka.actor.UntypedActor; -import akka.event.Logging; -import akka.event.LoggingAdapter; - -import com.cloudhopper.smpp.SmppBindType; -import com.cloudhopper.smpp.impl.DefaultSmppClient; -import com.cloudhopper.smpp.type.Address; +import static javax.servlet.sip.SipServlet.OUTBOUND_INTERFACES; /** * @@ -54,10 +50,9 @@ * @author gvagenas@telestax.com * */ -public final class SmppService extends UntypedActor { +public final class SmppService extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); - private final ActorSystem system; private final ActorRef smppMessageHandler; private final Configuration configuration; private boolean authenticateUsers = true; @@ -82,11 +77,10 @@ public final class SmppService extends UntypedActor { private ArrayList smppList = new ArrayList(); - public SmppService(final ActorSystem system, final Configuration configuration, final SipFactory factory, + public SmppService(final Configuration configuration, final SipFactory factory, final DaoManager storage, final ServletContext servletContext, final ActorRef smppMessageHandler) { super(); - this.system = system; this.smppMessageHandler = smppMessageHandler; this.configuration = configuration; final Configuration runtime = configuration.subset("runtime-settings"); diff --git a/restcomm/restcomm.telephony.api/src/main/java/org/restcomm/connect/telephony/api/util/B2BUAHelper.java b/restcomm/restcomm.telephony.api/src/main/java/org/restcomm/connect/telephony/api/util/B2BUAHelper.java index b2184d769f..3e86f537ad 100644 --- a/restcomm/restcomm.telephony.api/src/main/java/org/restcomm/connect/telephony/api/util/B2BUAHelper.java +++ b/restcomm/restcomm.telephony.api/src/main/java/org/restcomm/connect/telephony/api/util/B2BUAHelper.java @@ -498,9 +498,11 @@ public static void forwardResponse(final SipServletResponse response, final bool SipServletResponse clonedResponse = linkedRequest.createResponse(response.getStatus()); SipURI originalURI = null; try { - originalURI = (SipURI) response.getAddressHeader("Contact").getURI(); - if (originalURI.getUser() != null && !originalURI.getUser().isEmpty()) { - ((SipURI) clonedResponse.getAddressHeader("Contact").getURI()).setUser(originalURI.getUser()); + if(response.getAddressHeader("Contact") != null && response.getAddressHeader("Contact").getURI() != null){ + originalURI = (SipURI) response.getAddressHeader("Contact").getURI(); + if (originalURI != null && originalURI.getUser() != null && !originalURI.getUser().isEmpty()) { + ((SipURI) clonedResponse.getAddressHeader("Contact").getURI()).setUser(originalURI.getUser()); + } } } catch (ServletParseException | NullPointerException e) { logger.error("Problem while trying to set User part on a clones response for a P2P call, "+e); diff --git a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/Bridge.java b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/Bridge.java index ef3fd27331..ac8a5de59b 100644 --- a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/Bridge.java +++ b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/Bridge.java @@ -21,19 +21,19 @@ package org.restcomm.connect.telephony; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.restcomm.connect.telephony.api.BridgeStateChanged; -import org.restcomm.connect.telephony.api.JoinCalls; -import org.restcomm.connect.telephony.api.StartBridge; -import org.restcomm.connect.telephony.api.StopBridge; +import akka.actor.ActorRef; +import akka.event.Logging; +import akka.event.LoggingAdapter; +import jain.protocol.ip.mgcp.message.parms.ConnectionMode; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.fsm.Action; import org.restcomm.connect.commons.fsm.FiniteStateMachine; import org.restcomm.connect.commons.fsm.State; import org.restcomm.connect.commons.fsm.Transition; +import org.restcomm.connect.commons.patterns.Observe; +import org.restcomm.connect.commons.patterns.Observing; +import org.restcomm.connect.commons.patterns.StopObserving; +import org.restcomm.connect.mscontrol.api.MediaServerControllerFactory; import org.restcomm.connect.mscontrol.api.messages.CreateMediaSession; import org.restcomm.connect.mscontrol.api.messages.JoinCall; import org.restcomm.connect.mscontrol.api.messages.JoinComplete; @@ -42,22 +42,22 @@ import org.restcomm.connect.mscontrol.api.messages.MediaServerControllerStateChanged.MediaServerControllerState; import org.restcomm.connect.mscontrol.api.messages.StartRecording; import org.restcomm.connect.mscontrol.api.messages.Stop; -import org.restcomm.connect.commons.patterns.Observe; -import org.restcomm.connect.commons.patterns.Observing; -import org.restcomm.connect.commons.patterns.StopObserving; +import org.restcomm.connect.telephony.api.BridgeStateChanged; import org.restcomm.connect.telephony.api.BridgeStateChanged.BridgeState; +import org.restcomm.connect.telephony.api.JoinCalls; +import org.restcomm.connect.telephony.api.StartBridge; +import org.restcomm.connect.telephony.api.StopBridge; -import akka.actor.ActorRef; -import akka.actor.UntypedActor; -import akka.event.Logging; -import akka.event.LoggingAdapter; -import jain.protocol.ip.mgcp.message.parms.ConnectionMode; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; /** * @author Henrique Rosa (henrique.rosa@telestax.com) * */ -public class Bridge extends UntypedActor { +public class Bridge extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); @@ -83,11 +83,11 @@ public class Bridge extends UntypedActor { // Observer pattern private final List observers; - public Bridge(final ActorRef mscontroller) { + public Bridge(MediaServerControllerFactory factory) { final ActorRef source = self(); // Media Server Controller - this.mscontroller = mscontroller; + this.mscontroller = getContext().actorOf(factory.provideBridgeControllerProps()); // States for the FSM this.uninitialized = new State("uninitialized", null, null); diff --git a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/BridgeManager.java b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/BridgeManager.java index 18d032eb4b..ecb6e87d7e 100644 --- a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/BridgeManager.java +++ b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/BridgeManager.java @@ -22,12 +22,12 @@ package org.restcomm.connect.telephony; import akka.actor.ActorRef; -import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.UntypedActor; import akka.actor.UntypedActorFactory; import akka.event.Logging; import akka.event.LoggingAdapter; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.patterns.Observe; import org.restcomm.connect.mscontrol.api.MediaServerControllerFactory; import org.restcomm.connect.telephony.api.BridgeManagerResponse; @@ -38,17 +38,15 @@ * @author Henrique Rosa (henrique.rosa@telestax.com) * */ -public class BridgeManager extends UntypedActor { +public class BridgeManager extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); private final MediaServerControllerFactory factory; - private final ActorSystem system; public BridgeManager(final MediaServerControllerFactory factory) { super(); this.factory = factory; - this.system = context().system(); } private ActorRef createBridge() { @@ -57,10 +55,10 @@ private ActorRef createBridge() { @Override public UntypedActor create() throws Exception { - return new Bridge(factory.provideBridgeController()); + return new Bridge(factory); } }); - return system.actorOf(props); + return getContext().actorOf(props); } /* diff --git a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/Call.java b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/Call.java index a4bbf71749..633100a765 100644 --- a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/Call.java +++ b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/Call.java @@ -20,7 +20,6 @@ package org.restcomm.connect.telephony; import akka.actor.ActorRef; -import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.ReceiveTimeout; import akka.actor.UntypedActor; @@ -28,7 +27,6 @@ import akka.actor.UntypedActorFactory; import akka.event.Logging; import akka.event.LoggingAdapter; - import org.apache.commons.configuration.Configuration; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; @@ -40,6 +38,7 @@ import org.restcomm.connect.commons.annotations.concurrency.Immutable; import org.restcomm.connect.commons.configuration.RestcommConfiguration; import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.fsm.Action; import org.restcomm.connect.commons.fsm.FiniteStateMachine; import org.restcomm.connect.commons.fsm.State; @@ -57,6 +56,7 @@ import org.restcomm.connect.dao.entities.CallDetailRecord; import org.restcomm.connect.http.client.Downloader; import org.restcomm.connect.http.client.HttpRequestDescriptor; +import org.restcomm.connect.mscontrol.api.MediaServerControllerFactory; import org.restcomm.connect.mscontrol.api.messages.CloseMediaSession; import org.restcomm.connect.mscontrol.api.messages.Collect; import org.restcomm.connect.mscontrol.api.messages.CreateMediaSession; @@ -95,7 +95,6 @@ import org.restcomm.connect.telephony.api.InitializeOutbound; import org.restcomm.connect.telephony.api.Reject; import org.restcomm.connect.telephony.api.RemoveParticipant; - import scala.concurrent.duration.Duration; import javax.sdp.SdpException; @@ -113,7 +112,6 @@ import javax.sip.header.RecordRouteHeader; import javax.sip.header.RouteHeader; import javax.sip.message.Response; - import java.io.IOException; import java.math.BigDecimal; import java.net.InetAddress; @@ -142,7 +140,7 @@ * */ @Immutable -public final class Call extends UntypedActor { +public final class Call extends RestcommUntypedActor { // Logging private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); @@ -267,7 +265,6 @@ public final class Call extends UntypedActor { private HttpRequestDescriptor requestCallback; ActorRef downloader = null; - ActorSystem system = null; private URI statusCallback; private String statusCallbackMethod; private List statusCallbackEvent; @@ -286,18 +283,17 @@ public String toString() { } }; - public Call(final SipFactory factory, final ActorRef mediaSessionController, final Configuration configuration, + public Call(final SipFactory factory, final MediaServerControllerFactory mediaSessionControllerFactory, final Configuration configuration, final URI statusCallback, final String statusCallbackMethod, final List statusCallbackEvent) { - this(factory, mediaSessionController, configuration, statusCallback, statusCallbackMethod, + this(factory, mediaSessionControllerFactory, configuration, statusCallback, statusCallbackMethod, statusCallbackEvent, null); } - public Call(final SipFactory factory, final ActorRef mediaSessionController, final Configuration configuration, + public Call(final SipFactory factory, final MediaServerControllerFactory mediaSessionControllerFactory, final Configuration configuration, final URI statusCallback, final String statusCallbackMethod, final List statusCallbackEvent, Map> headers) { super(); final ActorRef source = self(); - this.system = context().system(); this.statusCallback = statusCallback; this.statusCallbackMethod = statusCallbackMethod; this.statusCallbackEvent = statusCallbackEvent; @@ -409,7 +405,7 @@ public Call(final SipFactory factory, final ActorRef mediaSessionController, fin this.conferencing = false; // Media Session Control runtime stuff. - this.msController = mediaSessionController; + this.msController = getContext().actorOf(mediaSessionControllerFactory.provideCallControllerProps()); this.fail = false; // Initialize the runtime stuff. @@ -441,7 +437,7 @@ public UntypedActor create() throws Exception { return new Downloader(); } }); - return system.actorOf(props); + return getContext().actorOf(props); } private boolean is(State state) { @@ -565,7 +561,7 @@ private List dialStatusCallbackParameters(final CallbackState sta private void executeStatusCallback(final CallbackState state) { if (statusCallback != null) { - if (statusCallbackEvent.contains(state.toString())) { + if (statusCallbackEvent.remove(state.toString())) { if (logger.isDebugEnabled()) { String msg = String.format("About to execute Call StatusCallback for state %s to StatusCallback %s. Call from %s to %s direction %s", state.text, statusCallback.toString(), from.toString(), to.toString(), direction); logger.debug(msg); @@ -581,7 +577,7 @@ private void executeStatusCallback(final CallbackState state) { } } else { if (logger.isDebugEnabled()) { - String msg = String.format("Call StatusCallback did not run because state %s no in the statusCallbackEvent list", state.text); + String msg = String.format("Call StatusCallback will not be sent because its either not in the statusCallbackEvent list or already sent, state %s . Call from %s to %s direction %s", state.text, from.toString(), to.toString(), direction); logger.debug(msg); } } @@ -1726,10 +1722,26 @@ public Stopping(final ActorRef source) { @Override public void execute(Object message) throws Exception { // Stops media operations and closes media session + if (logger.isDebugEnabled()) { + if (message instanceof SipServletRequest) { + logger.debug("At Call Stopping state because of SipServletRequest: "+((SipServletRequest)message).getMethod()); + } else if (message instanceof Hangup) { + logger.debug("At Call Stopping state because of Hangup: "+((Hangup)message)); + } else { + logger.debug("At Call Stopping state because of Message: "+message); + } + } + msController.tell(new CloseMediaSession(), source); if (fail) { + if (logger.isDebugEnabled()) { + logger.debug("At Call Stopping state, moving to Failed state"); + } fsm.transition(message, failed); } else { + if (logger.isDebugEnabled()) { + logger.debug("At Call Stopping state, moving to Completed state"); + } fsm.transition(message, completed); } } @@ -2202,7 +2214,7 @@ private void onSipServletResponse(SipServletResponse message, ActorRef self, Act private void onHangup(Hangup message, ActorRef self, ActorRef sender) throws Exception { if(logger.isDebugEnabled()) { - logger.debug("Got Hangup: "+message+" for Call, from: "+from+" to: "+to+" state: "+fsm.state()+" conferencing: "+conferencing +" conference: "+conference); + logger.debug("Got Hangup: "+message+" for Call, from: "+from+", to: "+to+", state: "+fsm.state()+", conferencing: "+conferencing +", conference: "+conference); } if (is(completed)) { @@ -2221,7 +2233,7 @@ private void onHangup(Hangup message, ActorRef self, ActorRef sender) throws Exc msController.tell(new Stop(true), self); } - if (is(updatingMediaSession) || is(ringing) || is(queued) || is(dialing) || is(inProgress) || is(completed) || is(waitingForAnswer)) { + if (is(updatingMediaSession) || is(ringing) || is(queued) || is(dialing) || is(inProgress) || is(waitingForAnswer)) { if (conferencing) { // Tell conference to remove the call from participants list // before moving to a stopping state @@ -2237,6 +2249,8 @@ private void onHangup(Hangup message, ActorRef self, ActorRef sender) throws Exc } } else if (is(failingNoAnswer)) { fsm.transition(message, canceling); + } else if (is(stopping)) { + fsm.transition(message, completed); } } 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 eb1d0a5042..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,7 +38,9 @@ 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; import org.restcomm.connect.commons.telephony.CreateCallType; import org.restcomm.connect.commons.telephony.ProxyRule; @@ -64,9 +66,11 @@ 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.VoiceInterpreterBuilder; +import org.restcomm.connect.interpreter.VoiceInterpreter; +import org.restcomm.connect.interpreter.VoiceInterpreterParams; import org.restcomm.connect.monitoringservice.MonitoringService; import org.restcomm.connect.mscontrol.api.MediaServerControllerFactory; import org.restcomm.connect.telephony.api.CallInfo; @@ -125,12 +129,7 @@ import static akka.pattern.Patterns.ask; import static javax.servlet.sip.SipServlet.OUTBOUND_INTERFACES; -import static javax.servlet.sip.SipServletResponse.SC_ACCEPTED; -import static javax.servlet.sip.SipServletResponse.SC_BAD_REQUEST; -import static javax.servlet.sip.SipServletResponse.SC_FORBIDDEN; -import static javax.servlet.sip.SipServletResponse.SC_NOT_FOUND; -import static javax.servlet.sip.SipServletResponse.SC_OK; -import static javax.servlet.sip.SipServletResponse.SC_SERVER_INTERNAL_ERROR; +import static javax.servlet.sip.SipServletResponse.*; /** * @author quintana.thomas@gmail.com (Thomas Quintana) @@ -138,7 +137,7 @@ * @author jean.deruelle@telestax.com * @author gvagenas@telestax.com */ -public final class CallManager extends UntypedActor { +public final class CallManager extends RestcommUntypedActor { static final int ERROR_NOTIFICATION = 0; static final int WARNING_NOTIFICATION = 1; @@ -372,7 +371,7 @@ private ActorRef call(final CreateCall request) { @Override public UntypedActor create() throws Exception { - return new Call(sipFactory, msControllerFactory.provideCallController(), configuration, + return new Call(sipFactory, msControllerFactory, configuration, null, null, null, null); } }); @@ -382,12 +381,12 @@ public UntypedActor create() throws Exception { @Override public UntypedActor create() throws Exception { - return new Call(sipFactory, msControllerFactory.provideCallController(), configuration, + return new Call(sipFactory, msControllerFactory, configuration, request.statusCallback(), request.statusCallbackMethod(), request.statusCallbackEvent(), request.getOutboundProxyHeaders()); } }); } - return system.actorOf(props); + return getContext().actorOf(props); } private boolean check(final Object message) throws IOException { @@ -413,7 +412,7 @@ private void destroy(final Object message) throws Exception { if(logger.isInfoEnabled()) { logger.info("About to destroy call: "+request.call().path()+", call isTerminated(): "+sender().isTerminated()+", sender: "+sender()); } - system.stop(call); + getContext().stop(call); } } @@ -818,11 +817,11 @@ private void processRequestAndProxyOut (final SipServletRequest request, final C rcml = String.format("%s", sipUri); } - final VoiceInterpreterBuilder builder = new VoiceInterpreterBuilder(system); + final VoiceInterpreterParams.Builder builder = new VoiceInterpreterParams.Builder(); builder.setConfiguration(configuration); builder.setStorage(storage); builder.setCallManager(self()); - builder.setConferenceManager(conferences); + builder.setConferenceCenter(conferences); builder.setBridgeManager(bridges); builder.setSmsService(sms); @@ -843,7 +842,8 @@ private void processRequestAndProxyOut (final SipServletRequest request, final C builder.setEmailAddress(account.getEmailAddress()); builder.setRcml(rcml); builder.setMonitoring(monitoring); - final ActorRef interpreter = builder.build(); + final Props props = VoiceInterpreter.props(builder.build()); + final ActorRef interpreter = getContext().actorOf(props); final ActorRef call = call(null); final SipApplicationSession application = request.getApplicationSession(); application.setAttribute(Call.class.getName(), call); @@ -858,11 +858,11 @@ private void processRequestAndProxyOut (final SipServletRequest request, final C private void proxyThroughMediaServerAsNumber (final SipServletRequest request, final Client client, final String destNumber) { String rcml = ""+destNumber+""; - final VoiceInterpreterBuilder builder = new VoiceInterpreterBuilder(system); + final VoiceInterpreterParams.Builder builder = new VoiceInterpreterParams.Builder(); builder.setConfiguration(configuration); builder.setStorage(storage); builder.setCallManager(self()); - builder.setConferenceManager(conferences); + builder.setConferenceCenter(conferences); builder.setBridgeManager(bridges); builder.setSmsService(sms); builder.setAccount(client.getAccountSid()); @@ -871,7 +871,9 @@ private void proxyThroughMediaServerAsNumber (final SipServletRequest request, f builder.setEmailAddress(account.getEmailAddress()); builder.setRcml(rcml); builder.setMonitoring(monitoring); - final ActorRef interpreter = builder.build(); + final Props props = VoiceInterpreter.props(builder.build()); + final ActorRef interpreter = getContext().actorOf(props); + final ActorRef call = call(null); final SipApplicationSession application = request.getApplicationSession(); application.setAttribute(Call.class.getName(), call); @@ -881,11 +883,11 @@ private void proxyThroughMediaServerAsNumber (final SipServletRequest request, f private void proxyDialClientThroughMediaServer(final SipServletRequest request, final Client client, final String destNumber) { String rcml = ""+destNumber+""; - final VoiceInterpreterBuilder builder = new VoiceInterpreterBuilder(system); + final VoiceInterpreterParams.Builder builder = new VoiceInterpreterParams.Builder(); builder.setConfiguration(configuration); builder.setStorage(storage); builder.setCallManager(self()); - builder.setConferenceManager(conferences); + builder.setConferenceCenter(conferences); builder.setBridgeManager(bridges); builder.setSmsService(sms); builder.setAccount(client.getAccountSid()); @@ -894,7 +896,9 @@ private void proxyDialClientThroughMediaServer(final SipServletRequest request, builder.setEmailAddress(account.getEmailAddress()); builder.setRcml(rcml); builder.setMonitoring(monitoring); - final ActorRef interpreter = builder.build(); + final Props props = VoiceInterpreter.props(builder.build()); + final ActorRef interpreter = getContext().actorOf(props); + final ActorRef call = call(null); final SipApplicationSession application = request.getApplicationSession(); application.setAttribute(Call.class.getName(), call); @@ -1110,11 +1114,11 @@ private void transfer(SipServletRequest request) throws Exception { existingInterpreter.tell(new StopInterpreter(true), null); // Build a new VoiceInterpreter - final VoiceInterpreterBuilder builder = new VoiceInterpreterBuilder(system); + final VoiceInterpreterParams.Builder builder = new VoiceInterpreterParams.Builder(); builder.setConfiguration(configuration); builder.setStorage(storage); builder.setCallManager(self()); - builder.setConferenceManager(conferences); + builder.setConferenceCenter(conferences); builder.setBridgeManager(bridges); builder.setSmsService(sms); builder.setAccount(cdr.getAccountSid()); @@ -1122,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())); } @@ -1139,7 +1145,8 @@ private void transfer(SipServletRequest request) throws Exception { builder.setMonitoring(monitoring); // Ask first transferorActor leg to execute with the new Interpreter - final ActorRef interpreter = builder.build(); + final Props props = VoiceInterpreter.props(builder.build()); + final ActorRef interpreter = getContext().actorOf(props); system.scheduler().scheduleOnce(Duration.create(500, TimeUnit.MILLISECONDS), interpreter, new StartInterpreter(transfereeActor), system.dispatcher()); if(logger.isInfoEnabled()) { @@ -1207,11 +1214,11 @@ private boolean redirectToHostedVoiceApp(final ActorRef self, final SipServletRe number = numbers.getIncomingPhoneNumber("*"); } if (number != null) { - final VoiceInterpreterBuilder builder = new VoiceInterpreterBuilder(system); + final VoiceInterpreterParams.Builder builder = new VoiceInterpreterParams.Builder(); builder.setConfiguration(configuration); builder.setStorage(storage); builder.setCallManager(self); - builder.setConferenceManager(conferences); + builder.setConferenceCenter(conferences); builder.setBridgeManager(bridges); builder.setSmsService(sms); //https://github.com/RestComm/Restcomm-Connect/issues/1939 @@ -1226,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())); } @@ -1245,7 +1254,9 @@ private boolean redirectToHostedVoiceApp(final ActorRef self, final SipServletRe builder.setStatusCallback(number.getStatusCallback()); builder.setStatusCallbackMethod(number.getStatusCallbackMethod()); builder.setMonitoring(monitoring); - final ActorRef interpreter = builder.build(); + final Props props = VoiceInterpreter.props(builder.build()); + final ActorRef interpreter = getContext().actorOf(props); + final ActorRef call = call(null); final SipApplicationSession application = request.getApplicationSession(); application.setAttribute(Call.class.getName(), call); @@ -1282,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(); @@ -1290,11 +1303,11 @@ private boolean redirectToClientVoiceApp(final ActorRef self, final SipServletRe boolean isClientManaged =( (applicationSid != null && !applicationSid.toString().isEmpty() && !applicationSid.toString().equals("")) || (clientAppVoiceUrl != null && !clientAppVoiceUrl.toString().isEmpty() && !clientAppVoiceUrl.toString().equals(""))); if (isClientManaged) { - final VoiceInterpreterBuilder builder = new VoiceInterpreterBuilder(system); + final VoiceInterpreterParams.Builder builder = new VoiceInterpreterParams.Builder(); builder.setConfiguration(configuration); builder.setStorage(storage); builder.setCallManager(self); - builder.setConferenceManager(conferences); + builder.setConferenceCenter(conferences); builder.setBridgeManager(bridges); builder.setSmsService(sms); builder.setAccount(client.getAccountSid()); @@ -1311,7 +1324,8 @@ private boolean redirectToClientVoiceApp(final ActorRef self, final SipServletRe builder.setFallbackUrl(null); builder.setFallbackMethod(client.getVoiceFallbackMethod()); builder.setMonitoring(monitoring); - final ActorRef interpreter = builder.build(); + final Props props = VoiceInterpreter.props(builder.build()); + final ActorRef interpreter = getContext().actorOf(props); final ActorRef call = call(null); final SipApplicationSession application = request.getApplicationSession(); application.setAttribute(Call.class.getName(), call); @@ -1547,11 +1561,11 @@ private boolean isLBPatchRURI(SipServletRequest request, private void execute(final Object message) { final ExecuteCallScript request = (ExecuteCallScript) message; final ActorRef self = self(); - final VoiceInterpreterBuilder builder = new VoiceInterpreterBuilder(system); + final VoiceInterpreterParams.Builder builder = new VoiceInterpreterParams.Builder(); builder.setConfiguration(configuration); builder.setStorage(storage); builder.setCallManager(self); - builder.setConferenceManager(conferences); + builder.setConferenceCenter(conferences); builder.setBridgeManager(bridges); builder.setSmsService(sms); builder.setAccount(request.account()); @@ -1561,7 +1575,8 @@ private void execute(final Object message) { builder.setFallbackUrl(request.fallbackUrl()); builder.setFallbackMethod(request.fallbackMethod()); builder.setMonitoring(monitoring); - final ActorRef interpreter = builder.build(); + final Props props = VoiceInterpreter.props(builder.build()); + final ActorRef interpreter = getContext().actorOf(props); interpreter.tell(new StartInterpreter(request.call()), self); } @@ -1629,11 +1644,11 @@ private void update(final Object message) throws Exception { existingInterpreter.tell(new StopInterpreter(true), null); // Build a new VoiceInterpreter - final VoiceInterpreterBuilder builder = new VoiceInterpreterBuilder(system); + final VoiceInterpreterParams.Builder builder = new VoiceInterpreterParams.Builder(); builder.setConfiguration(configuration); builder.setStorage(storage); builder.setCallManager(self); - builder.setConferenceManager(conferences); + builder.setConferenceCenter(conferences); builder.setBridgeManager(bridges); builder.setSmsService(sms); builder.setAccount(request.account()); @@ -1645,9 +1660,10 @@ private void update(final Object message) throws Exception { builder.setStatusCallback(request.callback()); builder.setStatusCallbackMethod(request.callbackMethod()); builder.setMonitoring(monitoring); + final Props props = VoiceInterpreter.props(builder.build()); // Ask first call leg to execute with the new Interpreter - final ActorRef interpreter = builder.build(); + final ActorRef interpreter = getContext().actorOf(props); system.scheduler().scheduleOnce(Duration.create(500, TimeUnit.MILLISECONDS), interpreter, new StartInterpreter(request.call()), system.dispatcher()); // interpreter.tell(new StartInterpreter(request.call()), self); @@ -1658,7 +1674,7 @@ private void update(final Object message) throws Exception { // Check what to do with the second/outbound call leg of the call if (relatedCall != null && listOfRelatedCalls == null) { if (moveConnectedCallLeg) { - final ActorRef relatedInterpreter = builder.build(); + final ActorRef relatedInterpreter = getContext().actorOf(props); if(logger.isInfoEnabled()) { logger.info("About to redirect related Call :" + relatedCall.path() + " with 200ms delay to related interpreter: " + relatedInterpreter.path()); @@ -2396,11 +2412,11 @@ private void imsProxyThroughMediaServer(final SipServletRequest request, final C logger.info("rcml: " + rcml); } - final VoiceInterpreterBuilder builder = new VoiceInterpreterBuilder(system); + final VoiceInterpreterParams.Builder builder = new VoiceInterpreterParams.Builder(); builder.setConfiguration(configuration); builder.setStorage(storage); builder.setCallManager(self()); - builder.setConferenceManager(conferences); + builder.setConferenceCenter(conferences); builder.setBridgeManager(bridges); builder.setSmsService(sms); builder.setAccount(Sid.generate(Sid.Type.ACCOUNT,imsAccount)); @@ -2412,7 +2428,8 @@ private void imsProxyThroughMediaServer(final SipServletRequest request, final C builder.setImsUaLogin(user); builder.setImsUaPassword(password); } - final ActorRef interpreter = builder.build(); + final Props props = VoiceInterpreter.props(builder.build()); + final ActorRef interpreter = getContext().actorOf(props); final ActorRef call = call(null); final SipApplicationSession application = request.getApplicationSession(); application.setAttribute(Call.class.getName(), call); diff --git a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/CallManagerProxy.java b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/CallManagerProxy.java index 4f4f1dfa42..e4e9db04cc 100644 --- a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/CallManagerProxy.java +++ b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/CallManagerProxy.java @@ -128,14 +128,13 @@ public UntypedActor create() throws Exception { return system.actorOf(props); } - private ActorRef ussdManager(final Configuration configuration, final ServletContext context, final ActorRef conferences, - final ActorRef bridges, final ActorRef sms, final SipFactory factory, final DaoManager storage) { + private ActorRef ussdManager(final Configuration configuration, final ServletContext context, final SipFactory factory, final DaoManager storage) { final Props props = new Props(new UntypedActorFactory() { private static final long serialVersionUID = 1L; @Override public UntypedActor create() throws Exception { - return new UssdCallManager(system, configuration, context, conferences, sms, factory, storage); + return new UssdCallManager(configuration, context, factory, storage); } }); return system.actorOf(props); @@ -200,7 +199,7 @@ public void servletInitialized(SipServletContextEvent event) { final ActorRef bridges = bridges(mscontrolFactory); final ActorRef sms = (ActorRef) context.getAttribute(SmsService.class.getName()); manager = manager(configuration, context, mscontrolFactory, conferences, bridges, sms, factory, storage); - ussdManager = ussdManager(configuration, context, conferences, bridges, sms, factory, storage); + ussdManager = ussdManager(configuration, context, factory, storage); context.setAttribute(CallManager.class.getName(), manager); context.setAttribute(UssdCallManager.class.getName(), ussdManager); } diff --git a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/Conference.java b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/Conference.java index 1fe597f423..4ee6946c12 100644 --- a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/Conference.java +++ b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/Conference.java @@ -20,13 +20,13 @@ package org.restcomm.connect.telephony; import akka.actor.ActorRef; -import akka.actor.UntypedActor; import akka.event.Logging; import akka.event.LoggingAdapter; import jain.protocol.ip.mgcp.message.parms.ConnectionMode; import org.mobicents.servlet.restcomm.mscontrol.messages.MediaServerConferenceControllerStateChanged; import org.restcomm.connect.commons.annotations.concurrency.Immutable; import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.fsm.Action; import org.restcomm.connect.commons.fsm.FiniteStateMachine; import org.restcomm.connect.commons.fsm.State; @@ -38,6 +38,7 @@ import org.restcomm.connect.dao.ConferenceDetailRecordsDao; import org.restcomm.connect.dao.DaoManager; import org.restcomm.connect.dao.entities.ConferenceDetailRecord; +import org.restcomm.connect.mscontrol.api.MediaServerControllerFactory; import org.restcomm.connect.mscontrol.api.messages.CreateMediaSession; import org.restcomm.connect.mscontrol.api.messages.JoinCall; import org.restcomm.connect.mscontrol.api.messages.JoinComplete; @@ -72,7 +73,7 @@ * @author maria.farooq@telestax.com (Maria Farooq) */ @Immutable -public final class Conference extends UntypedActor { +public final class Conference extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); @@ -107,7 +108,7 @@ public final class Conference extends UntypedActor { private final ActorRef conferenceCenter; - public Conference(final String name, final ActorRef msController, final DaoManager storage, final ActorRef conferenceCenter) { + public Conference(final String name, final MediaServerControllerFactory factory, final DaoManager storage, final ActorRef conferenceCenter) { super(); final ActorRef source = self(); @@ -150,7 +151,7 @@ public Conference(final String name, final ActorRef msController, final DaoManag this.conferenceCenter = conferenceCenter; //generate it later at MRB level, by watching if same conference is running on another RC instance. //this.sid = Sid.generate(Sid.Type.CONFERENCE); - this.mscontroller = msController; + this.mscontroller = getContext().actorOf(factory.provideConferenceControllerProps()); this.calls = new ArrayList(); this.observers = new ArrayList(); } diff --git a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/ConferenceCenter.java b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/ConferenceCenter.java index 2c88516de7..9fa9aa1b4a 100644 --- a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/ConferenceCenter.java +++ b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/ConferenceCenter.java @@ -20,13 +20,13 @@ package org.restcomm.connect.telephony; import akka.actor.ActorRef; -import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.UntypedActor; import akka.actor.UntypedActorContext; import akka.actor.UntypedActorFactory; import akka.event.Logging; import akka.event.LoggingAdapter; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.patterns.Observe; import org.restcomm.connect.dao.DaoManager; import org.restcomm.connect.mscontrol.api.MediaServerControllerFactory; @@ -46,7 +46,7 @@ * @author amit.bhayani@telestax.com (Amit Bhayani) * @author maria.farooq@telestax.com (Maria Farooq) */ -public final class ConferenceCenter extends UntypedActor { +public final class ConferenceCenter extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); @@ -54,7 +54,6 @@ public final class ConferenceCenter extends UntypedActor { private final Map conferences; private final Map> initializing; private final DaoManager storage; - private final ActorSystem system; public ConferenceCenter(final MediaServerControllerFactory factory, final DaoManager storage) { super(); @@ -62,7 +61,6 @@ public ConferenceCenter(final MediaServerControllerFactory factory, final DaoMan this.conferences = new HashMap(); this.initializing = new HashMap>(); this.storage = storage; - this.system = context().system(); } private ActorRef getConference(final String name) { @@ -72,10 +70,10 @@ private ActorRef getConference(final String name) { @Override public UntypedActor create() throws Exception { //Here Here we can pass Gateway where call is connected - return new Conference(name, factory.provideConferenceController(), storage, self()); + return new Conference(name, factory, storage, getSelf()); } }); - return system.actorOf(props); + return getContext().actorOf(props); } @Override diff --git a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/proxy/ProxyManager.java b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/proxy/ProxyManager.java index 1809570ec7..f7e1f243e4 100644 --- a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/proxy/ProxyManager.java +++ b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/proxy/ProxyManager.java @@ -19,13 +19,17 @@ */ package org.restcomm.connect.telephony.proxy; -import static javax.servlet.sip.SipServlet.OUTBOUND_INTERFACES; -import static javax.servlet.sip.SipServletResponse.SC_OK; -import static javax.servlet.sip.SipServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED; -import static javax.servlet.sip.SipServletResponse.SC_UNAUTHORIZED; - -import java.util.List; -import java.util.concurrent.TimeUnit; +import akka.actor.ActorContext; +import akka.actor.ReceiveTimeout; +import akka.event.Logging; +import akka.event.LoggingAdapter; +import org.joda.time.DateTime; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; +import org.restcomm.connect.dao.DaoManager; +import org.restcomm.connect.dao.GatewaysDao; +import org.restcomm.connect.dao.entities.Gateway; +import org.restcomm.connect.telephony.api.RegisterGateway; +import scala.concurrent.duration.Duration; import javax.servlet.ServletContext; import javax.servlet.sip.Address; @@ -37,25 +41,17 @@ import javax.servlet.sip.SipServletResponse; import javax.servlet.sip.SipSession; import javax.servlet.sip.SipURI; +import java.util.List; +import java.util.concurrent.TimeUnit; -import org.joda.time.DateTime; -import org.restcomm.connect.dao.DaoManager; -import org.restcomm.connect.dao.GatewaysDao; -import org.restcomm.connect.dao.entities.Gateway; -import org.restcomm.connect.telephony.api.RegisterGateway; - -import scala.concurrent.duration.Duration; -import akka.actor.ActorContext; -import akka.actor.ReceiveTimeout; -import akka.actor.UntypedActor; -import akka.event.Logging; -import akka.event.LoggingAdapter; +import static javax.servlet.sip.SipServlet.OUTBOUND_INTERFACES; +import static javax.servlet.sip.SipServletResponse.*; /** * @author quintana.thomas@gmail.com (Thomas Quintana) * @author gvagenas@gmail.com */ -public final class ProxyManager extends UntypedActor { +public final class ProxyManager extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); private static final int ttl = 1800; diff --git a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/ua/UserAgentManager.java b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/ua/UserAgentManager.java index ccb3b01982..c5c0cd7512 100644 --- a/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/ua/UserAgentManager.java +++ b/restcomm/restcomm.telephony/src/main/java/org/restcomm/connect/telephony/ua/UserAgentManager.java @@ -21,13 +21,13 @@ import akka.actor.ActorRef; import akka.actor.ReceiveTimeout; -import akka.actor.UntypedActor; import akka.event.Logging; import akka.event.LoggingAdapter; import org.apache.commons.configuration.Configuration; import org.joda.time.DateTime; import org.restcomm.connect.commons.configuration.RestcommConfiguration; import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.util.DigestAuthentication; import org.restcomm.connect.dao.ClientsDao; import org.restcomm.connect.dao.DaoManager; @@ -61,16 +61,14 @@ import static java.lang.Integer.parseInt; import static javax.servlet.sip.SipServlet.OUTBOUND_INTERFACES; -import static javax.servlet.sip.SipServletResponse.SC_OK; -import static javax.servlet.sip.SipServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED; -import static javax.servlet.sip.SipServletResponse.SC_UNAUTHORIZED; +import static javax.servlet.sip.SipServletResponse.*; import static org.restcomm.connect.commons.util.HexadecimalUtils.toHex; /** * @author quintana.thomas@gmail.com (Thomas Quintana) * @author jean.deruelle@telestax.com */ -public final class UserAgentManager extends UntypedActor { +public final class UserAgentManager extends RestcommUntypedActor { private static final int DEFAUL_IMS_PROXY_PORT = -1; private static final String REGISTER = "REGISTER"; private static final String REQ_PARAMETER = "Req"; diff --git a/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/faultTolerance/ActorFaultToleranceTest.java b/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/faultTolerance/ActorFaultToleranceTest.java deleted file mode 100644 index 315180ff9b..0000000000 --- a/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/faultTolerance/ActorFaultToleranceTest.java +++ /dev/null @@ -1,212 +0,0 @@ -package org.restcomm.connect.testsuite.faultTolerance; - -import akka.actor.ActorPath; -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.actor.Props; -import akka.actor.UntypedActor; -import akka.event.Logging; -import akka.event.LoggingAdapter; -import akka.testkit.JavaTestKit; -import com.typesafe.config.Config; -import com.typesafe.config.ConfigFactory; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import scala.concurrent.duration.Duration; - -import static akka.pattern.Patterns.ask; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -/** - * Created by gvagenas on 22/02/2017. - */ -public class ActorFaultToleranceTest { - - static ActorSystem system; - - @BeforeClass - public static void setup () { - Config config = ConfigFactory.load("akka_fault_tolerance_application.conf"); - system = ActorSystem.create("test", config ); - System.out.println(system.settings()); - } - - @AfterClass - public static void teardown () { - system.shutdown(); - } - - @Test - public void testIt () { - /* - * Wrap the whole test procedure within a testkit constructor - * if you want to receive actor replies or use Within(), etc. - */ - new JavaTestKit(system) {{ - final Props props = new Props(TestActor.class); - final ActorRef subject = system.actorOf(props); - - // can also use JavaTestKit “from the outside” - final JavaTestKit probe = new JavaTestKit(system); - // “inject” the probe by passing it to the test subject - // like a real resource would be passed in production - subject.tell(probe.getRef(), getRef()); - // await the correct response - expectMsgEquals(duration("1 second"), "done"); - - // the run() method needs to finish within 3 seconds - new Within(duration("3 seconds")) { - protected void run () { - - subject.tell("hello", getRef()); - - // This is a demo: would normally use expectMsgEquals(). - // Wait time is bounded by 3-second deadline above. - new AwaitCond() { - protected boolean cond () { - return probe.msgAvailable(); - } - }; - - // response must have been enqueued to us before probe - expectMsgEquals(Duration.Zero(), "world"); - // check that the probe we injected earlier got the msg - probe.expectMsgEquals(Duration.Zero(), "hello"); - assertEquals(getRef(), probe.getLastSender()); - - // Will wait for the rest of the 3 seconds - expectNoMsg(); - } - }; - }}; - } - - @Test - public void testException () throws Exception { - new JavaTestKit(system) {{ - LoggingAdapter logger = Logging.getLogger(system, this); - - final ActorRef subject = system.actorOf(new Props(TestActor.class)); - - subject.tell("exceptionMsgReceived", getRef()); - expectMsgEquals(duration("1 second"), false); - - ActorPath subjectPath = subject.path(); - int subjectHashCode = subject.hashCode(); - subject.tell("exception", getRef()); - expectMsgEquals(duration("1 second"), "I don't stop on exceptions"); - Thread.sleep(5000); - - //Verify Actor didn't restarted, if exceptionMsgReceived is TRUE that means the actor DID NOT restarted - subject.tell("exceptionMsgReceived", getRef()); - expectMsgEquals(duration("1 second"), true); - - system.stop(subject); - Thread.sleep(500); - assertTrue(subject.isTerminated()); - }}; - } - - @Test - public void testExceptionOnAchildActor () throws Exception { - new JavaTestKit(system) {{ - LoggingAdapter logger = Logging.getLogger(system, this); - - final ActorRef subject = system.actorOf(new Props(TestActor.class)); - - final ActorRef childActor = system.actorOf(new Props(TestActor2.class)); - - childActor.tell("exceptionMsgReceived", getRef()); - expectMsgEquals(duration("1 second"), false); - - childActor.tell("exception", getRef()); - ActorPath subjectPath = childActor.path(); - expectMsgEquals(duration("1 second"), "Me the TestActor2, I don't stop on exceptions"); - - //Verify Actor didn't restarted, if exceptionMsgReceived is TRUE that means the actor DID NOT restarted - Thread.sleep(5000); - childActor.tell("exceptionMsgReceived", getRef()); - expectMsgEquals(duration("1 second"), true); - }}; - } - - public static class TestActor extends UntypedActor { - - private LoggingAdapter logger = Logging.getLogger(getContext().system(), this); - ActorRef target = null; - boolean exceptionMsgReceived = false; - - public void onReceive (Object msg) { - final Class klass = msg.getClass(); - logger.info(" ********** TestActor " + self().path() + " Processing Message: " + klass.getName()); - - if (msg.equals("hello")) { - getSender().tell("world", getSelf()); - if (target != null) target.forward(msg, getContext()); - - } else if (msg.equals("exception")) { - exceptionMsgReceived = true; - getSender().tell("I don't stop on exceptions", getSelf()); - String s = null; - s.equalsIgnoreCase("blabla"); - } else if (msg.equals("exceptionMsgReceived")) { - sender().tell(exceptionMsgReceived, self()); - } else if (msg.equals("CreateChild")) { - final Props props = new Props(TestActor2.class); - final ActorRef actor2 = system.actorOf(props); - getSender().tell(actor2, self()); - } else if (msg instanceof ActorRef) { - target = (ActorRef) msg; - getSender().tell("done", getSelf()); - } - } - - @Override - public void postStop () { - logger.info("At postStop method"); - super.postStop(); - } - - @Override - public void postRestart (Throwable reason) { - logger.info("At postRestart method"); - super.postRestart(reason); - } - } - - public static class TestActor2 extends UntypedActor { - - private LoggingAdapter logger = Logging.getLogger(getContext().system(), this); - ActorRef target = null; - boolean exceptionMsgReceived = false; - - public void onReceive (Object msg) { - final Class klass = msg.getClass(); - logger.info(" ********** TestActor2 " + self().path() + " Processing Message: " + klass.getName()); - - if (msg.equals("exception")) { - exceptionMsgReceived = true; - getSender().tell("Me the TestActor2, I don't stop on exceptions", getSelf()); - String s = null; - s.equalsIgnoreCase("blabla"); - } else if (msg.equals("exceptionMsgReceived")) { - sender().tell(exceptionMsgReceived, self()); - } - } - - @Override - public void postStop () { - logger.info("TestActor2, at postStop method"); - super.postStop(); - } - - @Override - public void postRestart (Throwable reason) { - logger.info("TestActor2, at postRestart method"); - super.postRestart(reason); - } - } -} diff --git a/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/faultTolerance/ActorSupervisorStrategyTest.java b/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/faultTolerance/ActorSupervisorStrategyTest.java new file mode 100644 index 0000000000..a411c1bcb5 --- /dev/null +++ b/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/faultTolerance/ActorSupervisorStrategyTest.java @@ -0,0 +1,110 @@ +package org.restcomm.connect.testsuite.faultTolerance; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.testkit.JavaTestKit; +import akka.util.Timeout; +import com.typesafe.config.Config; +import com.typesafe.config.ConfigFactory; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; +import scala.concurrent.Await; +import scala.concurrent.Future; +import scala.concurrent.duration.Duration; + +import java.util.concurrent.TimeUnit; + +import static akka.pattern.Patterns.ask; +import static org.junit.Assert.assertTrue; + +/** + * @author oleg.agafonov@telestax.com (Oleg Agafonov) + */ +public class ActorSupervisorStrategyTest { + + static ActorSystem system; + + @BeforeClass + public static void setup() { + Config config = ConfigFactory.load("akka_fault_tolerance_application.conf"); + system = ActorSystem.create("test", config); + } + + @AfterClass + public static void teardown() { + system.shutdown(); + } + + @Test + public void parentActorThrowsExceptionTest() throws Exception { + new JavaTestKit(system) {{ + final ActorRef parent = system.actorOf(new Props(Parent.class)); + parent.tell("check exception", getRef()); + expectMsgEquals(duration("1 second"), false); + parent.tell("throw exception", getRef()); + Thread.sleep(5000); + parent.tell("check exception", getRef()); + expectMsgEquals(duration("1 second"), true); + }}; + } + + @Test + public void childActorThrowsExceptionTest() throws Exception { + new JavaTestKit(system) {{ + final ActorRef parent = system.actorOf(new Props(Parent.class)); + final Future future = ask(parent, "create child", new Timeout(Duration.create(5, TimeUnit.SECONDS))); + final ActorRef child = (ActorRef) Await.result(future, Duration.create(10, TimeUnit.SECONDS)); + + child.tell("check exception", getRef()); + expectMsgEquals(duration("1 second"), false); + child.tell("throw exception", getRef()); + Thread.sleep(5000); + child.tell("check exception", getRef()); + expectMsgEquals(duration("1 second"), true); + + system.stop(parent); + Thread.sleep(500); + assertTrue(parent.isTerminated()); + assertTrue(child.isTerminated()); + }}; + + } + + public static class Parent extends RestcommUntypedActor { + + private boolean receivedThrowException; + + @SuppressWarnings("Duplicates") + @Override + public void onReceive(Object message) throws Exception { + if ("create child".equals(message)) { + ActorRef child = getContext().actorOf(new Props(Child.class)); + sender().tell(child, self()); + } else if ("throw exception".equals(message)) { + this.receivedThrowException = true; + throw new RuntimeException(); + } else if ("check exception".equals(message)) { + sender().tell(receivedThrowException, self()); + } + } + } + + public static class Child extends RestcommUntypedActor { + + private boolean receivedThrowException; + + @SuppressWarnings("Duplicates") + @Override + public void onReceive(Object message) throws Exception { + if ("throw exception".equals(message)) { + this.receivedThrowException = true; + throw new RuntimeException(); + } else if ("check exception".equals(message)) { + sender().tell(receivedThrowException, self()); + } + } + } +} diff --git a/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/telephony/DialRecordingS3UploadTest_Secure.java b/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/telephony/DialRecordingS3UploadTest_Secure.java index 13dd1f0638..9f58594946 100644 --- a/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/telephony/DialRecordingS3UploadTest_Secure.java +++ b/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/telephony/DialRecordingS3UploadTest_Secure.java @@ -240,7 +240,7 @@ public synchronized void testDialClientAlice_BobDisconnects() throws Interrupted assertNotNull(recording); assertEquals(1, recording.size()); double duration = recording.get(0).getAsJsonObject().get("duration").getAsDouble(); - assertEquals(3.0, duration, 0); + assertEquals(3.0, duration, 1.0); assertTrue(recording.get(0).getAsJsonObject().get("file_uri").getAsString().startsWith("http://localhost:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings/")); //Since we are in secure mode the s3_uri shouldn't be here @@ -410,7 +410,7 @@ public synchronized void testRecordCall() throws InterruptedException, ParseExce assertNotNull(recording); assertEquals(1, recording.size()); double duration = recording.get(0).getAsJsonObject().get("duration").getAsDouble(); - assertEquals(6.0, duration,1); + assertEquals(3.0, duration,1); assertTrue(recording.get(0).getAsJsonObject().get("file_uri").getAsString().startsWith("http://localhost:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings/")); //Since we are in secure mode the s3_uri shouldn't be here @@ -487,7 +487,7 @@ public synchronized void testRecordCallWithAction() throws InterruptedException, assertNotNull(recording); assertEquals(1, recording.size()); double duration = recording.get(0).getAsJsonObject().get("duration").getAsDouble(); - assertEquals(6.0, duration,1); + assertEquals(3.0, duration,1); assertTrue(recording.get(0).getAsJsonObject().get("file_uri").getAsString().startsWith("http://localhost:8080/restcomm/2012-04-24/Accounts/ACae6e420f425248d6a26948c17a9e2acf/Recordings/")); //Since we are in secure mode the s3_uri shouldn't be here diff --git a/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/telephony/DialRecordingTest.java b/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/telephony/DialRecordingTest.java index 61ef5d27af..55e2ebc5ce 100644 --- a/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/telephony/DialRecordingTest.java +++ b/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/telephony/DialRecordingTest.java @@ -23,6 +23,7 @@ import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.spec.WebArchive; import org.jboss.shrinkwrap.resolver.api.maven.archive.ShrinkWrapMaven; +import org.joda.time.DateTime; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; @@ -222,7 +223,7 @@ public synchronized void testDialClientAlice_BobDisconnects() throws Interrupted assertNotNull(recording); assertEquals(1, recording.size()); double duration = recording.get(0).getAsJsonObject().get("duration").getAsDouble(); - assertEquals(3.0, duration, 0); + assertEquals(3.0, duration, 0.0); JsonObject metrics = MonitoringServiceTool.getInstance().getMetrics(deploymentUrl.toString(),adminAccountSid, adminAuthToken); assertNotNull(metrics); @@ -494,6 +495,7 @@ public synchronized void testRecordCallWithAction() throws InterruptedException, assertEquals(Response.OK, bobCall.getLastReceivedResponse().getStatusCode()); bobCall.sendInviteOkAck(); + DateTime start = DateTime.now(); assertTrue(!(bobCall.getLastReceivedResponse().getStatusCode() >= 400)); String callSid = bobCall.getLastReceivedResponse().getMessage().getHeader("X-RestComm-CallSid").toString().split(":")[1].trim().split("-")[1]; @@ -509,15 +511,90 @@ public synchronized void testRecordCallWithAction() throws InterruptedException, Thread.sleep(3000); bobCall.disconnect(); + DateTime end = DateTime.now(); - Thread.sleep(3000); + Thread.sleep(500); //Check recording JsonArray recording = RestcommCallsTool.getInstance().getCallRecordings(deploymentUrl.toString(),adminAccountSid,adminAuthToken,callSid); assertNotNull(recording); assertEquals(1, recording.size()); + double recordedDuration = (end.getMillis() - start.getMillis())/1000; double duration = recording.get(0).getAsJsonObject().get("duration").getAsDouble(); - assertEquals(3.0, duration,1); + assertEquals(recordedDuration, duration,0); + + logger.info("\n\n &&&&&& About to check liveCalls &&&&&& \n"); + + metrics = MonitoringServiceTool.getInstance().getMetrics(deploymentUrl.toString(),adminAccountSid, adminAuthToken); + assertNotNull(metrics); + liveCalls = metrics.getAsJsonObject("Metrics").get("LiveCalls").getAsInt(); + logger.info("LiveCalls: "+liveCalls); + liveCallsArraySize = metrics.getAsJsonArray("LiveCallDetails").size(); + logger.info("LiveCallsArraySize: "+liveCallsArraySize); + assertEquals(0,liveCalls); + assertEquals(0, liveCallsArraySize); + } + + @Test + public synchronized void testRecordCallWithActionWithMaxRecordingReached() throws InterruptedException, ParseException { + stubFor(get(urlPathEqualTo("/1111")) + .willReturn(aResponse() + .withStatus(200) + .withHeader("Content-Type", "text/xml") + .withBody(recordCallWithAction))); + + stubFor(post(urlPathEqualTo("/record-action")) + .willReturn(aResponse() + .withStatus(200) + .withHeader("Content-Type", "text/xml") + .withBody(hangupRcml))); + + // Create outgoing call with first phone + final SipCall bobCall = bobPhone.createSipCall(); + bobCall.initiateOutgoingCall(bobContact, dialRestcomm, null, body, "application", "sdp", null, null); + assertLastOperationSuccess(bobCall); + assertTrue(bobCall.waitOutgoingCallResponse(5 * 1000)); + final int response = bobCall.getLastReceivedResponse().getStatusCode(); + assertTrue(response == Response.TRYING || response == Response.RINGING); + + if (response == Response.TRYING) { + assertTrue(bobCall.waitOutgoingCallResponse(5 * 1000)); + assertEquals(Response.RINGING, bobCall.getLastReceivedResponse().getStatusCode()); + } + + assertTrue(bobCall.waitOutgoingCallResponse(5 * 1000)); + assertEquals(Response.OK, bobCall.getLastReceivedResponse().getStatusCode()); + + bobCall.sendInviteOkAck(); + DateTime start = DateTime.now(); + assertTrue(!(bobCall.getLastReceivedResponse().getStatusCode() >= 400)); + String callSid = bobCall.getLastReceivedResponse().getMessage().getHeader("X-RestComm-CallSid").toString().split(":")[1].trim().split("-")[1]; + + JsonObject metrics = MonitoringServiceTool.getInstance().getMetrics(deploymentUrl.toString(),adminAccountSid, adminAuthToken); + assertNotNull(metrics); + int liveCalls = metrics.getAsJsonObject("Metrics").get("LiveCalls").getAsInt(); + logger.info("LiveCalls: "+liveCalls); + int liveCallsArraySize = metrics.getAsJsonArray("LiveCallDetails").size(); + logger.info("LiveCallsArraySize: "+liveCallsArraySize); + assertEquals(1,liveCalls); + assertEquals(1, liveCallsArraySize); + + bobCall.listenForDisconnect(); + assertTrue(bobCall.waitForDisconnect(70000)); + assertTrue(bobCall.respondToDisconnect()); + DateTime end = DateTime.now(); + + Thread.sleep(500); + + //Check recording + JsonArray recording = RestcommCallsTool.getInstance().getCallRecordings(deploymentUrl.toString(),adminAccountSid,adminAuthToken,callSid); + assertNotNull(recording); + assertEquals(1, recording.size()); + double recordedDuration = (end.getMillis() - start.getMillis())/1000; + double duration = recording.get(0).getAsJsonObject().get("duration").getAsDouble(); + assertEquals(recordedDuration, duration,0); + + logger.info("\n\n &&&&&& About to check liveCalls &&&&&& \n"); metrics = MonitoringServiceTool.getInstance().getMetrics(deploymentUrl.toString(),adminAccountSid, adminAuthToken); assertNotNull(metrics); diff --git a/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/telephony/DialStatusCallbackTest.java b/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/telephony/DialStatusCallbackTest.java index 45f67819d2..5638a08080 100644 --- a/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/telephony/DialStatusCallbackTest.java +++ b/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/telephony/DialStatusCallbackTest.java @@ -52,7 +52,9 @@ import java.net.URL; import java.text.ParseException; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.findAll; @@ -640,7 +642,7 @@ public void testDialStatusCallbackOnlyRingingCompleted() throws ParseException, assertTrue(aliceCall.waitForDisconnect(5000)); assertTrue(aliceCall.respondToDisconnect()); - Thread.sleep(10000); + Thread.sleep(12000); logger.info("About to check the StatusCallback Requests"); List requests = findAll(postRequestedFor(urlPathMatching("/status.*"))); @@ -946,7 +948,7 @@ public synchronized void testDialForkNoAnswerButHenriqueStatusCallbackOnAll() th assertTrue(alicePhone.unregister(aliceContact, 3600)); - Thread.sleep(10000); + Thread.sleep(12000); logger.info("About to check the StatusCallback Requests"); List requests = findAll(getRequestedFor(urlPathMatching("/status.*"))); @@ -1094,7 +1096,7 @@ public synchronized void testDialForkNoAnswerButHenriqueStatusCallbackOnAllPost( assertTrue(alicePhone.unregister(aliceContact, 3600)); - Thread.sleep(10000); + Thread.sleep(12000); logger.info("About to check the StatusCallback Requests"); List requests = findAll(postRequestedFor(urlPathMatching("/status.*"))); @@ -1578,9 +1580,32 @@ public synchronized void testDialForkNoAnswerExecuteRCML_ReturnedFromActionURLWi logger.info("About to check the StatusCallback Requests"); requests = findAll(getRequestedFor(urlPathMatching("/status.*"))); + Map requestMap = getRequestMap(requests); assertEquals(13, requests.size()); } + private Map getRequestMap(final List requestList) { + Map resultMap = new HashMap(); + for(LoggedRequest request: requestList) { + String[] tokens = request.getUrl().split("&"); + String to = null; + String callStatus = null; + for (String token: tokens) { + if (token.contains("To")) { + to = token; + } + if (token.contains("SequenceNumber")) { + to = to+token; + } + if (token.contains("CallStatus")) { + callStatus = token; + } + } + resultMap.put(to,callStatus); + } + return resultMap; + } + @Deployment(name = "DialAction", managed = true, testable = false) public static WebArchive createWebArchiveNoGw() { logger.info("Packaging Test App"); diff --git a/restcomm/restcomm.tts.acapela/src/main/java/org/restcomm/connect/tts/acapela/AcapelaSpeechSynthesizer.java b/restcomm/restcomm.tts.acapela/src/main/java/org/restcomm/connect/tts/acapela/AcapelaSpeechSynthesizer.java index 0bd6b2c374..398229d9ef 100644 --- a/restcomm/restcomm.tts.acapela/src/main/java/org/restcomm/connect/tts/acapela/AcapelaSpeechSynthesizer.java +++ b/restcomm/restcomm.tts.acapela/src/main/java/org/restcomm/connect/tts/acapela/AcapelaSpeechSynthesizer.java @@ -19,13 +19,9 @@ */ package org.restcomm.connect.tts.acapela; -import java.io.IOException; -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - +import akka.actor.ActorRef; +import akka.event.Logging; +import akka.event.LoggingAdapter; import org.apache.commons.configuration.Configuration; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; @@ -37,22 +33,25 @@ import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.restcomm.connect.commons.cache.HashGenerator; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; +import org.restcomm.connect.commons.util.HttpUtils; import org.restcomm.connect.tts.api.GetSpeechSynthesizerInfo; import org.restcomm.connect.tts.api.SpeechSynthesizerException; import org.restcomm.connect.tts.api.SpeechSynthesizerInfo; import org.restcomm.connect.tts.api.SpeechSynthesizerRequest; import org.restcomm.connect.tts.api.SpeechSynthesizerResponse; -import org.restcomm.connect.commons.util.HttpUtils; -import akka.actor.ActorRef; -import akka.actor.UntypedActor; -import akka.event.Logging; -import akka.event.LoggingAdapter; +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ -public final class AcapelaSpeechSynthesizer extends UntypedActor { +public final class AcapelaSpeechSynthesizer extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); diff --git a/restcomm/restcomm.tts.att/src/main/java/org/restcomm/connect/tts/att/AttSpeechSynthesizer.java b/restcomm/restcomm.tts.att/src/main/java/org/restcomm/connect/tts/att/AttSpeechSynthesizer.java index 2a914345ce..515bff6b69 100644 --- a/restcomm/restcomm.tts.att/src/main/java/org/restcomm/connect/tts/att/AttSpeechSynthesizer.java +++ b/restcomm/restcomm.tts.att/src/main/java/org/restcomm/connect/tts/att/AttSpeechSynthesizer.java @@ -20,33 +20,31 @@ package org.restcomm.connect.tts.att; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - +import akka.actor.ActorRef; +import akka.event.Logging; +import akka.event.LoggingAdapter; import naturalvoices.ClientPlayer; import naturalvoices.Player; - import org.apache.commons.configuration.Configuration; import org.restcomm.connect.commons.cache.HashGenerator; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.tts.api.GetSpeechSynthesizerInfo; import org.restcomm.connect.tts.api.SpeechSynthesizerException; import org.restcomm.connect.tts.api.SpeechSynthesizerInfo; import org.restcomm.connect.tts.api.SpeechSynthesizerRequest; import org.restcomm.connect.tts.api.SpeechSynthesizerResponse; -import akka.actor.ActorRef; -import akka.actor.UntypedActor; -import akka.event.Logging; -import akka.event.LoggingAdapter; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * @author gvagenas * */ -public final class AttSpeechSynthesizer extends UntypedActor { +public final class AttSpeechSynthesizer extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); private final Map men; diff --git a/restcomm/restcomm.tts.awspolly/src/main/java/org/restcomm/connect/tts/awspolly/AWSPollySpeechSyntetizer.java b/restcomm/restcomm.tts.awspolly/src/main/java/org/restcomm/connect/tts/awspolly/AWSPollySpeechSyntetizer.java index b281e7a1df..278915fed3 100644 --- a/restcomm/restcomm.tts.awspolly/src/main/java/org/restcomm/connect/tts/awspolly/AWSPollySpeechSyntetizer.java +++ b/restcomm/restcomm.tts.awspolly/src/main/java/org/restcomm/connect/tts/awspolly/AWSPollySpeechSyntetizer.java @@ -20,7 +20,6 @@ package org.restcomm.connect.tts.awspolly; import akka.actor.ActorRef; -import akka.actor.UntypedActor; import akka.event.Logging; import akka.event.LoggingAdapter; import com.amazonaws.auth.AWSCredentials; @@ -32,15 +31,9 @@ import com.amazonaws.services.polly.model.SynthesizeSpeechRequest; import com.amazonaws.services.polly.model.SynthesizeSpeechResult; import com.amazonaws.services.polly.model.VoiceId; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; -import java.util.HashMap; -import java.util.Map; import org.apache.commons.configuration.Configuration; import org.restcomm.connect.commons.cache.HashGenerator; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.util.PcmToWavConverterUtils; import org.restcomm.connect.tts.api.GetSpeechSynthesizerInfo; import org.restcomm.connect.tts.api.SpeechSynthesizerException; @@ -48,10 +41,18 @@ import org.restcomm.connect.tts.api.SpeechSynthesizerRequest; import org.restcomm.connect.tts.api.SpeechSynthesizerResponse; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.HashMap; +import java.util.Map; + /** * @author ricardo.limonta@gmail.com (Ricardo Limonta) */ -public class AWSPollySpeechSyntetizer extends UntypedActor { +public class AWSPollySpeechSyntetizer extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); private final AmazonPollyClient pollyClient; diff --git a/restcomm/restcomm.tts.voicerss/src/main/java/org/restcomm/connect/tts/voicerss/VoiceRSSSpeechSynthesizer.java b/restcomm/restcomm.tts.voicerss/src/main/java/org/restcomm/connect/tts/voicerss/VoiceRSSSpeechSynthesizer.java index ed99312e4e..81bb199d9b 100644 --- a/restcomm/restcomm.tts.voicerss/src/main/java/org/restcomm/connect/tts/voicerss/VoiceRSSSpeechSynthesizer.java +++ b/restcomm/restcomm.tts.voicerss/src/main/java/org/restcomm/connect/tts/voicerss/VoiceRSSSpeechSynthesizer.java @@ -19,17 +19,9 @@ */ package org.restcomm.connect.tts.voicerss; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - +import akka.actor.ActorRef; +import akka.event.Logging; +import akka.event.LoggingAdapter; import org.apache.commons.configuration.Configuration; import org.apache.http.Header; import org.apache.http.HttpResponse; @@ -43,21 +35,28 @@ import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.restcomm.connect.commons.cache.HashGenerator; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.tts.api.GetSpeechSynthesizerInfo; import org.restcomm.connect.tts.api.SpeechSynthesizerException; import org.restcomm.connect.tts.api.SpeechSynthesizerInfo; import org.restcomm.connect.tts.api.SpeechSynthesizerRequest; import org.restcomm.connect.tts.api.SpeechSynthesizerResponse; -import akka.actor.ActorRef; -import akka.actor.UntypedActor; -import akka.event.Logging; -import akka.event.LoggingAdapter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * @author gvagenas@gmail.com (George Vagenas) */ -public final class VoiceRSSSpeechSynthesizer extends UntypedActor { +public final class VoiceRSSSpeechSynthesizer extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); diff --git a/restcomm/restcomm.ui/src/main/webapp/conf/dashboard.json b/restcomm/restcomm.ui/src/main/webapp/conf/dashboard.json index 9c281b5a75..853a4c11b9 100644 --- a/restcomm/restcomm.ui/src/main/webapp/conf/dashboard.json +++ b/restcomm/restcomm.ui/src/main/webapp/conf/dashboard.json @@ -1,3 +1,4 @@ { - "resetPasswordUrl": "" + "resetPasswordUrl": "", + "rvdUrl":"/restcomm-rvd" } \ No newline at end of file diff --git a/restcomm/restcomm.ui/src/main/webapp/lib/jquery/README.md b/restcomm/restcomm.ui/src/main/webapp/lib/jquery/README.md index 328064b7b6..30b8381af3 100755 --- a/restcomm/restcomm.ui/src/main/webapp/lib/jquery/README.md +++ b/restcomm/restcomm.ui/src/main/webapp/lib/jquery/README.md @@ -1,3 +1,10 @@ +RestComm +======== +[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2FRestComm%2FRestcomm-Connect.svg?type=shield)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2FRestComm%2FRestcomm-Connect?ref=badge_shield) + +RestComm is licensed under dual license policy. The default license is the Free Open Source GNU Affero GPL v3.0. Alternatively a commercial license can be obtained from Telestax ([contact form](http://www.telestax.com/contactus/#InquiryForm)) + +[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2FRestComm%2FRestcomm-Connect.svg?type=large)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2FRestComm%2FRestcomm-Connect?ref=badge_large) jQuery Component ================ diff --git a/restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/interpreter/UssdInterpreter.java b/restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/interpreter/UssdInterpreter.java index ed4a074577..0eaf9dbf69 100644 --- a/restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/interpreter/UssdInterpreter.java +++ b/restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/interpreter/UssdInterpreter.java @@ -22,14 +22,12 @@ import akka.actor.Actor; import akka.actor.ActorRef; -import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.UntypedActor; import akka.actor.UntypedActorContext; import akka.actor.UntypedActorFactory; import akka.event.Logging; import akka.event.LoggingAdapter; - import org.apache.commons.configuration.Configuration; import org.apache.http.HttpStatus; import org.apache.http.NameValuePair; @@ -38,6 +36,7 @@ import org.joda.time.DateTime; import org.restcomm.connect.commons.configuration.RestcommConfiguration; import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.fsm.Action; import org.restcomm.connect.commons.fsm.FiniteStateMachine; import org.restcomm.connect.commons.fsm.State; @@ -69,7 +68,6 @@ import org.restcomm.connect.telephony.api.CallInfo; import org.restcomm.connect.telephony.api.CallResponse; import org.restcomm.connect.telephony.api.CallStateChanged; - import org.restcomm.connect.telephony.api.GetCallInfo; import org.restcomm.connect.ussd.commons.UssdInfoRequest; import org.restcomm.connect.ussd.commons.UssdMessageType; @@ -77,7 +75,6 @@ import javax.servlet.sip.SipServletRequest; import javax.servlet.sip.SipServletResponse; - import java.io.IOException; import java.math.BigDecimal; import java.net.URI; @@ -92,19 +89,16 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.regex.Pattern; -import static org.restcomm.connect.interpreter.rcml.Verbs.ussdCollect; -import static org.restcomm.connect.interpreter.rcml.Verbs.ussdLanguage; -import static org.restcomm.connect.interpreter.rcml.Verbs.ussdMessage; +import static org.restcomm.connect.interpreter.rcml.Verbs.*; /** * @author gvagenas */ -public class UssdInterpreter extends UntypedActor { +public class UssdInterpreter extends RestcommUntypedActor { // Logger. private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); - private final ActorSystem system; static final int ERROR_NOTIFICATION = 0; static final int WARNING_NOTIFICATION = 1; static final Pattern PATTERN = Pattern.compile("[\\*#0-9]{1,12}"); @@ -174,13 +168,9 @@ public class UssdInterpreter extends UntypedActor { private final State ready; private final State notFound; - public UssdInterpreter(final Configuration configuration, final Sid account, final Sid phone, final String version, - final URI url, final String method, final URI fallbackUrl, final String fallbackMethod, final URI statusCallback, - final String statusCallbackMethod, final String emailAddress, final ActorRef callManager, - final ActorRef conferenceManager, final ActorRef sms, final DaoManager storage) { + public UssdInterpreter(final UssdInterpreterParams params) { super(); final ActorRef source = self(); - this.system = context().system(); uninitialized = new State("uninitialized", null, null); observeCall = new State("observe call", new ObserveCall(source), null); @@ -221,19 +211,19 @@ public UssdInterpreter(final Configuration configuration, final Sid account, fin // Initialize the FSM. this.fsm = new FiniteStateMachine(uninitialized, transitions); // Initialize the runtime stuff. - this.accountId = account; - this.phoneId = phone; - this.version = version; - this.url = url; - this.method = method; - this.fallbackUrl = fallbackUrl; - this.fallbackMethod = fallbackMethod; - this.statusCallback = statusCallback; - this.statusCallbackMethod = statusCallbackMethod; - this.emailAddress = emailAddress; - this.configuration = configuration; - - this.storage = storage; + this.accountId = params.getAccount(); + this.phoneId = params.getPhone(); + this.version = params.getVersion(); + this.url = params.getUrl(); + this.method = params.getMethod(); + this.fallbackUrl = params.getFallbackUrl(); + this.fallbackMethod = params.getFallbackMethod(); + this.statusCallback = params.getStatusCallback(); + this.statusCallbackMethod = params.getStatusCallbackMethod(); + this.emailAddress = params.getEmailAddress(); + this.configuration = params.getConfiguration(); + + this.storage = params.getStorage(); final Configuration runtime = configuration.subset("runtime-settings"); String path = runtime.getString("cache-path"); if (!path.endsWith("/")) { @@ -243,6 +233,15 @@ public UssdInterpreter(final Configuration configuration, final Sid account, fin this.downloader = downloader(); } + public static Props props(final UssdInterpreterParams params) { + return new Props(new UntypedActorFactory() { + @Override + public Actor create() throws Exception { + return new UssdInterpreter(params); + } + }); + } + private Notification notification(final int log, final int error, final String message) { final Notification.Builder builder = Notification.builder(); final Sid sid = Sid.generate(Sid.Type.NOTIFICATION); @@ -300,7 +299,7 @@ public Actor create() throws Exception { return new EmailService(configuration); } }); - return system.actorOf(props); + return getContext().actorOf(props); } ActorRef downloader() { @@ -311,7 +310,7 @@ public UntypedActor create() throws Exception { return new Downloader(); } }); - return system.actorOf(props); + return getContext().actorOf(props); } ActorRef parser(final String xml) { @@ -323,7 +322,7 @@ public UntypedActor create() throws Exception { return new Parser(xml, self()); } }); - return system.actorOf(props); + return getContext().actorOf(props); } void invalidVerb(final Tag verb) { diff --git a/restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/interpreter/UssdInterpreterBuilder.java b/restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/interpreter/UssdInterpreterBuilder.java deleted file mode 100644 index 31290f9daf..0000000000 --- a/restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/interpreter/UssdInterpreterBuilder.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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.ussd.interpreter; - -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.actor.Props; -import akka.actor.UntypedActor; -import akka.actor.UntypedActorFactory; -import org.apache.commons.configuration.Configuration; -import org.apache.log4j.Logger; -import org.restcomm.connect.commons.dao.Sid; -import org.restcomm.connect.dao.DaoManager; - -import java.net.URI; - -/** - * @author gvagenas - */ -public class UssdInterpreterBuilder { - - private static Logger logger = Logger.getLogger(UssdInterpreterBuilder.class); - private final ActorSystem system; - private Configuration configuration; - private DaoManager storage; - private ActorRef calls; - private ActorRef conferences; - private ActorRef sms; - private Sid account; - private Sid phone; - private String version; - private URI url; - private String method; - private URI fallbackUrl; - private String fallbackMethod; - private URI statusCallback; - private String statusCallbackMethod; - private String emailAddress; - - public UssdInterpreterBuilder(ActorSystem system) { - this.system = system; - } - - public ActorRef build() { - final Props props = new Props(new UntypedActorFactory() { - private static final long serialVersionUID = 1L; - @Override - public UntypedActor create() throws Exception { - return new UssdInterpreter(configuration, account, phone, version, url, method, fallbackUrl, fallbackMethod, - statusCallback, statusCallbackMethod, emailAddress, calls, conferences, sms, storage); - } - }); - return system.actorOf(props); - } - - public void setConfiguration(final Configuration configuration) { - this.configuration = configuration; - } - - public void setStorage(final DaoManager storage) { - this.storage = storage; - } - - public void setCallManager(final ActorRef calls) { - this.calls = calls; - } - - public void setAccount(final Sid account) { - this.account = account; - } - - public void setPhone(final Sid phone) { - this.phone = phone; - } - - public void setUrl(final URI url) { - this.url = url; - } - - public void setMethod(final String method) { - this.method = method; - } - - public void setFallbackUrl(final URI fallbackUrl) { - this.fallbackUrl = fallbackUrl; - } - - public void setFallbackMethod(final String fallbackMethod) { - this.fallbackMethod = fallbackMethod; - } - - public void setStatusCallback(final URI statusCallback) { - this.statusCallback = statusCallback; - } - - public void setStatusCallbackMethod(final String statusCallbackMethod) { - this.statusCallbackMethod = statusCallbackMethod; - } - - public void setEmailAddress(final String emailAddress) { - this.emailAddress = emailAddress; - } - - public void setVersion(final String version) { - this.version = version; - } - -} diff --git a/restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/interpreter/UssdInterpreterParams.java b/restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/interpreter/UssdInterpreterParams.java new file mode 100644 index 0000000000..a35369542e --- /dev/null +++ b/restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/interpreter/UssdInterpreterParams.java @@ -0,0 +1,202 @@ +/* + * 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.ussd.interpreter; + +import akka.actor.ActorRef; +import org.apache.commons.configuration.Configuration; +import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.dao.DaoManager; + +import java.net.URI; + +/** + * @author oleg.agafonov@telestax.com (Oleg Agafonov) + */ +public final class UssdInterpreterParams { + + private Configuration configuration; + private DaoManager storage; + private ActorRef sms; + private Sid account; + private Sid phone; + private String version; + private URI url; + private String method; + private URI fallbackUrl; + private String fallbackMethod; + private URI statusCallback; + private String statusCallbackMethod; + private String emailAddress; + + public Configuration getConfiguration() { + return configuration; + } + + public DaoManager getStorage() { + return storage; + } + + public ActorRef getSms() { + return sms; + } + + public Sid getAccount() { + return account; + } + + public Sid getPhone() { + return phone; + } + + public String getVersion() { + return version; + } + + public URI getUrl() { + return url; + } + + public String getMethod() { + return method; + } + + public URI getFallbackUrl() { + return fallbackUrl; + } + + public String getFallbackMethod() { + return fallbackMethod; + } + + public URI getStatusCallback() { + return statusCallback; + } + + public String getStatusCallbackMethod() { + return statusCallbackMethod; + } + + public String getEmailAddress() { + return emailAddress; + } + + private UssdInterpreterParams(Configuration configuration, DaoManager storage, ActorRef callManager, ActorRef sms, Sid account, Sid phone, String version, URI url, String method, URI fallbackUrl, String fallbackMethod, URI statusCallback, String statusCallbackMethod, String emailAddress) { + this.configuration = configuration; + this.storage = storage; + this.sms = sms; + this.account = account; + this.phone = phone; + this.version = version; + this.url = url; + this.method = method; + this.fallbackUrl = fallbackUrl; + this.fallbackMethod = fallbackMethod; + this.statusCallback = statusCallback; + this.statusCallbackMethod = statusCallbackMethod; + this.emailAddress = emailAddress; + } + + public static final class Builder { + private Configuration configuration; + private DaoManager storage; + private ActorRef callManager; + private ActorRef sms; + private Sid account; + private Sid phone; + private String version; + private URI url; + private String method; + private URI fallbackUrl; + private String fallbackMethod; + private URI statusCallback; + private String statusCallbackMethod; + private String emailAddress; + + public Builder setConfiguration(Configuration configuration) { + this.configuration = configuration; + return this; + } + + public Builder setStorage(DaoManager storage) { + this.storage = storage; + return this; + } + + public Builder setSms(ActorRef sms) { + this.sms = sms; + return this; + } + + public Builder setAccount(Sid account) { + this.account = account; + return this; + } + + public Builder setPhone(Sid phone) { + this.phone = phone; + return this; + } + + public Builder setVersion(String version) { + this.version = version; + return this; + } + + public Builder setUrl(URI url) { + this.url = url; + return this; + } + + public Builder setMethod(String method) { + this.method = method; + return this; + } + + public Builder setFallbackUrl(URI fallbackUrl) { + this.fallbackUrl = fallbackUrl; + return this; + } + + public Builder setFallbackMethod(String fallbackMethod) { + this.fallbackMethod = fallbackMethod; + return this; + } + + public Builder setStatusCallback(URI statusCallback) { + this.statusCallback = statusCallback; + return this; + } + + public Builder setStatusCallbackMethod(String statusCallbackMethod) { + this.statusCallbackMethod = statusCallbackMethod; + return this; + } + + public Builder setEmailAddress(String emailAddress) { + this.emailAddress = emailAddress; + return this; + } + + public UssdInterpreterParams build() { + return new UssdInterpreterParams(configuration, storage, callManager, sms, account, phone, version, url, method, fallbackUrl, fallbackMethod, statusCallback, statusCallbackMethod, emailAddress); + } + } +} diff --git a/restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/telephony/UssdCall.java b/restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/telephony/UssdCall.java index c6a5db6460..c57e0d5fee 100644 --- a/restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/telephony/UssdCall.java +++ b/restcomm/restcomm.ussd/src/main/java/org/restcomm/connect/ussd/telephony/UssdCall.java @@ -19,37 +19,14 @@ */ package org.restcomm.connect.ussd.telephony; -import java.math.BigDecimal; -import java.net.InetAddress; -import java.net.URI; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Currency; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.concurrent.TimeUnit; - -import javax.servlet.sip.Address; -import javax.servlet.sip.ServletParseException; -import javax.servlet.sip.SipApplicationSession; -import javax.servlet.sip.SipFactory; -import javax.servlet.sip.SipServletMessage; -import javax.servlet.sip.SipServletRequest; -import javax.servlet.sip.SipServletResponse; -import javax.servlet.sip.SipSession; -import javax.servlet.sip.SipURI; - +import akka.actor.ActorRef; +import akka.actor.UntypedActorContext; +import akka.event.Logging; +import akka.event.LoggingAdapter; import org.joda.time.DateTime; import org.restcomm.connect.commons.configuration.RestcommConfiguration; -import org.restcomm.connect.dao.CallDetailRecordsDao; -import org.restcomm.connect.dao.entities.CallDetailRecord; import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.fsm.Action; import org.restcomm.connect.commons.fsm.FiniteStateMachine; import org.restcomm.connect.commons.fsm.State; @@ -58,29 +35,49 @@ import org.restcomm.connect.commons.patterns.Observing; import org.restcomm.connect.commons.patterns.StopObserving; import org.restcomm.connect.commons.telephony.CreateCallType; +import org.restcomm.connect.dao.CallDetailRecordsDao; +import org.restcomm.connect.dao.entities.CallDetailRecord; import org.restcomm.connect.telephony.api.Answer; import org.restcomm.connect.telephony.api.CallInfo; import org.restcomm.connect.telephony.api.CallResponse; import org.restcomm.connect.telephony.api.CallStateChanged; - import org.restcomm.connect.telephony.api.GetCallInfo; import org.restcomm.connect.telephony.api.GetCallObservers; import org.restcomm.connect.telephony.api.InitializeOutbound; import org.restcomm.connect.ussd.commons.UssdRestcommResponse; import org.restcomm.connect.ussd.interpreter.UssdInterpreter; - -import akka.actor.ActorRef; -import akka.actor.UntypedActor; -import akka.actor.UntypedActorContext; -import akka.event.Logging; -import akka.event.LoggingAdapter; import scala.concurrent.duration.Duration; +import javax.servlet.sip.Address; +import javax.servlet.sip.ServletParseException; +import javax.servlet.sip.SipApplicationSession; +import javax.servlet.sip.SipFactory; +import javax.servlet.sip.SipServletMessage; +import javax.servlet.sip.SipServletRequest; +import javax.servlet.sip.SipServletResponse; +import javax.servlet.sip.SipSession; +import javax.servlet.sip.SipURI; +import java.math.BigDecimal; +import java.net.InetAddress; +import java.net.URI; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Currency; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.concurrent.TimeUnit; + /** * @author gvagenas * */ -public class UssdCall extends UntypedActor { +public class UssdCall extends RestcommUntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); 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 625ac02ebb..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 @@ -20,14 +20,16 @@ package org.restcomm.connect.ussd.telephony; import akka.actor.ActorRef; -import akka.actor.ActorSystem; import akka.actor.Props; import akka.actor.UntypedActor; import akka.actor.UntypedActorFactory; 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; import org.restcomm.connect.dao.AccountsDao; import org.restcomm.connect.dao.ApplicationsDao; @@ -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; @@ -43,7 +46,7 @@ import org.restcomm.connect.telephony.api.InitializeOutbound; import org.restcomm.connect.telephony.api.util.CallControlHelper; import org.restcomm.connect.ussd.interpreter.UssdInterpreter; -import org.restcomm.connect.ussd.interpreter.UssdInterpreterBuilder; +import org.restcomm.connect.ussd.interpreter.UssdInterpreterParams; import javax.servlet.ServletContext; import javax.servlet.sip.ServletParseException; @@ -57,14 +60,12 @@ import java.util.regex.Pattern; import static javax.servlet.sip.SipServlet.OUTBOUND_INTERFACES; -import static javax.servlet.sip.SipServletResponse.SC_BAD_REQUEST; -import static javax.servlet.sip.SipServletResponse.SC_NOT_FOUND; -import static javax.servlet.sip.SipServletResponse.SC_OK; +import static javax.servlet.sip.SipServletResponse.*; /** * @author gvagenas */ -public class UssdCallManager extends UntypedActor { +public class UssdCallManager extends RestcommUntypedActor { static final int ERROR_NOTIFICATION = 0; static final int WARNING_NOTIFICATION = 1; @@ -85,8 +86,6 @@ public class UssdCallManager extends UntypedActor { private final LoggingAdapter logger = Logging.getLogger(getContext().system(), this); - private final ActorSystem system; - /** * @param configuration * @param context @@ -95,10 +94,8 @@ public class UssdCallManager extends UntypedActor { * @param factory * @param storage */ - public UssdCallManager(final ActorSystem system, Configuration configuration, ServletContext context, - ActorRef conferences, ActorRef sms, SipFactory factory, DaoManager storage) { + public UssdCallManager(Configuration configuration, ServletContext context, SipFactory factory, DaoManager storage) { super(); - this.system = system; this.configuration = configuration; this.context = context; this.sipFactory = factory; @@ -113,12 +110,13 @@ public UssdCallManager(final ActorSystem system, Configuration configuration, Se private ActorRef ussdCall() { final Props props = new Props(new UntypedActorFactory() { private static final long serialVersionUID = 1L; + @Override public UntypedActor create() throws Exception { return new UssdCall(sipFactory); } }); - return system.actorOf(props); + return getContext().actorOf(props); } private void check(final Object message) throws IOException { @@ -148,9 +146,9 @@ public void onReceive(final Object message) throws Exception { processRequest(request); } else if ("ACK".equalsIgnoreCase(method)) { processRequest(request); - } else if("BYE".equalsIgnoreCase(method)) { + } else if ("BYE".equalsIgnoreCase(method)) { processRequest(request); - } else if("CANCEL".equalsIgnoreCase(method)) { + } else if ("CANCEL".equalsIgnoreCase(method)) { processRequest(request); } } else if (message instanceof SipServletResponse) { @@ -181,7 +179,7 @@ private void invite(final Object message) throws Exception { final AccountsDao accounts = storage.getAccountsDao(); final ApplicationsDao applications = storage.getApplicationsDao(); final String toUser = CallControlHelper.getUserSipId(request, useTo); - if (redirectToHostedVoiceApp(self, request, accounts, applications, toUser)){ + if (redirectToHostedVoiceApp(self, request, accounts, applications, toUser)) { return; } @@ -202,7 +200,7 @@ private void invite(final Object message) throws Exception { * @throws Exception */ private boolean redirectToHostedVoiceApp(final ActorRef self, final SipServletRequest request, final AccountsDao accounts, - final ApplicationsDao applications, String id) throws Exception { + final ApplicationsDao applications, String id) throws Exception { boolean isFoundHostedApp = false; final IncomingPhoneNumbersDao numbersDao = storage.getIncomingPhoneNumbersDao(); @@ -212,10 +210,9 @@ private boolean redirectToHostedVoiceApp(final ActorRef self, final SipServletRe // This is a USSD Invite number = numbersDao.getIncomingPhoneNumber(id); if (number != null) { - final UssdInterpreterBuilder builder = new UssdInterpreterBuilder(system); + final UssdInterpreterParams.Builder builder = new UssdInterpreterParams.Builder(); builder.setConfiguration(configuration); builder.setStorage(storage); - builder.setCallManager(self); builder.setAccount(number.getAccountSid()); builder.setVersion(number.getApiVersion()); final Account account = accounts.getAccount(number.getAccountSid()); @@ -223,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())); } @@ -238,14 +237,15 @@ private boolean redirectToHostedVoiceApp(final ActorRef self, final SipServletRe builder.setFallbackMethod(number.getUssdFallbackMethod()); builder.setStatusCallback(number.getStatusCallback()); builder.setStatusCallbackMethod(number.getStatusCallbackMethod()); - final ActorRef ussdInterpreter = builder.build(); + final Props props = UssdInterpreter.props(builder.build()); + final ActorRef ussdInterpreter = getContext().actorOf(props); final ActorRef ussdCall = ussdCall(); ussdCall.tell(request, self); ussdInterpreter.tell(new StartInterpreter(ussdCall), self); SipApplicationSession applicationSession = request.getApplicationSession(); - applicationSession.setAttribute("UssdCall","true"); + applicationSession.setAttribute("UssdCall", "true"); applicationSession.setAttribute(UssdInterpreter.class.getName(), ussdInterpreter); applicationSession.setAttribute(UssdCall.class.getName(), ussdCall); isFoundHostedApp = true; @@ -259,8 +259,8 @@ private boolean redirectToHostedVoiceApp(final ActorRef self, final SipServletRe private void processRequest(SipServletRequest request) throws IOException { final ActorRef ussdInterpreter = (ActorRef) request.getApplicationSession().getAttribute(UssdInterpreter.class.getName()); - if(ussdInterpreter != null) { - logger.info("Dispatching Request: "+request.getMethod()+" to UssdInterpreter: "+ussdInterpreter); + if (ussdInterpreter != null) { + logger.info("Dispatching Request: " + request.getMethod() + " to UssdInterpreter: " + ussdInterpreter); ussdInterpreter.tell(request, self()); } else { final SipServletResponse notFound = request.createResponse(SipServletResponse.SC_NOT_FOUND); @@ -275,8 +275,8 @@ private ActorRef outbound(final Object message) throws ServletParseException { final String ussdUsername = (request.username() != null) ? request.username() : ussdGatewayUsername; final String ussdPassword = (request.password() != null) ? request.password() : ussdGatewayPassword; - SipURI from = (SipURI)sipFactory.createSipURI(request.from(), uri); - SipURI to = (SipURI)sipFactory.createSipURI(request.to(), uri); + SipURI from = (SipURI) sipFactory.createSipURI(request.from(), uri); + SipURI to = (SipURI) sipFactory.createSipURI(request.to(), uri); String transport = (to.getTransportParam() != null) ? to.getTransportParam() : "udp"; //from = outboundInterface(transport); @@ -293,8 +293,7 @@ private ActorRef outbound(final Object message) throws ServletParseException { private SipURI outboundInterface(String transport) { SipURI result = null; - @SuppressWarnings("unchecked") - final List uris = (List) context.getAttribute(OUTBOUND_INTERFACES); + @SuppressWarnings("unchecked") final List uris = (List) context.getAttribute(OUTBOUND_INTERFACES); for (final SipURI uri : uris) { final String interfaceTransport = uri.getTransportParam(); if (transport.equalsIgnoreCase(interfaceTransport)) { @@ -307,17 +306,17 @@ private SipURI outboundInterface(String transport) { private void execute(final Object message) { final ExecuteCallScript request = (ExecuteCallScript) message; final ActorRef self = self(); - final UssdInterpreterBuilder builder = new UssdInterpreterBuilder(system); + final UssdInterpreterParams.Builder builder = new UssdInterpreterParams.Builder(); builder.setConfiguration(configuration); builder.setStorage(storage); - builder.setCallManager(self); builder.setAccount(request.account()); builder.setVersion(request.version()); builder.setUrl(request.url()); builder.setMethod(request.method()); builder.setFallbackUrl(request.fallbackUrl()); builder.setFallbackMethod(request.fallbackMethod()); - final ActorRef interpreter = builder.build(); + final Props props = UssdInterpreter.props(builder.build()); + final ActorRef interpreter = getContext().actorOf(props); interpreter.tell(new StartInterpreter(request.call()), self); } From 80e3d7e0f12d2cabbe59f1055df7b53b53df446c Mon Sep 17 00:00:00 2001 From: George Vagenas Date: Tue, 18 Jul 2017 15:14:24 +0300 Subject: [PATCH 05/34] Minor Fix --- .../java/org/restcomm/connect/interpreter/VoiceInterpreter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java index a407f9a6ff..ba979c64f8 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java @@ -224,7 +224,7 @@ public class VoiceInterpreter extends BaseVoiceInterpreter { private String conferenceNameWithAccountAndFriendlyName; private Sid callSid; - private VoiceInterpreter(VoiceInterpreterParams params) { + public VoiceInterpreter(VoiceInterpreterParams params) { super(); final ActorRef source = self(); downloadingRcml = new State("downloading rcml", new DownloadingRcml(source), null); From e367a4b3187d37caad0d4d10fa7d906e58e3d02a Mon Sep 17 00:00:00 2001 From: George Vagenas Date: Tue, 18 Jul 2017 16:21:41 +0300 Subject: [PATCH 06/34] Fixes for org.restcomm.connect.interpreter.GatherSpeechTest failures --- .../connect/interpreter/BaseVoiceInterpreter.java | 7 ++++++- .../connect/interpreter/GatherSpeechTest.java | 4 ++++ .../src/test/resources/restcomm.xml | 13 ++++++++++++- .../testsuite/telephony/DialRecordingTest.java | 2 +- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java index 105103e6dc..a8b9422bc0 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java @@ -1534,7 +1534,12 @@ public void execute(final Object message) throws Exception { final NotificationsDao notifications = storage.getNotificationsDao(); // parse attribute "input" Attribute typeAttr = verb.attribute(GatherAttributes.ATTRIBUTE_INPUT); - Collect.Type inputType = Collect.Type.parseOrDefault(typeAttr.value(), Collect.Type.DTMF); + Collect.Type inputType = null; + if (typeAttr == null) { + inputType = Collect.Type.DTMF; + } else { + inputType = Collect.Type.parseOrDefault(typeAttr.value(), Collect.Type.DTMF); + } if (inputType != Collect.Type.DTMF && (resultCallbackAttr == null || StringUtils.isEmpty(resultCallbackAttr.value()))) { final Notification notification = notification(ERROR_NOTIFICATION, 11101, "partialResultCallback attribute is null"); diff --git a/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java b/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java index f23d7ceec9..839309396d 100644 --- a/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java +++ b/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java @@ -305,6 +305,10 @@ public void testPartialAndPlayScenario() throws Exception { interpreter.tell(new DownloaderResponse(getOkRcml(partialCallbackUri, playRcml)), observer); //wait for new tag: Play + DiskCacheRequest diskCacheRequest = expectMsgClass(DiskCacheRequest.class); + + interpreter.tell(new DiskCacheResponse(diskCacheRequest.uri()), observer); + expectMsgClass(Play.class); //simulate play is finished diff --git a/restcomm/restcomm.interpreter/src/test/resources/restcomm.xml b/restcomm/restcomm.interpreter/src/test/resources/restcomm.xml index 6a54018f7d..aea2b5f97d 100644 --- a/restcomm/restcomm.interpreter/src/test/resources/restcomm.xml +++ b/restcomm/restcomm.interpreter/src/test/resources/restcomm.xml @@ -27,6 +27,17 @@ beep.wav alert.wav + + + en-US + en-GB + es-ES + it-IT + fr-FR + pl-PL + pt-PT + + google @@ -40,7 +51,7 @@ If set to false RestComm will use cache for *.wav files playback. Default: false --> - false + true file://${restcomm:home}/recordings diff --git a/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/telephony/DialRecordingTest.java b/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/telephony/DialRecordingTest.java index 55e2ebc5ce..3377f58c06 100644 --- a/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/telephony/DialRecordingTest.java +++ b/restcomm/restcomm.testsuite/src/test/java/org/restcomm/connect/testsuite/telephony/DialRecordingTest.java @@ -223,7 +223,7 @@ public synchronized void testDialClientAlice_BobDisconnects() throws Interrupted assertNotNull(recording); assertEquals(1, recording.size()); double duration = recording.get(0).getAsJsonObject().get("duration").getAsDouble(); - assertEquals(3.0, duration, 0.0); + assertEquals(3.0, duration, 1.0); JsonObject metrics = MonitoringServiceTool.getInstance().getMetrics(deploymentUrl.toString(),adminAccountSid, adminAuthToken); assertNotNull(metrics); From d9aaee8a7f42e10c6e238c427d730647063fa457 Mon Sep 17 00:00:00 2001 From: George Vagenas Date: Tue, 18 Jul 2017 16:27:02 +0300 Subject: [PATCH 07/34] Changed RVD download URL to pull the RVD for ASR version. --- release/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/build.xml b/release/build.xml index bd18f27508..f12938ea04 100755 --- a/release/build.xml +++ b/release/build.xml @@ -45,7 +45,7 @@ Result assigned to: restcomm-rvd.download.url --> - + Will retrieve RVD from ${restcomm-rvd.download.url} From 71c9bcfb767a376f5f9e8f9df24ede9b7a39507a Mon Sep 17 00:00:00 2001 From: Eugene Lapin Date: Tue, 18 Jul 2017 17:00:28 +0300 Subject: [PATCH 08/34] Modify expected result after replacing of snmp4j lib to Hex class from appache commons for encoding --- .../test/java/org/restcomm/connect/mgcp/AsrSignalTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AsrSignalTest.java b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AsrSignalTest.java index bb330cb0e0..a02d4b854b 100644 --- a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AsrSignalTest.java +++ b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AsrSignalTest.java @@ -58,7 +58,7 @@ public void init() { @Test public void testFormatting() { - String expectedResult = "ip=hello.wav dr=no_name_driver ln=en-US eik=# mrt=100 wit=100 pst=50 hw=57:61:69:74"; + String expectedResult = "ip=hello.wav dr=no_name_driver ln=en-US eik=# mrt=100 wit=100 pst=50 hw=57616974"; AsrSignal asrSignal = new AsrSignal(driver, DEFAULT_LANG, initialPrompts, endInputKey, maximumRecTimer, waitingInputTimer, timeAfterSpeech, hotWords); String actualResult = asrSignal.toString(); @@ -72,7 +72,7 @@ public void testFormattingWithMultiplePrompts() { add(URI.create("hello.wav")); add(URI.create("world.wav")); }}; - String expectedResult = "ip=hello.wav,world.wav dr=no_name_driver ln=en-US eik=# mrt=100 wit=100 pst=50 hw=57:61:69:74"; + String expectedResult = "ip=hello.wav,world.wav dr=no_name_driver ln=en-US eik=# mrt=100 wit=100 pst=50 hw=57616974"; AsrSignal asrSignal = new AsrSignal(driver, DEFAULT_LANG, initialPrompts, endInputKey, maximumRecTimer, waitingInputTimer, timeAfterSpeech, hotWords); String actualResult = asrSignal.toString(); From ac6d2568074fd3c5f40b16acb6b585c07ffa313b Mon Sep 17 00:00:00 2001 From: Eugene Lapin Date: Mon, 24 Jul 2017 18:09:17 +0300 Subject: [PATCH 09/34] DTMF fix --- .../connect/interpreter/VoiceInterpreter.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java index ba979c64f8..9940c203e5 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java @@ -808,12 +808,12 @@ private void onMediaGroupResponse(Object message) throws TransitionFailedExcepti fsm.transition(message, finishRecording); } // This is either MMS collected digits or SIP INFO DTMF. If the DTMF is from SIP INFO, then more DTMF might // come later - else if (is(gathering) || is(continuousGathering) || is(finishGathering)) { - final MediaGroupResponse dtmfResponse = (MediaGroupResponse) message; - CollectedResult data = dtmfResponse.get(); - if (data.isAsr() && data.isPartial()) { + else if (is(gathering) || is(continuousGathering) || (is(finishGathering) && !super.dtmfReceived)) { + final MediaGroupResponse dtmfResponse = (MediaGroupResponse) message; + Object data = dtmfResponse.get(); + if (data instanceof CollectedResult && ((CollectedResult)data).isAsr() && ((CollectedResult)data).isPartial()) { fsm.transition(message, continuousGathering); - } else if (!super.dtmfReceived) { + } else { if (sender == call) { // DTMF using SIP INFO, check if all digits collected here collectedDigits.append(dtmfResponse.get()); @@ -837,7 +837,7 @@ else if (is(gathering) || is(continuousGathering) || is(finishGathering)) { } } } else { - collectedDigits.append(dtmfResponse.get().getResult()); + collectedDigits.append(data); fsm.transition(message, finishGathering); } } From b2d39409adf99b27d3b2d95dd3ea19b90283b953 Mon Sep 17 00:00:00 2001 From: Eugene Lapin Date: Tue, 25 Jul 2017 11:04:24 +0300 Subject: [PATCH 10/34] Small fix of unsafe code --- .../java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java b/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java index f118ee6811..3c94df9270 100644 --- a/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java +++ b/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java @@ -251,7 +251,7 @@ protected void notification(final Object message) { } if (originator != null) this.originator.tell(event, self); - if (!response.get().isPartial()) { + if (response.get() == null || !response.get().isPartial()) { ivrInUse = false; } } From e051ecd50abfcaac99e67d8ca3caf1f377b2c04b Mon Sep 17 00:00:00 2001 From: Eugene Lapin Date: Tue, 25 Jul 2017 14:13:25 +0300 Subject: [PATCH 11/34] Update gather-rcml documentation --- .../src/main/asciidoc/rcml/gather-rcml.adoc | 125 ++++++++++-------- 1 file changed, 72 insertions(+), 53 deletions(-) diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/rcml/gather-rcml.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/rcml/gather-rcml.adoc index 3fd5c71400..7b5c46ea18 100644 --- a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/rcml/gather-rcml.adoc +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/rcml/gather-rcml.adoc @@ -1,53 +1,72 @@ -= Restcomm RCML – Gather - -[[gather]] -== Gather -The ** verb "gathers" digits that a caller enters into his or her telephone keypad. When the caller is done entering digits, RestComm submits that digits to the provided 'action' URL in an HTTP GET or POST request. If no input is received before timeout, ** falls through to the next verb in the RestComm document. You may optionally nest **, **, and ** verbs within a ** verb while waiting for input. This allows you to read menu options to the caller while letting her enter a menu selection at any time. After the first digit is received the audio will stop playing. - -=== Gather Attributes - -[cols=",,",options="header",] -|====================================================== -|Name |Allowed Values |Default Value -|action |relative or absolute URL |current document URL -|method |GET, POST |POST -|timeout |positive integer |5 seconds -|finishOnKey |any digit, #, * |# -|numDigits |integer >= 1 |unlimited -|====================================================== - -* *action.* The 'action' attribute takes an absolute or relative URL as a value. When the caller has finished entering digits RestComm will make a GET or POST request to this URL including the parameters below. If no 'action' is provided, RestComm will by default make a POST request to the current document's URL. - -=== Request Parameters - -[cols=",",options="header",] -|======================================================================= -|Parameter |Description -|Digits |The digits the caller pressed, excluding the finishOnKey digit. -|======================================================================= - - -* *method.* The 'method' attribute takes the value 'GET' or 'POST'. This tells RestComm whether to request the 'action' URL via HTTP GET or POST. -* *timeout.* The 'timeout' attribute sets the limit in seconds that RestComm will wait for the caller to press another digit before moving on and making a request to the 'action' URL. For example, if 'timeout' is '10', RestComm will wait ten seconds for the caller to press another key before submitting the previously entered digits to the 'action' URL. RestComm waits until completing the execution of all nested verbs before beginning the timeout period. -* *finishOnKey.* The 'finishOnKey' attribute lets you choose one value that submits the received data when entered. For example, if you set 'finishOnKey' to '\#' and the user enters '1234#', RestComm will immediately stop waiting for more input when the '\#' is received and will submit "Digits=1234" to the 'action' URL. Note that the 'finishOnKey' value is not sent. The allowed values are the digits 0-9, '#', '*' and the empty string (set 'finishOnKey' to ''). If the empty string is used, captures all input and no key will end the when pressed. In this case RestComm will submit the entered digits to the 'action' URL only after the timeout has been reached. The value can only be a single character. -* *numDigits.* The 'numDigits' attribute lets you set the number of digits you are expecting, and submits the data to the 'action' URL once the caller enters that number of digits. - -=== Nesting -You can nest the following verbs within : , , - -=== Examples -For an example of how to use the ** verb see below. - ----- - - - Welcome to TPS. - For store hours, press 1. - To speak to an agent, press 2. - To check your package status, press 3. - - - Sorry, I didn't get your response. - handle-incoming-call.xml - ----- \ No newline at end of file += Restcomm RCML – Gather + +[[gather]] +== Gather +The ** verb supports two modes: *DTMF* and *SPEECH*. In DTMF mode it "gathers" digits that a caller enters into his or her telephone keypad. When the caller is done entering digits, RestComm submits that digits to the provided 'action' URL in an HTTP GET or POST request. In SPEECH mode it "gathers" recognized speech that a caller said. If no input is received before timeout, ** falls through to the next verb in the RestComm document. You may optionally nest **, **, and ** verbs within a ** verb while waiting for input. This allows you to read menu options to the caller while letting her enter a menu selection at any time. After the first digit is received the audio will stop playing. + +=== Gather Attributes + +[cols=",,",options="header",] +|====================================================== +|Name |Allowed Values |Default Value +|action |relative or absolute URL |current document URL +|method |GET, POST |POST +|timeout |positive integer |5 seconds +|finishOnKey |any digit, #, * |# +|numDigits |integer >= 1 |unlimited +|input |dtmf, speech |dtmf +|partialResultCallback |relative or absolute url |none +|partialResultCallbackMethod |GET, POST |POST +|language |en-US, en-GB, es-ES, it-IT, fr-FR, pl-PL, pt-PT |en-US +|hints |"words, phrases that have many words" |none +|====================================================== + +* *action.* The 'action' attribute takes an absolute or relative URL as a value. When the caller has finished entering digits RestComm will make a GET or POST request to this URL including the parameters below. If no 'action' is provided, RestComm will by default make a POST request to the current document's URL. + +=== Request Parameters + +[cols=",",options="header",] +|======================================================================= +|Parameter |Description +|Digits |The digits the caller pressed, excluding the finishOnKey digit. +|======================================================================= + + +* *method.* The 'method' attribute takes the value 'GET' or 'POST'. This tells RestComm whether to request the 'action' URL via HTTP GET or POST. +* *timeout.* The 'timeout' attribute sets the limit in seconds that RestComm will wait for the caller to press another digit before moving on and making a request to the 'action' URL. For example, if 'timeout' is '10', RestComm will wait ten seconds for the caller to press another key before submitting the previously entered digits to the 'action' URL. RestComm waits until completing the execution of all nested verbs before beginning the timeout period. +* *finishOnKey.* The 'finishOnKey' attribute lets you choose one value that submits the received data when entered. For example, if you set 'finishOnKey' to '\#' and the user enters '1234#', RestComm will immediately stop waiting for more input when the '\#' is received and will submit "Digits=1234" to the 'action' URL. Note that the 'finishOnKey' value is not sent. The allowed values are the digits 0-9, '#', '*' and the empty string (set 'finishOnKey' to ''). If the empty string is used, captures all input and no key will end the when pressed. In this case RestComm will submit the entered digits to the 'action' URL only after the timeout has been reached. The value can only be a single character. +* *numDigits.* The 'numDigits' attribute lets you set the number of digits you are expecting, and submits the data to the 'action' URL once the caller enters that number of digits. +* *input* A list of inputs that RestComm should accept for . Can be "dtmf" or "speech". Defaults to "dtmf". +* *partialResultCallback* A relative or fully qualified URL. Is a mandatory attribute for “speech” mode. RestComm will make requests to your partialResultCallback in real-time as speech is recognized. + +=== Request Parameters + +[cols=",",options="header",] +|======================================================================= +|Parameter |Description +|Speech |Partially recognized speech the caller said. +|======================================================================= + + +* *language* The language RestComm should recognize. Defaults to en-US +* *hints* A list of words or phrases that RestComm should expect during recognition. These are very useful for improving recognition of single words or phrases. Entries into hints should be separated by a comma. + +=== Nesting +You can nest the following verbs within : , , + +=== Examples +For an example of how to use the ** verb see below. + +---- + + + Welcome to TPS. + For store hours, press 1. + To speak to an agent, press 2. + To check your package status, press 3. + + + Sorry, I didn't get your response. + handle-incoming-call.xml + +---- From 823216cb71406c368041be40e1d69f1b53713744 Mon Sep 17 00:00:00 2001 From: Eugene Lapin Date: Mon, 31 Jul 2017 11:25:23 +0300 Subject: [PATCH 12/34] Added support of SpeechResult parameter in the action attribute --- .../src/main/asciidoc/rcml/gather-rcml.adoc | 3 +- .../interpreter/BaseVoiceInterpreter.java | 6 +- .../connect/interpreter/VoiceInterpreter.java | 3 + .../connect/interpreter/GatherSpeechTest.java | 22 +++++- .../org/restcomm/connect/mgcp/AsrSignal.java | 23 +++++- .../restcomm/connect/mgcp/IvrEndpoint.java | 73 ++++++++----------- .../restcomm/connect/mgcp/AsrSignalTest.java | 12 ++- .../connect/mgcp/IvrAsrEndpointTest.java | 6 +- .../connect/mscontrol/mms/MgcpMediaGroup.java | 4 +- 9 files changed, 94 insertions(+), 58 deletions(-) diff --git a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/rcml/gather-rcml.adoc b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/rcml/gather-rcml.adoc index 7b5c46ea18..3c0597324a 100644 --- a/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/rcml/gather-rcml.adoc +++ b/restcomm/restcomm.docs/sources-asciidoc/src/main/asciidoc/rcml/gather-rcml.adoc @@ -29,6 +29,7 @@ The ** verb supports two modes: *DTMF* and *SPEECH*. In DTMF mode it "ga |======================================================================= |Parameter |Description |Digits |The digits the caller pressed, excluding the finishOnKey digit. +|SpeechResult |The transcribed result of the speech. |======================================================================= @@ -44,7 +45,7 @@ The ** verb supports two modes: *DTMF* and *SPEECH*. In DTMF mode it "ga [cols=",",options="header",] |======================================================================= |Parameter |Description -|Speech |Partially recognized speech the caller said. +|UnstableSpeechResult |Partially recognized speech the caller said. |======================================================================= diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java index a2be6e5667..479abc07ca 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java @@ -254,6 +254,7 @@ public abstract class BaseVoiceInterpreter extends RestcommUntypedActor { String finishOnKey; int numberOfDigits = Short.MAX_VALUE; StringBuffer collectedDigits; + String speechResult; //Monitoring service ActorRef monitoring; @@ -1702,7 +1703,7 @@ public void execute(final Object message) throws Exception { // processing // the current TwiML document with the verb immediately following the Attribute action = verb.attribute(GatherAttributes.ATTRIBUTE_ACTION); - if (action != null && !digits.trim().isEmpty()) { + if (action != null && (!digits.trim().isEmpty() || !StringUtils.isEmpty(speechResult))) { // Redirect to the action url. if (digits.endsWith(finishOnKey)) { final int finishOnKeyIndex = digits.lastIndexOf(finishOnKey); @@ -1710,6 +1711,7 @@ public void execute(final Object message) throws Exception { } final List parameters = parameters(); parameters.add(new BasicNameValuePair("Digits", digits)); + parameters.add(new BasicNameValuePair("SpeechResult", speechResult)); execHttpRequest(notifications, action, verb.attribute(GatherAttributes.ATTRIBUTE_METHOD), parameters); return; @@ -1734,7 +1736,7 @@ public void execute(final Object message) throws Exception { final MediaGroupResponse asrResponse = (MediaGroupResponse) message; final List parameters = parameters(); - parameters.add(new BasicNameValuePair("Speech", asrResponse.get().getResult())); + parameters.add(new BasicNameValuePair("UnstableSpeechResult", asrResponse.get().getResult())); final NotificationsDao notifications = storage.getNotificationsDao(); execHttpRequest(notifications, verb.attribute(GatherAttributes.ATTRIBUTE_PARTIAL_RESULT_CALLBACK), diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java index 9940c203e5..b3af7821fc 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java @@ -813,6 +813,9 @@ else if (is(gathering) || is(continuousGathering) || (is(finishGathering) && !su Object data = dtmfResponse.get(); if (data instanceof CollectedResult && ((CollectedResult)data).isAsr() && ((CollectedResult)data).isPartial()) { fsm.transition(message, continuousGathering); + } else if (data instanceof CollectedResult && ((CollectedResult)data).isAsr() && !((CollectedResult)data).isPartial() && collectedDigits.length() == 0) { + speechResult = ((CollectedResult)data).getResult(); + fsm.transition(message, finishGathering); } else { if (sender == call) { // DTMF using SIP INFO, check if all digits collected here diff --git a/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java b/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java index 839309396d..aebd141337 100644 --- a/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java +++ b/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java @@ -232,7 +232,7 @@ public void testPartialHangupScenario() throws Exception { callback = expectMsgClass(HttpRequestDescriptor.class); assertEquals(callback.getUri(), partialCallbackUri); - assertEquals(findParam(callback.getParameters(), "Speech").getValue(), "1"); + assertEquals(findParam(callback.getParameters(), "UnstableSpeechResult").getValue(), "1"); interpreter.tell(new DownloaderResponse(getOkRcml(partialCallbackUri, "")), observer); @@ -241,7 +241,14 @@ public void testPartialHangupScenario() throws Exception { callback = expectMsgClass(HttpRequestDescriptor.class); assertEquals(callback.getUri(), partialCallbackUri); - assertEquals(findParam(callback.getParameters(), "Speech").getValue(), "12"); + assertEquals(findParam(callback.getParameters(), "UnstableSpeechResult").getValue(), "12"); + + //generate final response + interpreter.tell(new MediaGroupResponse(new CollectedResult("Hello. World.", true, false)), observer); + + callback = expectMsgClass(HttpRequestDescriptor.class); + assertEquals(callback.getUri(), actionCallbackUri); + assertEquals(findParam(callback.getParameters(), "SpeechResult").getValue(), "Hello. World."); interpreter.tell(new DownloaderResponse(getOkRcml(partialCallbackUri, endRcml)), observer); @@ -291,7 +298,7 @@ public void testPartialAndPlayScenario() throws Exception { callback = expectMsgClass(HttpRequestDescriptor.class); assertEquals(callback.getUri(), partialCallbackUri); - assertEquals(findParam(callback.getParameters(), "Speech").getValue(), "1"); + assertEquals(findParam(callback.getParameters(), "UnstableSpeechResult").getValue(), "1"); interpreter.tell(new DownloaderResponse(getOkRcml(partialCallbackUri, "")), observer); @@ -300,7 +307,14 @@ public void testPartialAndPlayScenario() throws Exception { callback = expectMsgClass(HttpRequestDescriptor.class); assertEquals(callback.getUri(), partialCallbackUri); - assertEquals(findParam(callback.getParameters(), "Speech").getValue(), "12"); + assertEquals(findParam(callback.getParameters(), "UnstableSpeechResult").getValue(), "12"); + + //generate final response + interpreter.tell(new MediaGroupResponse(new CollectedResult("Hello. World.", true, false)), observer); + + callback = expectMsgClass(HttpRequestDescriptor.class); + assertEquals(callback.getUri(), actionCallbackUri); + assertEquals(findParam(callback.getParameters(), "SpeechResult").getValue(), "Hello. World."); interpreter.tell(new DownloaderResponse(getOkRcml(partialCallbackUri, playRcml)), observer); diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java index 418f1aa2f7..52ce84c020 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java @@ -46,9 +46,12 @@ public class AsrSignal { private final long timeAfterSpeech; private final String hotWords; private final String lang; + private final String input; + private final int minNumber; + private final int maxNumber; public AsrSignal(String driver, String lang, List initialPrompts, String endInputKey, long maximumRecTimer, long waitingInputTimer, - long timeAfterSpeech, String hotWords) { + long timeAfterSpeech, String hotWords, String input, int numberOfDigits) { this.driver = driver; this.initialPrompts = initialPrompts; this.endInputKey = endInputKey; @@ -57,6 +60,9 @@ public AsrSignal(String driver, String lang, List initialPrompts, String en this.timeAfterSpeech = timeAfterSpeech; this.hotWords = hotWords; this.lang = lang; + this.input = input; + this.minNumber = numberOfDigits; + this.maxNumber = numberOfDigits; } @Override @@ -106,6 +112,21 @@ public String toString() { buffer.append(SPACE_CHARACTER); buffer.append("hw=").append(Hex.encodeHexString(hotWords.getBytes())); } + if (input != null) { + if (buffer.length() > 0) + buffer.append(SPACE_CHARACTER); + buffer.append("in=").append(input); + } + if (minNumber > 0) { + if (buffer.length() > 0) + buffer.append(SPACE_CHARACTER); + buffer.append("mn=").append(minNumber); + } + if (maxNumber > 0) { + if (buffer.length() > 0) + buffer.append(SPACE_CHARACTER); + buffer.append("mx=").append(maxNumber); + } return buffer.toString(); } } diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java index 625c05c818..4abcc2cef4 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java @@ -40,7 +40,6 @@ import org.restcomm.connect.commons.patterns.Observe; import org.restcomm.connect.commons.patterns.StopObserving; -import java.util.HashMap; import java.util.Map; import static jain.protocol.ip.mgcp.message.parms.ReturnCode.Transaction_Executed_Normally; @@ -176,6 +175,28 @@ private void response(final Object message) { } } + private void handleAsrr(final Map parameters, int code) { + if (parameters.containsKey("asrr")) { + String asrr = parameters.get("asrr"); + if (!StringUtils.isEmpty(asrr)) { + try { + asrr = new String(Hex.decodeHex(asrr.toCharArray())); + } catch (DecoderException e) { + logger.error("asrr parameter cannot be decoded"); + fail(code); + } + } + // Notify the observers that the event successfully completed. + final IvrEndpointResponse result = new IvrEndpointResponse(new CollectedResult(asrr, true, code == 101)); + for (final ActorRef observer : observers) { + observer.tell(result, self()); + } + } else { + logger.error("asrr parameter is missing"); + fail(code); + } + } + private void notification(final Object message) { final Notify notification = (Notify) message; final ActorRef self = self(); @@ -195,58 +216,28 @@ private void notification(final Object message) { case 327: // No speech case 328: // Spoke too long case 329: // Digit pattern not matched + case 331: // Speech pattern not detected case 100: { // Success(final result) String digits = parameters.get("dc"); - if (digits == null) { - digits = EMPTY_STRING; - } - final IvrEndpointResponse result = new IvrEndpointResponse( - new CollectedResult(digits, AsrSignal.REQUEST_ASR.getName().equals(event.getName()), false)); - for (final ActorRef observer : observers) { - observer.tell(result, self); - } - break; - } - case 101: { // Success(partial result) - if (parameters.containsKey("asrr")) { - String asrr = parameters.get("asrr"); - if (!StringUtils.isEmpty(asrr)) { - try { - asrr = new String(Hex.decodeHex(asrr.toCharArray())); - } catch (DecoderException e) { - logger.error("asrr parameter cannot be decoded"); - fail(code); - } - } - // Notify the observers that the event successfully completed. - final IvrEndpointResponse result = new IvrEndpointResponse(new CollectedResult(asrr, true, true)); + if (digits == null && parameters.get("asrr") != null) { + handleAsrr(parameters, code); + } else { + final IvrEndpointResponse result = new IvrEndpointResponse( + new CollectedResult(digits == null ? EMPTY_STRING : digits, AsrSignal.REQUEST_ASR.getName().equals(event.getName()), false)); for (final ActorRef observer : observers) { observer.tell(result, self); } - } else { - logger.error("asrr parameter is missing"); - fail(code); } break; } + case 101: { // Success(partial result) + handleAsrr(parameters, code); + break; + } default: { fail(code); } } } } - - private Map parse(final String input) { - final Map parameters = new HashMap(); - final String[] tokens = input.split(" "); - for (final String token : tokens) { - final String[] values = token.split("="); - if (values.length == 1) { - parameters.put(values[0], null); - } else if (values.length == 2) { - parameters.put(values[0], values[1]); - } - } - return parameters; - } } diff --git a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AsrSignalTest.java b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AsrSignalTest.java index a02d4b854b..ce99bb12e3 100644 --- a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AsrSignalTest.java +++ b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/AsrSignalTest.java @@ -44,6 +44,8 @@ public class AsrSignalTest { private long waitingInputTimer; private long timeAfterSpeech; private String hotWords; + private String input; + private int numberOfDigits; @Before public void init() { @@ -54,13 +56,15 @@ public void init() { waitingInputTimer = 10L; timeAfterSpeech = 5L; hotWords = "Wait"; + input = "dtmf_speech"; + numberOfDigits = 1; } @Test public void testFormatting() { - String expectedResult = "ip=hello.wav dr=no_name_driver ln=en-US eik=# mrt=100 wit=100 pst=50 hw=57616974"; + String expectedResult = "ip=hello.wav dr=no_name_driver ln=en-US eik=# mrt=100 wit=100 pst=50 hw=57616974 in=dtmf_speech mn=1 mx=1"; AsrSignal asrSignal = new AsrSignal(driver, DEFAULT_LANG, initialPrompts, endInputKey, maximumRecTimer, waitingInputTimer, - timeAfterSpeech, hotWords); + timeAfterSpeech, hotWords, input, numberOfDigits); String actualResult = asrSignal.toString(); assertEquals(expectedResult, actualResult); @@ -72,9 +76,9 @@ public void testFormattingWithMultiplePrompts() { add(URI.create("hello.wav")); add(URI.create("world.wav")); }}; - String expectedResult = "ip=hello.wav,world.wav dr=no_name_driver ln=en-US eik=# mrt=100 wit=100 pst=50 hw=57616974"; + String expectedResult = "ip=hello.wav,world.wav dr=no_name_driver ln=en-US eik=# mrt=100 wit=100 pst=50 hw=57616974 in=dtmf_speech mn=1 mx=1"; AsrSignal asrSignal = new AsrSignal(driver, DEFAULT_LANG, initialPrompts, endInputKey, maximumRecTimer, waitingInputTimer, - timeAfterSpeech, hotWords); + timeAfterSpeech, hotWords, input, numberOfDigits); String actualResult = asrSignal.toString(); assertEquals(expectedResult, actualResult); diff --git a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java index 336e9e2364..c4f94f7431 100644 --- a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java +++ b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java @@ -98,7 +98,7 @@ public void testSuccessfulAsrScenario() { final Observing observingResponse = expectMsgClass(Observing.class); assertTrue(observingResponse.succeeded()); - AsrSignal asr = new AsrSignal("no_name_driver", "en-US", Collections.singletonList(URI.create("hello.wav")), "#", 10, 10, 10, HINTS); + AsrSignal asr = new AsrSignal("no_name_driver", "en-US", Collections.singletonList(URI.create("hello.wav")), "#", 10, 10, 10, HINTS, "dtmf_speech", 1); endpoint.tell(asr, observer); final IvrEndpointResponse ivrResponse = expectMsgClass(IvrEndpointResponse.class); assertTrue(ivrResponse.succeeded()); @@ -146,7 +146,7 @@ public void testFailureScenario() { final Observing observingResponse = expectMsgClass(Observing.class); assertTrue(observingResponse.succeeded()); - AsrSignal asr = new AsrSignal("no_name_driver", "en-US", Collections.singletonList(URI.create("hello.wav")), "#", 10, 10, 10, HINTS); + AsrSignal asr = new AsrSignal("no_name_driver", "en-US", Collections.singletonList(URI.create("hello.wav")), "#", 10, 10, 10, HINTS, "dtmf_speech", 1); endpoint.tell(asr, observer); final IvrEndpointResponse ivrResponse = expectMsgClass(IvrEndpointResponse.class); assertFalse(ivrResponse.succeeded()); @@ -181,7 +181,7 @@ public void testEndSignal() { final Observing observingResponse = expectMsgClass(Observing.class); assertTrue(observingResponse.succeeded()); - AsrSignal asr = new AsrSignal("no_name_driver", "en-US", Collections.singletonList(URI.create("hello.wav")), "#", 10, 10, 10, ASR_RESULT_TEXT); + AsrSignal asr = new AsrSignal("no_name_driver", "en-US", Collections.singletonList(URI.create("hello.wav")), "#", 10, 10, 10, ASR_RESULT_TEXT, "dtmf_speech", 1); endpoint.tell(asr, observer); final IvrEndpointResponse ivrResponse = expectMsgClass(IvrEndpointResponse.class); assertTrue(ivrResponse.succeeded()); diff --git a/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java b/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java index 3c94df9270..fe2c437689 100644 --- a/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java +++ b/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java @@ -218,8 +218,8 @@ protected void collect(final Object message) { this.lastEvent = AUMgcpEvent.aupc; } else { this.lastEvent = AsrSignal.REQUEST_ASR; - signal = new AsrSignal(request.getDriver(), request.lang(), request.prompts(), request.endInputKey(), request.timeout(), request.timeout(), - request.timeout(), request.getHints()); + signal = new AsrSignal(request.getDriver(), request.lang(), request.prompts(), request.endInputKey(), 60, request.timeout(), + request.timeout(), request.getHints(), request.type().toString() ,request.numberOfDigits()); } this.originator = sender(); ivr.tell(signal, self); From a9d939315cbbc032dddad3b0d987c164fbb63f47 Mon Sep 17 00:00:00 2001 From: Eugene Lapin Date: Mon, 31 Jul 2017 13:13:42 +0300 Subject: [PATCH 13/34] Changes after PR review --- .../java/org/restcomm/connect/mgcp/AsrSignal.java | 14 ++++++++++++++ .../org/restcomm/connect/mgcp/IvrEndpoint.java | 2 +- .../connect/mscontrol/mms/MgcpMediaGroup.java | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java index 52ce84c020..b43da597e2 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java @@ -50,6 +50,20 @@ public class AsrSignal { private final int minNumber; private final int maxNumber; + /** + * + * @param driver ASR driver + * @param lang speech language + * @param initialPrompts Initial prompt + * @param endInputKey end input key, if present stop ASR with dtmf signal + * @param maximumRecTimer maximum recognition time + * @param waitingInputTimer waiting time to detect user input (gather timeout) + * @param timeAfterSpeech amount of silence necessary after the end of speech (gather timeout) + * @param hotWords hints for speech analyzer tool + * @param input "dtmf", "speech", "dtmf speech" + * @param numberOfDigits number of digits system expects from User + */ + public AsrSignal(String driver, String lang, List initialPrompts, String endInputKey, long maximumRecTimer, long waitingInputTimer, long timeAfterSpeech, String hotWords, String input, int numberOfDigits) { this.driver = driver; diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java index 4abcc2cef4..7c6de561ae 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java @@ -182,7 +182,7 @@ private void handleAsrr(final Map parameters, int code) { try { asrr = new String(Hex.decodeHex(asrr.toCharArray())); } catch (DecoderException e) { - logger.error("asrr parameter cannot be decoded"); + logger.error("asrr parameter cannot be decoded: " + e.getStackTrace()); fail(code); } } diff --git a/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java b/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java index fe2c437689..0d7510cf3f 100644 --- a/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java +++ b/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java @@ -218,7 +218,7 @@ protected void collect(final Object message) { this.lastEvent = AUMgcpEvent.aupc; } else { this.lastEvent = AsrSignal.REQUEST_ASR; - signal = new AsrSignal(request.getDriver(), request.lang(), request.prompts(), request.endInputKey(), 60, request.timeout(), + signal = new AsrSignal(request.getDriver(), request.lang(), request.prompts(), request.endInputKey(), request.timeout(), request.timeout(), request.timeout(), request.getHints(), request.type().toString() ,request.numberOfDigits()); } this.originator = sender(); From 137b2860054795170e668539168cf8d32453ebf1 Mon Sep 17 00:00:00 2001 From: Eugene Lapin Date: Mon, 31 Jul 2017 14:13:16 +0300 Subject: [PATCH 14/34] Changes after PR review --- .../src/main/java/org/restcomm/connect/mgcp/AsrSignal.java | 1 + .../src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java index b43da597e2..4a2e01a4bc 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/AsrSignal.java @@ -75,6 +75,7 @@ public AsrSignal(String driver, String lang, List initialPrompts, String en this.hotWords = hotWords; this.lang = lang; this.input = input; + //RMS expects two parameters but Collect in RVD has only one this.minNumber = numberOfDigits; this.maxNumber = numberOfDigits; } diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java index 7c6de561ae..d758e12909 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java @@ -182,7 +182,7 @@ private void handleAsrr(final Map parameters, int code) { try { asrr = new String(Hex.decodeHex(asrr.toCharArray())); } catch (DecoderException e) { - logger.error("asrr parameter cannot be decoded: " + e.getStackTrace()); + logger.error("asrr parameter cannot be decoded.", e); fail(code); } } From c93350aa9d2ce3c278c4ed0605f892b42963ca00 Mon Sep 17 00:00:00 2001 From: Eugene Lapin Date: Tue, 1 Aug 2017 13:14:07 +0300 Subject: [PATCH 15/34] Remove PartialCallback check. Add FinalResult tests --- .../interpreter/BaseVoiceInterpreter.java | 9 -- .../connect/interpreter/GatherSpeechTest.java | 126 +++++++++++++++++- 2 files changed, 121 insertions(+), 14 deletions(-) diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java index 479abc07ca..cdeaa30c65 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java @@ -1542,15 +1542,6 @@ public void execute(final Object message) throws Exception { inputType = Collect.Type.parseOrDefault(typeAttr.value(), Collect.Type.DTMF); } - if (inputType != Collect.Type.DTMF && (resultCallbackAttr == null || StringUtils.isEmpty(resultCallbackAttr.value()))) { - final Notification notification = notification(ERROR_NOTIFICATION, 11101, "partialResultCallback attribute is null"); - notifications.addNotification(notification); - sendMail(notification); - final StopInterpreter stop = new StopInterpreter(); - source.tell(stop, source); - throw new IllegalStateException("Attribute partialResultCallback is null"); - } - // parse attribute "language" Attribute langAttr = verb.attribute(GatherAttributes.ATTRIBUTE_LANGUAGE); String defaultLang = restcommConfiguration.getMgAsr().getDefaultLanguage(); diff --git a/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java b/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java index aebd141337..a6cee949f1 100644 --- a/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java +++ b/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java @@ -84,13 +84,19 @@ public class GatherSpeechTest { private String endRcml = ""; private String playRcml = "" + playUri + ""; - private String gatherRcml = "" + ""; + private String gatherRcmlNoPartial = "" + + ""; private String gatherEmpty = "" + ""; @@ -223,7 +229,7 @@ public void testPartialHangupScenario() throws Exception { HttpRequestDescriptor callback = expectMsgClass(HttpRequestDescriptor.class); assertEquals(callback.getUri(), requestUri); - interpreter.tell(new DownloaderResponse(getOkRcml(requestUri, gatherRcml)), observer); + interpreter.tell(new DownloaderResponse(getOkRcml(requestUri, gatherRcmlPartial)), observer); expectMsgClass(Collect.class); @@ -250,7 +256,57 @@ public void testPartialHangupScenario() throws Exception { assertEquals(callback.getUri(), actionCallbackUri); assertEquals(findParam(callback.getParameters(), "SpeechResult").getValue(), "Hello. World."); - interpreter.tell(new DownloaderResponse(getOkRcml(partialCallbackUri, endRcml)), observer); + interpreter.tell(new DownloaderResponse(getOkRcml(actionCallbackUri, endRcml)), observer); + + expectMsgClass(Hangup.class); + } + }; + } + + @Test + @SuppressWarnings("unchecked") + public void testFinalResultAndHangupScenario() throws Exception { + new JavaTestKit(system) { + { + final ActorRef observer = getRef(); + final ActorRef interpreter = createVoiceInterpreter(observer); + interpreter.tell(new StartInterpreter(observer), observer); + + expectMsgClass(GetCallInfo.class); + interpreter.tell(new CallResponse(new CallInfo( + new Sid("ACae6e420f425248d6a26948c17a9e2acf"), + CallStateChanged.State.IN_PROGRESS, + CreateCallType.SIP, + "inbound", + new DateTime(), + null, + "test", "test", + "testTo", + null, + null, + false, + false, + false, + new DateTime())), observer); + + expectMsgClass(Observe.class); + + //wait for rcml downloading + HttpRequestDescriptor callback = expectMsgClass(HttpRequestDescriptor.class); + assertEquals(callback.getUri(), requestUri); + + interpreter.tell(new DownloaderResponse(getOkRcml(requestUri, gatherRcmlNoPartial)), observer); + + expectMsgClass(Collect.class); + + //generate final response + interpreter.tell(new MediaGroupResponse(new CollectedResult("Hello. World.", true, false)), observer); + + callback = expectMsgClass(HttpRequestDescriptor.class); + assertEquals(callback.getUri(), actionCallbackUri); + assertEquals(findParam(callback.getParameters(), "SpeechResult").getValue(), "Hello. World."); + + interpreter.tell(new DownloaderResponse(getOkRcml(actionCallbackUri, endRcml)), observer); expectMsgClass(Hangup.class); } @@ -289,7 +345,7 @@ public void testPartialAndPlayScenario() throws Exception { HttpRequestDescriptor callback = expectMsgClass(HttpRequestDescriptor.class); assertEquals(callback.getUri(), requestUri); - interpreter.tell(new DownloaderResponse(getOkRcml(requestUri, gatherRcml)), observer); + interpreter.tell(new DownloaderResponse(getOkRcml(requestUri, gatherRcmlPartial)), observer); expectMsgClass(Collect.class); @@ -316,7 +372,67 @@ public void testPartialAndPlayScenario() throws Exception { assertEquals(callback.getUri(), actionCallbackUri); assertEquals(findParam(callback.getParameters(), "SpeechResult").getValue(), "Hello. World."); - interpreter.tell(new DownloaderResponse(getOkRcml(partialCallbackUri, playRcml)), observer); + interpreter.tell(new DownloaderResponse(getOkRcml(actionCallbackUri, playRcml)), observer); + + //wait for new tag: Play + DiskCacheRequest diskCacheRequest = expectMsgClass(DiskCacheRequest.class); + + interpreter.tell(new DiskCacheResponse(diskCacheRequest.uri()), observer); + + expectMsgClass(Play.class); + + //simulate play is finished + interpreter.tell(new MediaGroupResponse(new CollectedResult("", false, false)), observer); + + expectMsgClass(Hangup.class); + } + }; + } + + @Test + @SuppressWarnings("unchecked") + public void testFinalResultAndPlayScenario() throws Exception { + new JavaTestKit(system) { + { + final ActorRef observer = getRef(); + final ActorRef interpreter = createVoiceInterpreter(observer); + interpreter.tell(new StartInterpreter(observer), observer); + + expectMsgClass(GetCallInfo.class); + interpreter.tell(new CallResponse(new CallInfo( + new Sid("ACae6e420f425248d6a26948c17a9e2acf"), + CallStateChanged.State.IN_PROGRESS, + CreateCallType.SIP, + "inbound", + new DateTime(), + null, + "test", "test", + "testTo", + null, + null, + false, + false, + false, + new DateTime())), observer); + + expectMsgClass(Observe.class); + + //wait for rcml downloading + HttpRequestDescriptor callback = expectMsgClass(HttpRequestDescriptor.class); + assertEquals(callback.getUri(), requestUri); + + interpreter.tell(new DownloaderResponse(getOkRcml(requestUri, gatherRcmlNoPartial)), observer); + + expectMsgClass(Collect.class); + + //generate final response + interpreter.tell(new MediaGroupResponse(new CollectedResult("Hello. World.", true, false)), observer); + + callback = expectMsgClass(HttpRequestDescriptor.class); + assertEquals(callback.getUri(), actionCallbackUri); + assertEquals(findParam(callback.getParameters(), "SpeechResult").getValue(), "Hello. World."); + + interpreter.tell(new DownloaderResponse(getOkRcml(actionCallbackUri, playRcml)), observer); //wait for new tag: Play DiskCacheRequest diskCacheRequest = expectMsgClass(DiskCacheRequest.class); From dc06f003c119d510ee8a953f36d2dc35c2f53eea Mon Sep 17 00:00:00 2001 From: Eugene Lapin Date: Tue, 1 Aug 2017 16:43:11 +0300 Subject: [PATCH 16/34] Ignore RCML from partialCallback --- .../interpreter/BaseVoiceInterpreter.java | 15 +++++++++------ .../connect/interpreter/VoiceInterpreter.java | 18 +----------------- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java index cdeaa30c65..dabbf55ac8 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java @@ -1724,14 +1724,17 @@ public PartialGathering(final ActorRef source) { @Override public void execute(final Object message) throws Exception { - final MediaGroupResponse asrResponse = (MediaGroupResponse) message; + if (verb.attribute(GatherAttributes.ATTRIBUTE_PARTIAL_RESULT_CALLBACK) != null + && !StringUtils.isEmpty(verb.attribute(GatherAttributes.ATTRIBUTE_PARTIAL_RESULT_CALLBACK).value())) { + final MediaGroupResponse asrResponse = (MediaGroupResponse) message; - final List parameters = parameters(); - parameters.add(new BasicNameValuePair("UnstableSpeechResult", asrResponse.get().getResult())); + final List parameters = parameters(); + parameters.add(new BasicNameValuePair("UnstableSpeechResult", asrResponse.get().getResult())); - final NotificationsDao notifications = storage.getNotificationsDao(); - execHttpRequest(notifications, verb.attribute(GatherAttributes.ATTRIBUTE_PARTIAL_RESULT_CALLBACK), - verb.attribute(GatherAttributes.ATTRIBUTE_PARTIAL_RESULT_CALLBACK_METHOD), parameters); + final NotificationsDao notifications = storage.getNotificationsDao(); + execHttpRequest(notifications, verb.attribute(GatherAttributes.ATTRIBUTE_PARTIAL_RESULT_CALLBACK), + verb.attribute(GatherAttributes.ATTRIBUTE_PARTIAL_RESULT_CALLBACK_METHOD), parameters); + } } } diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java index b3af7821fc..cfc3dd2c9f 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java @@ -30,7 +30,6 @@ import akka.pattern.AskTimeoutException; import akka.util.Timeout; import org.apache.commons.configuration.Configuration; -import org.apache.commons.lang.StringUtils; import org.apache.http.HttpStatus; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; @@ -1086,21 +1085,6 @@ private void onCallResponse(Object message, State state) throws TransitionFailed } } - private boolean isEmptyDownloaderResponse(DownloaderResponse response) throws IOException { - final String type = response.get().getContentType(); - if (type == null) - return true; - - if (type.contains("audio/wav") || type.contains("audio/wave") || type.contains("audio/x-wav")) { - return false; - } - - if (type.contains("text/plain") || type.contains("text/xml") || type.contains("application/xml") || type.contains("text/html")) { - return StringUtils.isEmpty(response.get().getContentAsString()); - } - return true; - } - private void onDownloaderResponse(Object message, State state) throws IOException, TransitionFailedException, TransitionNotFoundException, TransitionRollbackException { final DownloaderResponse response = (DownloaderResponse) message; if (logger.isDebugEnabled()) { @@ -1109,7 +1093,7 @@ private void onDownloaderResponse(Object message, State state) throws IOExceptio logger.debug("statusCode " + response.get().getStatusCode()); } if (response.succeeded() && HttpStatus.SC_OK == response.get().getStatusCode()) { - if (continuousGathering.equals(state) && isEmptyDownloaderResponse(response)) { + if (continuousGathering.equals(state)) { //no need change state return; } From 9f585e072b83f94c4f6db28a17dc852d3d859fb8 Mon Sep 17 00:00:00 2001 From: Eugene Lapin Date: Tue, 1 Aug 2017 16:51:30 +0300 Subject: [PATCH 17/34] Minor changes to restcomm configuration script --- .../restcomm/autoconfig.d/config-restcomm.sh | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-restcomm.sh b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-restcomm.sh index 5db1570dfe..5cd1576d94 100755 --- a/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-restcomm.sh +++ b/restcomm/configuration/config-scripts/as7-config-scripts/restcomm/autoconfig.d/config-restcomm.sh @@ -605,15 +605,13 @@ configRMSNetworking() { configAsrDriver() { if [ ! -z "$MG_ASR_DRIVERS" ] && [ ! -z "$MG_ASR_DRIVER_DEFAULT" ]; then FILE=$RESTCOMM_DEPLOY/WEB-INF/conf/restcomm.xml - xmlstarlet ed -d "/restcomm/runtime-settings/mg-asr-drivers" \ - -s "/restcomm/runtime-settings" -t elem -n mg-asr-drivers \ - -i "/restcomm/runtime-settings/mg-asr-drivers" -t attr -n default -v "$MG_ASR_DRIVER_DEFAULT" \ - $FILE > $FILE.bak - mv $FILE.bak $FILE + xmlstarlet ed --inplace -d "/restcomm/runtime-settings/mg-asr-drivers" \ + -s "/restcomm/runtime-settings" -t elem -n mg-asr-drivers \ + -i "/restcomm/runtime-settings/mg-asr-drivers" -t attr -n default -v "$MG_ASR_DRIVER_DEFAULT" \ + $FILE for driverName in ${MG_ASR_DRIVERS//,/ }; do - xmlstarlet ed -s "/restcomm/runtime-settings/mg-asr-drivers" -t elem -n "driver" -v "$driverName" \ - $FILE > $FILE.bak - mv $FILE.bak $FILE + xmlstarlet ed --inplace -s "/restcomm/runtime-settings/mg-asr-drivers" -t elem -n "driver" -v "$driverName" \ + $FILE done fi } From 3927f3e47e5ed1c2d0445143e5357d6f52012316 Mon Sep 17 00:00:00 2001 From: Eugene Lapin Date: Wed, 2 Aug 2017 13:24:28 +0300 Subject: [PATCH 18/34] Fix: Go to the next Verb after silent --- .../restcomm/connect/interpreter/BaseVoiceInterpreter.java | 2 ++ .../org/restcomm/connect/interpreter/VoiceInterpreter.java | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java index dabbf55ac8..2563503ee3 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java @@ -1705,11 +1705,13 @@ public void execute(final Object message) throws Exception { parameters.add(new BasicNameValuePair("SpeechResult", speechResult)); execHttpRequest(notifications, action, verb.attribute(GatherAttributes.ATTRIBUTE_METHOD), parameters); + speechResult = null; return; } if (logger.isInfoEnabled()) { logger.info("Attribute, Action or Digits is null, FinishGathering failed, moving to the next available verb"); } + speechResult = null; // Ask the parser for the next action to take. final GetNextVerb next = new GetNextVerb(); parser.tell(next, source); diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java index cfc3dd2c9f..a25d125eac 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java @@ -30,6 +30,7 @@ import akka.pattern.AskTimeoutException; import akka.util.Timeout; import org.apache.commons.configuration.Configuration; +import org.apache.commons.lang.StringUtils; import org.apache.http.HttpStatus; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; @@ -839,7 +840,9 @@ else if (is(gathering) || is(continuousGathering) || (is(finishGathering) && !su } } } else { - collectedDigits.append(data); + if (!(data instanceof CollectedResult) || !StringUtils.isEmpty(((CollectedResult)data).getResult())) { + collectedDigits.append(data); + } fsm.transition(message, finishGathering); } } From d49005885a41053a05ed9cf2888814cd30274ffb Mon Sep 17 00:00:00 2001 From: Eugene Lapin Date: Wed, 2 Aug 2017 15:13:39 +0300 Subject: [PATCH 19/34] Added unit tests --- .../connect/interpreter/VoiceInterpreter.java | 1 + .../connect/interpreter/GatherSpeechTest.java | 49 ++++++++++++++++--- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java index a25d125eac..41283781c7 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java @@ -840,6 +840,7 @@ else if (is(gathering) || is(continuousGathering) || (is(finishGathering) && !su } } } else { + // Skip digits collecting if empty CollectResult received if (!(data instanceof CollectedResult) || !StringUtils.isEmpty(((CollectedResult)data).getResult())) { collectedDigits.append(data); } diff --git a/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java b/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java index a6cee949f1..4d65d43f7c 100644 --- a/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java +++ b/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java @@ -26,6 +26,7 @@ import akka.actor.Props; import akka.actor.UntypedActorFactory; import akka.testkit.JavaTestKit; +import akka.testkit.TestActorRef; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; @@ -38,12 +39,13 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import org.mockito.Mockito; import org.restcomm.connect.commons.cache.DiskCacheRequest; import org.restcomm.connect.commons.cache.DiskCacheResponse; import org.restcomm.connect.commons.configuration.RestcommConfiguration; import org.restcomm.connect.commons.dao.CollectedResult; import org.restcomm.connect.commons.dao.Sid; +import org.restcomm.connect.commons.fsm.FiniteStateMachine; +import org.restcomm.connect.commons.fsm.State; import org.restcomm.connect.commons.patterns.Observe; import org.restcomm.connect.commons.telephony.CreateCallType; import org.restcomm.connect.dao.CallDetailRecordsDao; @@ -67,6 +69,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; +import static org.mockito.Mockito.*; /** * Created by gdubina on 6/24/17. @@ -146,13 +149,13 @@ private HttpResponseDescriptor getOkRcml(URI uri, String rcml) { return builder.build(); } - private ActorRef createVoiceInterpreter(final ActorRef observer) { + private TestActorRef createVoiceInterpreter(final ActorRef observer) { //dao - final CallDetailRecordsDao recordsDao = Mockito.mock(CallDetailRecordsDao.class); - Mockito.when(recordsDao.getCallDetailRecord(Mockito.any(Sid.class))).thenReturn(null); + final CallDetailRecordsDao recordsDao = mock(CallDetailRecordsDao.class); + when(recordsDao.getCallDetailRecord(any(Sid.class))).thenReturn(null); - final DaoManager storage = Mockito.mock(DaoManager.class); - Mockito.when(storage.getCallDetailRecordsDao()).thenReturn(recordsDao); + final DaoManager storage = mock(DaoManager.class); + when(storage.getCallDetailRecordsDao()).thenReturn(recordsDao); //actors final ActorRef downloader = new MockedActor("downloader") @@ -194,7 +197,7 @@ public ActorRef getCache() { }; } }); - return system.actorOf(props); + return TestActorRef.create(system, props, "VoiceInterpreter" + System.currentTimeMillis());//system.actorOf(props); } @Test @@ -492,6 +495,38 @@ public void testValidateDefaultAttributeValues() throws Exception { }; } + @Test + @SuppressWarnings("unchecked") + public void testOnMediaGroupResponseEmptyCollectedResult() throws Exception { + new JavaTestKit(system) { + { + final ActorRef observer = getRef(); + final TestActorRef interpreterRef = createVoiceInterpreter(observer); + VoiceInterpreter interpreter = interpreterRef.underlyingActor(); + interpreter.fsm = spy(new FiniteStateMachine(interpreter.continuousGathering, interpreter.transitions)); + doNothing().when(interpreter.fsm).transition(any(), eq(interpreter.finishGathering)); + interpreter.collectedDigits = new StringBuffer(); + interpreterRef.tell(new MediaGroupResponse(new CollectedResult("", false, false)), observer); + assertSame(0, interpreter.collectedDigits.length()); + } + }; + } + + @Test + @SuppressWarnings("unchecked") + public void testIgnoreRcmlFromPartialCallback() throws Exception { + new JavaTestKit(system) { + { + final ActorRef observer = getRef(); + final TestActorRef interpreterRef = createVoiceInterpreter(observer); + VoiceInterpreter interpreter = interpreterRef.underlyingActor(); + interpreter.fsm = spy(new FiniteStateMachine(interpreter.continuousGathering, interpreter.transitions)); + interpreterRef.tell(new DownloaderResponse(getOkRcml(partialCallbackUri, playRcml)), observer); + verify(interpreter.fsm, never()).transition(any(), any(State.class)); + } + }; + } + private NameValuePair findParam(final List params, final String key) { return Iterables.find(params, new Predicate() { public boolean apply(NameValuePair p) { From 0d3c18152ff861292294f8c48047458eaa5900eb Mon Sep 17 00:00:00 2001 From: Eugene Lapin Date: Thu, 3 Aug 2017 16:45:13 +0300 Subject: [PATCH 20/34] Added configuration for timeouts, fixed issue with languages in ASR --- .../src/main/webapp/WEB-INF/conf/restcomm.xml | 6 ++++++ .../sets/impl/MgAsrConfigurationSet.java | 12 ++++++++++++ .../configuration/MgAsrConfigurationTest.java | 16 +++++++++++++--- .../src/test/resources/restcomm.xml | 6 ++++++ .../interpreter/BaseVoiceInterpreter.java | 2 +- .../org/restcomm/connect/mgcp/AsrSignal.java | 10 +++++----- .../org/restcomm/connect/mgcp/AsrSignalTest.java | 12 ++++++------ .../connect/mscontrol/mms/MgcpMediaGroup.java | 3 ++- 8 files changed, 51 insertions(+), 16 deletions(-) diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/restcomm.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/restcomm.xml index ecbd0f720f..84028b574a 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/restcomm.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/restcomm.xml @@ -38,6 +38,12 @@ pt-PT + + 60 + + + 5 + + 60 + + + 5 + - en-US + af-ZA + id-ID + ms-MY + ca-ES + cs-CZ + da-DK + de-DE + en-AU + en-CA en-GB + en-IN + en-IE + en-NZ + en-PH + en-ZA + en-US + es-AR + es-BO + es-CL + es-CO + es-CR + es-EC + es-SV es-ES - it-IT + es-US + es-GT + es-HN + es-MX + es-NI + es-PA + es-PY + es-PE + es-PR + es-DO + es-UY + es-VE + eu-ES + fil-PH + fr-CA fr-FR + gl-ES + hr-HR + zu-ZA + is-IS + it-IT + lt-LT + hu-HU + nl-NL + nb-NO pl-PL + pt-BR pt-PT + ro-RO + sk-SK + sl-SI + fi-FI + sv-SE + vi-VN + tr-TR + el-GR + bg-BG + ru-RU + sr-RS + uk-UA + he-IL + ar-IL + ar-JO + ar-AE + ar-BH + ar-DZ + ar-SA + ar-IQ + ar-KW + ar-MA + ar-TN + ar-OM + ar-PS + ar-QA + ar-LB + ar-EG + fa-IR + hi-IN + th-TH + ko-KR + cmn-Hant-TW + yue-Hant-HK + ja-JP + cmn-Hans-HK + cmn-Hans-CN From 8b0c98443f51ba1dbc68ddfc716bde2e6ad1b9e1 Mon Sep 17 00:00:00 2001 From: maria-farooq Date: Thu, 3 Aug 2017 21:53:35 +0500 Subject: [PATCH 22/34] added Timeouts description --- .../src/main/webapp/WEB-INF/conf/restcomm.xml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/restcomm.xml b/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/restcomm.xml index 84028b574a..8857e1f912 100644 --- a/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/restcomm.xml +++ b/restcomm/restcomm.application/src/main/webapp/WEB-INF/conf/restcomm.xml @@ -38,11 +38,24 @@ pt-PT - - 60 + 5 + + 60 - + Will retrieve RVD from ${restcomm-rvd.download.url} From ed3239b24633098e6343615d3f4a7a7e5b004618 Mon Sep 17 00:00:00 2001 From: Maria Farooq Date: Wed, 20 Sep 2017 13:42:05 +0500 Subject: [PATCH 32/34] moved Collected result to mscontrol.api and did proper translation in mediagroup, made IvrEndpointResponse to generic --- .../interpreter/BaseVoiceInterpreter.java | 10 +++- .../connect/interpreter/VoiceInterpreter.java | 2 +- .../connect/interpreter/GatherSpeechTest.java | 2 +- .../connect/mgcp}/CollectedResult.java | 2 +- .../restcomm/connect/mgcp/IvrEndpoint.java | 24 ++++---- .../connect/mgcp/IvrEndpointResponse.java | 5 +- .../api/messages/CollectedResult.java | 58 +++++++++++++++++++ .../connect/mscontrol/mms/MgcpMediaGroup.java | 9 ++- 8 files changed, 89 insertions(+), 23 deletions(-) rename restcomm/{restcomm.commons/src/main/java/org/restcomm/connect/commons/dao => restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp}/CollectedResult.java (97%) create mode 100644 restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/messages/CollectedResult.java diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java index 349cdf8a16..6b37b6f1ab 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/BaseVoiceInterpreter.java @@ -46,7 +46,6 @@ import org.restcomm.connect.commons.cache.DiskCacheResponse; import org.restcomm.connect.commons.cache.HashGenerator; import org.restcomm.connect.commons.configuration.RestcommConfiguration; -import org.restcomm.connect.commons.dao.CollectedResult; import org.restcomm.connect.commons.dao.Sid; import org.restcomm.connect.commons.faulttolerance.RestcommUntypedActor; import org.restcomm.connect.commons.fsm.Action; @@ -87,6 +86,7 @@ import org.restcomm.connect.interpreter.rcml.Verbs; import org.restcomm.connect.interpreter.rcml.domain.GatherAttributes; import org.restcomm.connect.mscontrol.api.messages.Collect; +import org.restcomm.connect.mscontrol.api.messages.CollectedResult; import org.restcomm.connect.mscontrol.api.messages.MediaGroupResponse; import org.restcomm.connect.mscontrol.api.messages.Play; import org.restcomm.connect.mscontrol.api.messages.Record; @@ -2046,7 +2046,13 @@ public void execute(final Object message) throws Exception { if (MediaGroupResponse.class.equals(klass)) { final MediaGroupResponse response = (MediaGroupResponse) message; Object data = response.get(); - parameters.add(new BasicNameValuePair("Digits", data instanceof CollectedResult ? ((CollectedResult)data).getResult() : (String)data)); + if (data instanceof CollectedResult) { + parameters.add(new BasicNameValuePair("Digits", ((CollectedResult)data).getResult())); + } else if(data instanceof String) { + parameters.add(new BasicNameValuePair("Digits", (String)data)); + } else { + logger.error("unidentified response recived in MediaGroupResponse: "+response); + } request = new HttpRequestDescriptor(uri, method, parameters); if (logger.isInfoEnabled()){ logger.info("About to execute Record action to: "+uri); diff --git a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java index ab48c4f182..0c749ec823 100644 --- a/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java +++ b/restcomm/restcomm.interpreter/src/main/java/org/restcomm/connect/interpreter/VoiceInterpreter.java @@ -38,7 +38,6 @@ import org.joda.time.Interval; import org.restcomm.connect.asr.AsrResponse; import org.restcomm.connect.commons.cache.DiskCacheResponse; -import org.restcomm.connect.commons.dao.CollectedResult; import org.restcomm.connect.commons.dao.Sid; import org.restcomm.connect.commons.fsm.Action; import org.restcomm.connect.commons.fsm.FiniteStateMachine; @@ -67,6 +66,7 @@ import org.restcomm.connect.interpreter.rcml.Tag; import org.restcomm.connect.interpreter.rcml.Verbs; import org.restcomm.connect.interpreter.rcml.domain.GatherAttributes; +import org.restcomm.connect.mscontrol.api.messages.CollectedResult; import org.restcomm.connect.mscontrol.api.messages.JoinComplete; import org.restcomm.connect.mscontrol.api.messages.Left; import org.restcomm.connect.mscontrol.api.messages.MediaGroupResponse; diff --git a/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java b/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java index 340eae8d7f..4c9c111a78 100644 --- a/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java +++ b/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java @@ -42,7 +42,6 @@ import org.restcomm.connect.commons.cache.DiskCacheRequest; import org.restcomm.connect.commons.cache.DiskCacheResponse; import org.restcomm.connect.commons.configuration.RestcommConfiguration; -import org.restcomm.connect.commons.dao.CollectedResult; import org.restcomm.connect.commons.dao.Sid; import org.restcomm.connect.commons.fsm.FiniteStateMachine; import org.restcomm.connect.commons.fsm.State; @@ -56,6 +55,7 @@ import org.restcomm.connect.interpreter.rcml.MockedActor; import org.restcomm.connect.interpreter.rcml.domain.GatherAttributes; import org.restcomm.connect.mscontrol.api.messages.Collect; +import org.restcomm.connect.mscontrol.api.messages.CollectedResult; import org.restcomm.connect.mscontrol.api.messages.MediaGroupResponse; import org.restcomm.connect.mscontrol.api.messages.Play; import org.restcomm.connect.telephony.api.CallInfo; diff --git a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/dao/CollectedResult.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/CollectedResult.java similarity index 97% rename from restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/dao/CollectedResult.java rename to restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/CollectedResult.java index 1615d02e9b..ccef6e0c7f 100644 --- a/restcomm/restcomm.commons/src/main/java/org/restcomm/connect/commons/dao/CollectedResult.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/CollectedResult.java @@ -18,7 +18,7 @@ * */ -package org.restcomm.connect.commons.dao; +package org.restcomm.connect.mgcp; /** * Created by gdubina on 6/6/17. diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java index cb770a17f2..8d4198c408 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpoint.java @@ -19,6 +19,18 @@ */ package org.restcomm.connect.mgcp; +import static jain.protocol.ip.mgcp.message.parms.ReturnCode.Transaction_Executed_Normally; + +import java.util.Map; + +import org.apache.commons.codec.DecoderException; +import org.apache.commons.codec.binary.Hex; +import org.apache.commons.lang.StringUtils; +import org.mobicents.protocols.mgcp.jain.pkg.AUMgcpEvent; +import org.mobicents.protocols.mgcp.jain.pkg.AUPackage; +import org.restcomm.connect.commons.patterns.Observe; +import org.restcomm.connect.commons.patterns.StopObserving; + import akka.actor.ActorRef; import jain.protocol.ip.mgcp.JainIPMgcpException; import jain.protocol.ip.mgcp.JainMgcpResponseEvent; @@ -35,18 +47,6 @@ import jain.protocol.ip.mgcp.message.parms.ReturnCode; import jain.protocol.ip.mgcp.pkg.MgcpEvent; import jain.protocol.ip.mgcp.pkg.PackageName; -import org.mobicents.protocols.mgcp.jain.pkg.AUMgcpEvent; -import org.mobicents.protocols.mgcp.jain.pkg.AUPackage; -import org.restcomm.connect.commons.patterns.Observe; -import org.restcomm.connect.commons.patterns.StopObserving; - -import java.util.Map; - -import static jain.protocol.ip.mgcp.message.parms.ReturnCode.Transaction_Executed_Normally; -import org.apache.commons.codec.DecoderException; -import org.apache.commons.codec.binary.Hex; -import org.apache.commons.lang.StringUtils; -import org.restcomm.connect.commons.dao.CollectedResult; /** * @author quintana.thomas@gmail.com (Thomas Quintana) diff --git a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpointResponse.java b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpointResponse.java index e7c84a6a17..e8467377d4 100644 --- a/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpointResponse.java +++ b/restcomm/restcomm.mgcp/src/main/java/org/restcomm/connect/mgcp/IvrEndpointResponse.java @@ -19,14 +19,13 @@ */ package org.restcomm.connect.mgcp; -import org.restcomm.connect.commons.dao.CollectedResult; import org.restcomm.connect.commons.patterns.StandardResponse; /** * @author quintana.thomas@gmail.com (Thomas Quintana) */ -public class IvrEndpointResponse extends StandardResponse { - public IvrEndpointResponse(final CollectedResult object) { +public class IvrEndpointResponse extends StandardResponse { + public IvrEndpointResponse(final T object) { super(object); } diff --git a/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/messages/CollectedResult.java b/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/messages/CollectedResult.java new file mode 100644 index 0000000000..8b2df9a1aa --- /dev/null +++ b/restcomm/restcomm.mscontrol.api/src/main/java/org/restcomm/connect/mscontrol/api/messages/CollectedResult.java @@ -0,0 +1,58 @@ +/* + * 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.mscontrol.api.messages; + +/** + * Created by gdubina on 6/6/17. + */ +public class CollectedResult { + + private final String result; + private final boolean isAsr; + private final boolean isPartial; + + public CollectedResult(String result, boolean isAsr, boolean isPartial) { + this.result = result; + this.isAsr = isAsr; + this.isPartial = isPartial; + } + + public String getResult() { + return result; + } + + public boolean isAsr() { + return isAsr; + } + + public boolean isPartial() { + return isPartial; + } + + @Override + public String toString() { + return "CollectedResult{" + + "result='" + result + '\'' + + ", isAsr=" + isAsr + + ", isPartial=" + isPartial + + '}'; + } +} diff --git a/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java b/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java index 28eecf77d8..fd12cfe3fd 100644 --- a/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java +++ b/restcomm/restcomm.mscontrol.mms/src/main/java/org/restcomm/connect/mscontrol/mms/MgcpMediaGroup.java @@ -29,7 +29,6 @@ import org.apache.commons.configuration.Configuration; import org.mobicents.protocols.mgcp.jain.pkg.AUMgcpEvent; import org.restcomm.connect.commons.configuration.RestcommConfiguration; -import org.restcomm.connect.commons.dao.CollectedResult; import org.restcomm.connect.commons.fsm.Action; import org.restcomm.connect.commons.fsm.FiniteStateMachine; import org.restcomm.connect.commons.fsm.State; @@ -56,6 +55,7 @@ import org.restcomm.connect.mgcp.UpdateLink; import org.restcomm.connect.mscontrol.api.MediaGroup; import org.restcomm.connect.mscontrol.api.messages.Collect; +import org.restcomm.connect.mscontrol.api.messages.CollectedResult; import org.restcomm.connect.mscontrol.api.messages.Join; import org.restcomm.connect.mscontrol.api.messages.MediaGroupResponse; import org.restcomm.connect.mscontrol.api.messages.MediaGroupStateChanged; @@ -243,16 +243,19 @@ protected void play(final Object message) { @SuppressWarnings("unchecked") protected void notification(final Object message) { final IvrEndpointResponse response = (IvrEndpointResponse) message; + Object ivrResponse = response.get(); final ActorRef self = self(); MediaGroupResponse event; + org.restcomm.connect.mgcp.CollectedResult mgcpCollectedResult = null; if (response.succeeded()) { - event = new MediaGroupResponse<>(response.get()); + mgcpCollectedResult = (org.restcomm.connect.mgcp.CollectedResult)ivrResponse; + event = new MediaGroupResponse<>(new CollectedResult(mgcpCollectedResult.getResult(), mgcpCollectedResult.isAsr(), mgcpCollectedResult.isPartial())); } else { event = new MediaGroupResponse<>(response.cause(), response.error()); } if (originator != null) this.originator.tell(event, self); - if (response.get() == null || !response.get().isPartial()) { + if (ivrResponse == null || (mgcpCollectedResult != null && !(mgcpCollectedResult.isPartial()))) { ivrInUse = false; } } From 744f888a7ba97c9d6fc400d09184490fbf985624 Mon Sep 17 00:00:00 2001 From: Maria Farooq Date: Wed, 20 Sep 2017 14:20:32 +0500 Subject: [PATCH 33/34] fixed class casting errors in different classes --- .../connect/interpreter/GatherSpeechTest.java | 39 ++++++++------ .../connect/mgcp/IvrAsrEndpointTest.java | 51 ++++++++++--------- .../connect/mgcp/IvrEndpointTest.java | 33 ++++++------ 3 files changed, 69 insertions(+), 54 deletions(-) diff --git a/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java b/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java index 4c9c111a78..5c08f01d16 100644 --- a/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java +++ b/restcomm/restcomm.interpreter/src/test/java/org/restcomm/connect/interpreter/GatherSpeechTest.java @@ -20,16 +20,20 @@ package org.restcomm.connect.interpreter; -import akka.actor.Actor; -import akka.actor.ActorRef; -import akka.actor.ActorSystem; -import akka.actor.Props; -import akka.actor.UntypedActorFactory; -import akka.testkit.JavaTestKit; -import akka.testkit.TestActorRef; -import com.google.common.base.Function; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.net.URI; +import java.util.List; + import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.XMLConfiguration; @@ -64,12 +68,17 @@ import org.restcomm.connect.telephony.api.GetCallInfo; import org.restcomm.connect.telephony.api.Hangup; -import java.net.URI; -import java.util.List; +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.mockito.Mockito.*; +import akka.actor.Actor; +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; +import akka.actor.UntypedActorFactory; +import akka.testkit.JavaTestKit; +import akka.testkit.TestActorRef; /** * Created by gdubina on 6/24/17. diff --git a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java index 1bca38ae40..ef771fc653 100644 --- a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java +++ b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java @@ -20,6 +20,22 @@ package org.restcomm.connect.mgcp; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.net.URI; +import java.util.Collections; + +import org.apache.commons.codec.binary.Hex; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mobicents.protocols.mgcp.jain.pkg.AUMgcpEvent; +import org.mobicents.protocols.mgcp.jain.pkg.AUPackage; +import org.restcomm.connect.commons.patterns.Observe; +import org.restcomm.connect.commons.patterns.Observing; +import org.restcomm.connect.commons.patterns.StopObserving; + import akka.actor.ActorRef; import akka.actor.ActorSystem; import akka.actor.Props; @@ -31,21 +47,6 @@ import jain.protocol.ip.mgcp.message.parms.EventName; import jain.protocol.ip.mgcp.message.parms.ReturnCode; import jain.protocol.ip.mgcp.pkg.MgcpEvent; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mobicents.protocols.mgcp.jain.pkg.AUMgcpEvent; -import org.mobicents.protocols.mgcp.jain.pkg.AUPackage; -import org.restcomm.connect.commons.patterns.Observe; -import org.restcomm.connect.commons.patterns.Observing; -import org.restcomm.connect.commons.patterns.StopObserving; -import org.apache.commons.codec.binary.Hex; - -import java.net.URI; -import java.util.Collections; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; /** * @author Dmitriy Nadolenko @@ -102,19 +103,22 @@ public void testSuccessfulAsrScenario() { endpoint.tell(asr, observer); final IvrEndpointResponse ivrResponse = expectMsgClass(IvrEndpointResponse.class); assertTrue(ivrResponse.succeeded()); - assertTrue(ASR_RESULT_TEXT.equals(ivrResponse.get().getResult())); - assertTrue(ivrResponse.get().isAsr()); + CollectedResult collectedResult = (CollectedResult)ivrResponse.get(); + assertTrue(ASR_RESULT_TEXT.equals(collectedResult.getResult())); + assertTrue(collectedResult.isAsr()); final IvrEndpointResponse ivrResponse2 = expectMsgClass(IvrEndpointResponse.class); assertTrue(ivrResponse2.succeeded()); - assertTrue(ASR_RESULT_TEXT.equals(ivrResponse2.get().getResult())); - assertTrue(ivrResponse2.get().isAsr()); + collectedResult = (CollectedResult)ivrResponse2.get(); + assertTrue(ASR_RESULT_TEXT.equals(collectedResult.getResult())); + assertTrue(collectedResult.isAsr()); final IvrEndpointResponse ivrResponse3 = expectMsgClass(IvrEndpointResponse.class); + collectedResult = (CollectedResult)ivrResponse3.get(); assertTrue(ivrResponse3.succeeded()); - assertTrue(ivrResponse3.get().getResult().isEmpty()); - assertTrue(ivrResponse2.get().isAsr()); + assertTrue(collectedResult.getResult().isEmpty()); + assertTrue(collectedResult.isAsr()); // Stop observing events from the IVR end point. endpoint.tell(new StopObserving(observer), observer); @@ -185,8 +189,9 @@ public void testEndSignal() { endpoint.tell(asr, observer); final IvrEndpointResponse ivrResponse = expectMsgClass(IvrEndpointResponse.class); assertTrue(ivrResponse.succeeded()); - assertTrue(ASR_RESULT_TEXT.equals(ivrResponse.get().getResult())); - assertTrue(ivrResponse.get().isAsr()); + CollectedResult collectedResult = (CollectedResult)ivrResponse.get(); + assertTrue(ASR_RESULT_TEXT.equals(collectedResult.getResult())); + assertTrue(collectedResult.isAsr()); // EndSignal to IVR endpoint.tell(new StopEndpoint(AsrSignal.REQUEST_ASR), observer); diff --git a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrEndpointTest.java b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrEndpointTest.java index 6c7e21fc6c..0bc5705a41 100644 --- a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrEndpointTest.java +++ b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrEndpointTest.java @@ -19,6 +19,22 @@ */ package org.restcomm.connect.mgcp; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mobicents.protocols.mgcp.jain.pkg.AUMgcpEvent; +import org.mobicents.protocols.mgcp.jain.pkg.AUPackage; +import org.restcomm.connect.commons.patterns.Observe; +import org.restcomm.connect.commons.patterns.Observing; +import org.restcomm.connect.commons.patterns.StopObserving; + import akka.actor.ActorRef; import akka.actor.ActorSystem; import akka.actor.Props; @@ -30,21 +46,6 @@ import jain.protocol.ip.mgcp.message.parms.EventName; import jain.protocol.ip.mgcp.message.parms.ReturnCode; import jain.protocol.ip.mgcp.pkg.MgcpEvent; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mobicents.protocols.mgcp.jain.pkg.AUMgcpEvent; -import org.mobicents.protocols.mgcp.jain.pkg.AUPackage; -import org.restcomm.connect.commons.patterns.Observe; -import org.restcomm.connect.commons.patterns.Observing; -import org.restcomm.connect.commons.patterns.StopObserving; - -import java.net.URI; -import java.util.ArrayList; -import java.util.List; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; /** * @author thomas.quintana@telestax.com (Thomas Quintana) @@ -132,7 +133,7 @@ public void testSuccessfulScenarioWithDigits() { endpoint.tell(playCollect, observer); final IvrEndpointResponse ivrResponse = expectMsgClass(IvrEndpointResponse.class); assertTrue(ivrResponse.succeeded()); - assertTrue("1".equals((ivrResponse.get()).getResult())); + assertTrue("1".equals(((CollectedResult)ivrResponse.get()).getResult())); // Stop observing events from the IVR end point. endpoint.tell(new StopObserving(observer), observer); } From 57fe839f8dd5fc8a18f0683e9569f11717510b2b Mon Sep 17 00:00:00 2001 From: Eugene Lapin Date: Wed, 20 Sep 2017 15:47:49 +0300 Subject: [PATCH 34/34] IVR test fix --- .../java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java index ef771fc653..3ca946ca10 100644 --- a/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java +++ b/restcomm/restcomm.mgcp/src/test/java/org/restcomm/connect/mgcp/IvrAsrEndpointTest.java @@ -117,7 +117,7 @@ public void testSuccessfulAsrScenario() { final IvrEndpointResponse ivrResponse3 = expectMsgClass(IvrEndpointResponse.class); collectedResult = (CollectedResult)ivrResponse3.get(); assertTrue(ivrResponse3.succeeded()); - assertTrue(collectedResult.getResult().isEmpty()); + assertTrue(ASR_RESULT_TEXT.equals(collectedResult.getResult())); assertTrue(collectedResult.isAsr()); // Stop observing events from the IVR end point. @@ -230,7 +230,7 @@ protected void event(final Object message, final ActorRef sender) { notify = createNotify(request, (int) transactionIdPool.get(), AUMgcpEvent.auoc.withParm("rc=101 asrr=" + ASR_RESULT_TEXT_HEX)); sender.tell(notify, self); - notify = createNotify(request, (int) transactionIdPool.get(), AUMgcpEvent.auoc.withParm("rc=100")); + notify = createNotify(request, (int) transactionIdPool.get(), AUMgcpEvent.auoc.withParm("rc=100 asrr=" + ASR_RESULT_TEXT_HEX)); sender.tell(notify, self); } }